From 2f19dcff030f9320fe9aa89a65c8b9ff422d0f0c Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 15 Aug 2021 08:33:08 +0700 Subject: [PATCH 01/71] + Removed unused import and useless typehint --- utils/api/google.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/api/google.py b/utils/api/google.py index 2126c969..685a9ed4 100644 --- a/utils/api/google.py +++ b/utils/api/google.py @@ -6,12 +6,11 @@ import re from contextlib import suppress from typing import Any, List, Optional -from urllib.parse import quote_plus import aiohttp import bs4 -from core.decorators import in_executor # type: ignore +from core.decorators import in_executor class SearchResult: From 5175c00ec4a772c55c1d35c848d893dd07a0357e Mon Sep 17 00:00:00 2001 From: ziro Date: Thu, 19 Aug 2021 17:39:47 +0700 Subject: [PATCH 02/71] + Added realurl command --- exts/utilities/utilities.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/exts/utilities/utilities.py b/exts/utilities/utilities.py index b3a20558..fca7d95f 100644 --- a/exts/utilities/utilities.py +++ b/exts/utilities/utilities.py @@ -7,6 +7,7 @@ import sys from decimal import InvalidOperation, Overflow +import aiohttp import discord import pyparsing as pyp from discord.ext import commands @@ -227,3 +228,32 @@ async def google(self, ctx, *, query: str): await msg.delete() await ctx.try_reply(embed=e) + + @commands.command( + brief="Get shorten url's real url. No more rick roll!", + usage="(shorten url)", + ) + @commands.cooldown(1, 10, commands.BucketType.user) + async def realurl(self, ctx, shortenUrl: str): + async with ctx.loading(): + try: + async with ctx.bot.session.get(shortenUrl) as res: + e = ZEmbed.default( + ctx, + title="Real URL", + description=("**Shorten URL**: {}\n" "**Real URL**: {}").format( + shortenUrl, res.real_url + ), + ) + await ctx.try_reply(embed=e) + except aiohttp.InvalidURL: + return await ctx.error( + "'{}' is not a valid url!".format(shortenUrl), title="Invalid URL" + ) + except aiohttp.ClientConnectorError: + return await ctx.error( + "Cannot connect to '{}'. Please try again later!".format( + shortenUrl + ), + title="Failed to connect", + ) From 28d1838aab0efc173c4b40f9fcd02e04491880e9 Mon Sep 17 00:00:00 2001 From: ziro Date: Thu, 19 Aug 2021 18:15:28 +0700 Subject: [PATCH 03/71] + Fix formatting --- exts/utilities/utilities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exts/utilities/utilities.py b/exts/utilities/utilities.py index fca7d95f..e290f2fd 100644 --- a/exts/utilities/utilities.py +++ b/exts/utilities/utilities.py @@ -241,7 +241,7 @@ async def realurl(self, ctx, shortenUrl: str): e = ZEmbed.default( ctx, title="Real URL", - description=("**Shorten URL**: {}\n" "**Real URL**: {}").format( + description="**Shorten URL**: {}\n**Real URL**: {}".format( shortenUrl, res.real_url ), ) From 6ec2a06582ed417749ebf1edccdb6efa9d247c85 Mon Sep 17 00:00:00 2001 From: ziro Date: Fri, 20 Aug 2021 09:40:33 +0700 Subject: [PATCH 04/71] + [ 2 files changed ] Added SQLAlchemy<1.4 (databases-sqlalchemy1.4 support currently broken) --- poetry.lock | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index fe767d95..7717d99e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -776,7 +776,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "1a35f5b6a77cfb1fb7fbd0cd9ae3c31b383920829798b53d42b8970a473eef96" +content-hash = "8a628968d3c32c523fe94f70e9a377f2daf54ed3ffec4ac945b98f069383e239" [metadata.files] aiohttp = [ diff --git a/pyproject.toml b/pyproject.toml index b26e6b49..fe691f51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ aiomysql = {version = "^0.0.21", optional = true} aiosqlite = {version = "^0.17.0", optional = true} aiopg = {version = "^1.3.1", optional = true} PyNaCl = {version = ">=1.3.0,<1.5", optional = true} +SQLAlchemy = "<1.4" [tool.poetry.dev-dependencies] black = "^21.7b0" From dea95ac752b33ace40675bc32dc771f6d406ac36 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 22 Aug 2021 17:45:17 +0700 Subject: [PATCH 05/71] + Added stringWrap --- utils/format.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/utils/format.py b/utils/format.py index 2ebc9139..a6605f72 100644 --- a/utils/format.py +++ b/utils/format.py @@ -169,3 +169,21 @@ def separateStringFlags(string: str) -> Tuple[str, str]: def formatPerms(perms: list) -> str: return ", ".join([str(perm).title().replace("_", " ") for perm in perms]) + + +def stringWrap(string: str, limit: int, countHidden: bool = False): + """ + stringWrap('Test "long" text', 10) -> 'Test "l...' + stringWrap('Test "long" text', 10) -> 'Test "l... [+9 hidden]' + """ + + length: int = len(string.strip()) + if length > limit: + string = string.strip()[:-limit] + if countHidden: + newLen = len(string) + count = f"... [+{length-newLen} hidden]" + string += count + else: + string += "..." + return string From 6c8c1b57b13329d8bb20409f10b78dc2ceb43abc Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 29 Aug 2021 08:11:55 +0700 Subject: [PATCH 06/71] + Update discord.py (RIP d.py) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3a4655f8..2416b03c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" aiohttp = "3.7.3" python = "^3.8" beautifulsoup4 = "^4.9.3" -"discord.py" = {git = "https://github.com/Rapptz/discord.py", rev = "08a4db396118aeda6205ff56c8c8fc565fc338fc"} +"discord.py" = {git = "https://github.com/Rapptz/discord.py", rev = "45d498c1b76deaf3b394d17ccf56112fa691d160"} discord-ext-menus = "^1.1" fuzzywuzzy = "0.18.0" humanize = "3.7.0" From f02fbd29ccc42d3fc9693701912a5e62f68c2856 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 29 Aug 2021 08:15:20 +0700 Subject: [PATCH 07/71] + More update --- poetry.lock | 102 ++++++++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7717d99e..456d7f73 100644 --- a/poetry.lock +++ b/poetry.lock @@ -189,7 +189,7 @@ pycparser = "*" [[package]] name = "cfgv" -version = "3.3.0" +version = "3.3.1" description = "Validate configuration and produce human readable error messages." category = "dev" optional = false @@ -263,7 +263,7 @@ python-versions = ">=3.5.3" [[package]] name = "discord.py" -version = "2.0.0a3467+g08a4db39" +version = "2.0.0a3575+g45d498c1" description = "A Python wrapper for the Discord API" category = "main" optional = false @@ -281,8 +281,8 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "git" url = "https://github.com/Rapptz/discord.py" -reference = "08a4db396118aeda6205ff56c8c8fc565fc338fc" -resolved_reference = "08a4db396118aeda6205ff56c8c8fc565fc338fc" +reference = "45d498c1b76deaf3b394d17ccf56112fa691d160" +resolved_reference = "45d498c1b76deaf3b394d17ccf56112fa691d160" [[package]] name = "distlib" @@ -465,7 +465,7 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock [[package]] name = "pre-commit" -version = "2.14.0" +version = "2.14.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false @@ -610,7 +610,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] name = "regex" -version = "2021.8.3" +version = "2021.8.28" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -737,7 +737,7 @@ test = ["aiohttp", "flake8 (>=3.8.4,<3.9.0)", "psutil", "pycodestyle (>=2.6.0,<2 [[package]] name = "virtualenv" -version = "20.7.1" +version = "20.7.2" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -776,7 +776,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "8a628968d3c32c523fe94f70e9a377f2daf54ed3ffec4ac945b98f069383e239" +content-hash = "bc4c7a4936a8860abec2d0f5e6a02ff411685a6d340bf7d19f705c4ca4a0c240" [metadata.files] aiohttp = [ @@ -932,8 +932,8 @@ cffi = [ {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, ] cfgv = [ - {file = "cfgv-3.3.0-py2.py3-none-any.whl", hash = "sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1"}, - {file = "cfgv-3.3.0.tar.gz", hash = "sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1"}, + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, @@ -1103,8 +1103,8 @@ platformdirs = [ {file = "platformdirs-2.2.0.tar.gz", hash = "sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e"}, ] pre-commit = [ - {file = "pre_commit-2.14.0-py2.py3-none-any.whl", hash = "sha256:ec3045ae62e1aa2eecfb8e86fa3025c2e3698f77394ef8d2011ce0aedd85b2d4"}, - {file = "pre_commit-2.14.0.tar.gz", hash = "sha256:2386eeb4cf6633712c7cc9ede83684d53c8cafca6b59f79c738098b51c6d206c"}, + {file = "pre_commit-2.14.1-py2.py3-none-any.whl", hash = "sha256:a22d12a02da4d8df314187dfe7a61bda6291d57992060522feed30c8cd658b68"}, + {file = "pre_commit-2.14.1.tar.gz", hash = "sha256:7977a3103927932d4823178cbe4719ab55bb336f42a9f3bb2776cff99007a117"}, ] "prettify.py" = [] psycopg2-binary = [ @@ -1225,39 +1225,47 @@ pyyaml = [ {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] regex = [ - {file = "regex-2021.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8764a78c5464ac6bde91a8c87dd718c27c1cabb7ed2b4beaf36d3e8e390567f9"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4551728b767f35f86b8e5ec19a363df87450c7376d7419c3cac5b9ceb4bce576"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:577737ec3d4c195c4aef01b757905779a9e9aee608fa1cf0aec16b5576c893d3"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c856ec9b42e5af4fe2d8e75970fcc3a2c15925cbcc6e7a9bcb44583b10b95e80"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3835de96524a7b6869a6c710b26c90e94558c31006e96ca3cf6af6751b27dca1"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cea56288eeda8b7511d507bbe7790d89ae7049daa5f51ae31a35ae3c05408531"}, - {file = "regex-2021.8.3-cp36-cp36m-win32.whl", hash = "sha256:a4eddbe2a715b2dd3849afbdeacf1cc283160b24e09baf64fa5675f51940419d"}, - {file = "regex-2021.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:57fece29f7cc55d882fe282d9de52f2f522bb85290555b49394102f3621751ee"}, - {file = "regex-2021.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a5c6dbe09aff091adfa8c7cfc1a0e83fdb8021ddb2c183512775a14f1435fe16"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff4a8ad9638b7ca52313d8732f37ecd5fd3c8e3aff10a8ccb93176fd5b3812f6"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b63e3571b24a7959017573b6455e05b675050bbbea69408f35f3cb984ec54363"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fbc20975eee093efa2071de80df7f972b7b35e560b213aafabcec7c0bd00bd8c"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14caacd1853e40103f59571f169704367e79fb78fac3d6d09ac84d9197cadd16"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb350eb1060591d8e89d6bac4713d41006cd4d479f5e11db334a48ff8999512f"}, - {file = "regex-2021.8.3-cp37-cp37m-win32.whl", hash = "sha256:18fdc51458abc0a974822333bd3a932d4e06ba2a3243e9a1da305668bd62ec6d"}, - {file = "regex-2021.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:026beb631097a4a3def7299aa5825e05e057de3c6d72b139c37813bfa351274b"}, - {file = "regex-2021.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:16d9eaa8c7e91537516c20da37db975f09ac2e7772a0694b245076c6d68f85da"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3905c86cc4ab6d71635d6419a6f8d972cab7c634539bba6053c47354fd04452c"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937b20955806381e08e54bd9d71f83276d1f883264808521b70b33d98e4dec5d"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:28e8af338240b6f39713a34e337c3813047896ace09d51593d6907c66c0708ba"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c09d88a07483231119f5017904db8f60ad67906efac3f1baa31b9b7f7cca281"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:85f568892422a0e96235eb8ea6c5a41c8ccbf55576a2260c0160800dbd7c4f20"}, - {file = "regex-2021.8.3-cp38-cp38-win32.whl", hash = "sha256:bf6d987edd4a44dd2fa2723fca2790f9442ae4de2c8438e53fcb1befdf5d823a"}, - {file = "regex-2021.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:8fe58d9f6e3d1abf690174fd75800fda9bdc23d2a287e77758dc0e8567e38ce6"}, - {file = "regex-2021.8.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7976d410e42be9ae7458c1816a416218364e06e162b82e42f7060737e711d9ce"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9569da9e78f0947b249370cb8fadf1015a193c359e7e442ac9ecc585d937f08d"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bbe342c5b2dec5c5223e7c363f291558bc27982ef39ffd6569e8c082bdc83"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4f421e3cdd3a273bace013751c345f4ebeef08f05e8c10757533ada360b51a39"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea212df6e5d3f60341aef46401d32fcfded85593af1d82b8b4a7a68cd67fdd6b"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3b73390511edd2db2d34ff09aa0b2c08be974c71b4c0505b4a048d5dc128c2b"}, - {file = "regex-2021.8.3-cp39-cp39-win32.whl", hash = "sha256:f35567470ee6dbfb946f069ed5f5615b40edcbb5f1e6e1d3d2b114468d505fc6"}, - {file = "regex-2021.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:bfa6a679410b394600eafd16336b2ce8de43e9b13f7fb9247d84ef5ad2b45e91"}, - {file = "regex-2021.8.3.tar.gz", hash = "sha256:8935937dad2c9b369c3d932b0edbc52a62647c2afb2fafc0c280f14a8bf56a6a"}, + {file = "regex-2021.8.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308"}, + {file = "regex-2021.8.28-cp310-cp310-win32.whl", hash = "sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed"}, + {file = "regex-2021.8.28-cp310-cp310-win_amd64.whl", hash = "sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8"}, + {file = "regex-2021.8.28-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f"}, + {file = "regex-2021.8.28-cp36-cp36m-win32.whl", hash = "sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354"}, + {file = "regex-2021.8.28-cp36-cp36m-win_amd64.whl", hash = "sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645"}, + {file = "regex-2021.8.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906"}, + {file = "regex-2021.8.28-cp37-cp37m-win32.whl", hash = "sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a"}, + {file = "regex-2021.8.28-cp37-cp37m-win_amd64.whl", hash = "sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc"}, + {file = "regex-2021.8.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e"}, + {file = "regex-2021.8.28-cp38-cp38-win32.whl", hash = "sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d"}, + {file = "regex-2021.8.28-cp38-cp38-win_amd64.whl", hash = "sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2"}, + {file = "regex-2021.8.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed"}, + {file = "regex-2021.8.28-cp39-cp39-win32.whl", hash = "sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374"}, + {file = "regex-2021.8.28-cp39-cp39-win_amd64.whl", hash = "sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73"}, + {file = "regex-2021.8.28.tar.gz", hash = "sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1"}, ] requests = [ {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, @@ -1338,8 +1346,8 @@ uvloop = [ {file = "uvloop-0.15.3.tar.gz", hash = "sha256:905f0adb0c09c9f44222ee02f6b96fd88b493478fffb7a345287f9444e926030"}, ] virtualenv = [ - {file = "virtualenv-20.7.1-py2.py3-none-any.whl", hash = "sha256:73863dc3be1efe6ee638e77495c0c195a6384ae7b15c561f3ceb2698ae7267c1"}, - {file = "virtualenv-20.7.1.tar.gz", hash = "sha256:57bcb59c5898818bd555b1e0cfcf668bd6204bc2b53ad0e70a52413bd790f9e4"}, + {file = "virtualenv-20.7.2-py2.py3-none-any.whl", hash = "sha256:e4670891b3a03eb071748c569a87cceaefbf643c5bac46d996c5a45c34aa0f06"}, + {file = "virtualenv-20.7.2.tar.gz", hash = "sha256:9ef4e8ee4710826e98ff3075c9a4739e2cb1040de6a2a8d35db0055840dc96a0"}, ] yarl = [ {file = "yarl-1.6.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434"}, From 26fe3f5bc981ae6ab7dcd0c90ea7768af772f460 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 29 Aug 2021 08:38:14 +0700 Subject: [PATCH 08/71] + [ 2 files changed ] + Fix breaking changes avatar won't return "default" avatar when user don't have a custom avatar d.py introduced display_avatar to get this behaviour back --- README.md | 2 +- exts/info/info.py | 43 ++++++++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index a9949e71..8ce56432 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,6 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) ## Plans - Event for ~~member boosting a guild~~ (Just need to implement setup for it) -- Properly support different SQL scheme (databases have `database_url.scheme` to check scheme type) - Tags (stripped version of custom command) - Unify categories/exts emoji - Channel manager commands @@ -99,6 +98,7 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) - i18n using gettext (Learning how gettext works) - Slash command (RIP dpy, have to design this myself for now) +- Properly support different SQL scheme (designing best way to do this) ### Scrapped Plan diff --git a/exts/info/info.py b/exts/info/info.py index 05a70950..082fa410 100644 --- a/exts/info/info.py +++ b/exts/info/info.py @@ -56,21 +56,22 @@ def __init__(self, bot): async def avatar(self, ctx, _user: MemberOrUser = None): user: Union[discord.Member, discord.User] = _user or await authorOrReferenced( ctx - ) - user.avatar.with_format("jpg").url + ) # type: ignore + + avatar = user.display_avatar # Links to avatar (with different formats) links = ( "[`JPEG`]({})" " | [`PNG`]({})" " | [`WEBP`]({})".format( - user.avatar.with_format("jpg").url, - user.avatar.with_format("png").url, - user.avatar.with_format("webp").url, + avatar.with_format("jpg").url, + avatar.with_format("png").url, + avatar.with_format("webp").url, ) ) - if user.avatar.is_animated(): - links += " | [`GIF`]({})".format(user.avatar.with_format("gif").url) + if avatar.is_animated(): + links += " | [`GIF`]({})".format(avatar.with_format("gif").url) # Embed stuff e = ZEmbed.default( @@ -78,7 +79,7 @@ async def avatar(self, ctx, _user: MemberOrUser = None): title="{}'s Avatar".format(user.name), description=links, ) - e.set_image(url=user.avatar.with_size(1024).url) + e.set_image(url=avatar.with_size(1024).url) await ctx.try_reply(embed=e) @commands.command( @@ -400,9 +401,10 @@ async def covid(self, ctx, *, country): brief="Get user's information", ) @commands.cooldown(1, 5, commands.BucketType.user) - async def userinfo(self, ctx, *, user: MemberOrUser = None): - if not user: - user = await authorOrReferenced(ctx) + async def userinfo(self, ctx, *, _user: MemberOrUser = None): + user: Union[discord.User, discord.Member] = _user or await authorOrReferenced( + ctx + ) # type: ignore # MemberOrUser or authorOrReferenced will return user/member def status(x): return { @@ -454,12 +456,15 @@ def activity(x): isUser = isinstance(user, discord.User) joinedAt = None if not isUser: - joinedAt = user.joined_at.replace(tzinfo=dt.timezone.utc) + # already checked by isUser + joinedAt = user.joined_at.replace(tzinfo=dt.timezone.utc) # type: ignore + + avatar = user.display_avatar e = ( ZEmbed() - .set_author(name=user, icon_url=user.avatar.url) - .set_thumbnail(url=user.avatar.url) + .set_author(name=user, icon_url=avatar.url) + .set_thumbnail(url=avatar.url) ) e.add_field( @@ -488,9 +493,9 @@ def activity(x): formatDiscordDT(joinedAt, "F"), formatDiscordDT(joinedAt, "R") ) + "**Role count**: ({}/{})\n".format( - len(user.roles), len(user.guild.roles) + len(user.roles), len(user.guild.roles) # type: ignore ) - + "**Top role**: {}".format(user.top_role.mention) + + "**Top role**: {}".format(user.top_role.mention) # type: ignore ) ), inline=False, @@ -502,9 +507,9 @@ def activity(x): "N/A" if isUser else ( - "**Status**: {}\n".format(status(user.status)) + "**Status**: {}\n".format(status(user.status)) # type: ignore + "**Activity**: {}".format( - activity(user.activity) if user.activity else "None" + activity(user.activity) if user.activity else "None" # type: ignore ) ) ), @@ -694,7 +699,7 @@ async def permissions( ), ) with suppress(AttributeError): - e.set_thumbnail(url=memberOrRole.avatar.url) # type: ignore + e.set_thumbnail(url=memberOrRole.display_avatar.url) # type: ignore await ctx.try_reply(embed=e) From 4966dee37f41806144d70442c92dc72a6c87b14d Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 29 Aug 2021 08:43:30 +0700 Subject: [PATCH 09/71] + Typehint mixin --- core/mixin.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/core/mixin.py b/core/mixin.py index 44fab31e..66baa2a5 100644 --- a/core/mixin.py +++ b/core/mixin.py @@ -1,9 +1,20 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + + +if TYPE_CHECKING: + from databases import Database + + from core.bot import ziBot + + class CogMixin: """Mixin for Cogs/Exts.""" - def __init__(self, bot): - self.bot = bot + def __init__(self, bot: ziBot) -> None: + self.bot: ziBot = bot @property - def db(self): + def db(self) -> Database: return self.bot.db From 062268944602c14daeaebf69b7b6ae4f8d955b41 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 29 Aug 2021 09:04:46 +0700 Subject: [PATCH 10/71] + [ 2 files changed ] - Events stuff * Changed get_channel to get_partial_messagable * Added caseNum to modlog (currently only shown if mods moderate manually) --- exts/events/events.py | 66 +++++++++++++++++++++++++++---------------- utils/other.py | 6 ++-- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/exts/events/events.py b/exts/events/events.py index 42079864..37c02710 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -37,30 +37,32 @@ async def doModlog( bot: ziBot, guild: discord.Guild, - member: discord.abc.User, - moderator: discord.abc.User, + member: discord.User, + moderator: discord.User, type: str, reason: str = None, + caseNum: Optional[int] = None, ) -> None: """Basically handle formatting modlog events""" - channel = await bot.getGuildConfig(guild.id, "modlogCh", "guildChannels") - channel = bot.get_channel(channel) + channel = bot.get_channel( + await bot.getGuildConfig(guild.id, "modlogCh", "guildChannels") or 0 + ) - if moderator.id == bot.user.id: + if moderator.id == bot.user.id: # type: ignore # This usually True when mods use moderation commands # Or when bots doing automod stuff if reason and channel: # Get the real moderator match = REASON_REGEX.match(reason) if match: - modId = match.group(1) + modId = int(match.group(1)) moderator = bot.get_user(modId) or await bot.fetch_user(modId) reason = match.group(2) else: # Since moderation is done manually, caselog will be done here - await doCaselog( + caseNum = await doCaselog( bot, guildId=guild.id, type=type, @@ -73,7 +75,6 @@ async def doModlog( # No channel found, don't do modlog return - # TODO: Include caselog number into modlog e = ZEmbed.minimal( title="Modlog - {}".format(type.title()), description=( @@ -82,8 +83,12 @@ async def doModlog( + f"**Moderator**: {moderator.mention}" ), ) + # TODO: Make caseNum appears when moderation cmd is used + if caseNum is not None: + e.description += f"\n**Case**: #{caseNum}" + e.set_footer(text=f"ID: {member.id}") - await channel.send(embed=e) + await channel.send(embed=e) # type: ignore class EventHandler(commands.Cog, CogMixin): @@ -326,7 +331,7 @@ async def onCommandError(self, ctx, error) -> Optional[discord.Message]: try: # Send embed that when user react with greenTick bot will send it to bot owner or issue channel dest = ( - self.bot.get_channel(self.bot.issueChannel) + self.bot.get_partial_messageable(self.bot.issueChannel) or self.bot.get_user(self.bot.owner_id) or (self.bot.get_user(self.bot.master[0])) ) @@ -390,23 +395,28 @@ async def onMessageEdit( if before.author.bot: return + if not (guild := before.guild): + return + if before.type != discord.MessageType.default: return if before.content == after.content: return - guild = before.guild - - logCh = guild.get_channel( - await self.bot.getGuildConfig(guild.id, "purgatoryCh", "guildChannels") + logChId = await self.bot.getGuildConfig( + guild.id, "purgatoryCh", "guildChannels" ) - if not logCh: + if not logChId: return + logCh = self.bot.get_partial_messageable(logChId) + e = ZEmbed(timestamp=utcnow(), title="Edited Message") - e.set_author(name=before.author, icon_url=before.author.avatar.url) + avatar = before.author.display_avatar + + e.set_author(name=before.author, icon_url=avatar.url) e.add_field( name="Before", @@ -457,20 +467,25 @@ async def onMessageDelete( if message.author.bot: return - if message.type != discord.MessageType.default: + if not (guild := message.guild): return - guild = message.guild + if message.type != discord.MessageType.default: + return - logCh = guild.get_channel( - await self.bot.getGuildConfig(guild.id, "purgatoryCh", "guildChannels") + logChId = await self.bot.getGuildConfig( + guild.id, "purgatoryCh", "guildChannels" ) - if not logCh: + if not logChId: return + logCh = self.bot.get_partial_messageable(logChId) + e = ZEmbed(timestamp=utcnow(), title="Deleted Message") - e.set_author(name=message.author, icon_url=message.author.avatar.url) + avatar = message.author.display_avatar + + e.set_author(name=message.author, icon_url=avatar.url) e.description = ( message.content[:1020] + " ..." @@ -488,7 +503,7 @@ async def onMemberUpdate( return # TODO: Add user log channel - channel = after.guild.get_channel(814009733006360597) + channel = self.bot.get_partial_messageable(814009733006360597) role = after.guild.premium_subscriber_role if role not in before.roles and role in after.roles: @@ -502,7 +517,10 @@ async def onMemberUpdate( @commands.Cog.listener("on_member_muted") async def onMemberMuted(self, member: discord.Member, mutedRole: discord.Object): - guild = member.guild + if not (guild := member.guild): + # impossible to happened, but sure + return + with suppress(discord.Forbidden): await asyncio.sleep(5) entry = ( diff --git a/utils/other.py b/utils/other.py index 42c6ab3c..6f439e75 100644 --- a/utils/other.py +++ b/utils/other.py @@ -9,7 +9,7 @@ import uuid from decimal import Decimal from html.parser import HTMLParser -from typing import Tuple +from typing import Optional, Tuple import discord from pyparsing import ( @@ -398,7 +398,7 @@ async def doCaselog( modId: int, targetId: int, reason: str, -): +) -> Optional[int]: caseNums = await bot.db.fetch_one( "SELECT IFNULL(MAX(caseId)+1, 1) FROM caseLog WHERE guildId=:guildId", values={"guildId": guildId}, @@ -430,7 +430,7 @@ async def doCaselog( "reason": reason, }, ) - return caseNum + return int(caseNum) TAG_IN_MD = { From a3c05616bd1747ee141d1d76d6ac2f99f904d450 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 29 Aug 2021 09:30:19 +0700 Subject: [PATCH 11/71] + [ 3 files changed ] - v3.3 --- CHANGELOG.md | 8 ++++++++ core/bot.py | 2 +- pyproject.toml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a66cc8ee..a6d0f5a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# v3.3 + +## 3.3.0 + +- [**New**] Added realurl (get real url of a shorten url) +- [**Improved**] Added case number to modlog message (for now only work with + manual moderation action) + # v3.2 ## 3.2.9 diff --git a/core/bot.py b/core/bot.py index bfff5748..97400d24 100644 --- a/core/bot.py +++ b/core/bot.py @@ -60,7 +60,7 @@ class ziBot(commands.Bot): # --- NOTE: Information about the bot author: str = getattr(config, "author", "ZiRO2264#9999") - version: str = "`3.2.9` - `overhaul`" + version: str = "`3.3.0` - `overhaul`" links: Dict[str, str] = getattr( config, "links", diff --git a/pyproject.toml b/pyproject.toml index 2416b03c..b5b7d217 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "Z3R0" -version = "3.2.9" +version = "3.3.0" description = "A multi-purpose open source discord bot" authors = ["null2264"] license = "MPL-2.0" From 040be264eed97074c1583615e29a918a6594796e Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 29 Aug 2021 10:45:53 +0700 Subject: [PATCH 12/71] + [ 4 files changed ] - Fix Admin commands' checks not working properly --- CHANGELOG.md | 3 +-- README.md | 1 + exts/admin/admin.py | 10 ++++------ exts/mod/mod.py | 4 +--- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6d0f5a0..2a8e7baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [**New**] Added realurl (get real url of a shorten url) - [**Improved**] Added case number to modlog message (for now only work with manual moderation action) +- [**Fixed**] Fix Admin commands' checks not working properly # v3.2 @@ -16,8 +17,6 @@ - [**Fixed**] Fixed Moderation commands' checks not working properly - - ## 3.2.7 - [**Fixed**] Fixed help command not working in DMs diff --git a/README.md b/README.md index 8ce56432..5820d6e8 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) ## Plans +- Use [enhanced-discord.py](https://github.com/iDevision/enhanced-discord.py) - Event for ~~member boosting a guild~~ (Just need to implement setup for it) - Tags (stripped version of custom command) - Unify categories/exts emoji diff --git a/exts/admin/admin.py b/exts/admin/admin.py index d6687b9b..088bd4a4 100644 --- a/exts/admin/admin.py +++ b/exts/admin/admin.py @@ -44,12 +44,7 @@ async def setGuildRole(bot, guildId: int, roleType: str, roleId: Optional[int]): return await bot.setGuildConfig(guildId, roleType, roleId, "guildRoles") async def cog_check(self, ctx): - if not ctx.guild: - # Configuration only for Guild - return False - - # Check if member can manage_channels or have mod role - return await checks.isMod(ctx) + return ctx.guild is not None async def handleGreetingConfig(self, ctx, arguments, type: str): """Handle welcome and farewell configuration.""" @@ -435,6 +430,8 @@ async def roleTypes(self, ctx): }, ), ) + @commands.bot_has_guild_permissions(manage_roles=True) + @checks.is_admin() async def autorole(self, ctx, name: Union[discord.Role, str]): await ctx.try_invoke( self.roleCreate if isinstance(name, str) else self.roleSet, @@ -451,6 +448,7 @@ async def autorole(self, ctx, name: Union[discord.Role, str]): }, ), ) + @checks.is_mod() async def announcement(self, ctx, channel: discord.TextChannel): await self.bot.setGuildConfig( ctx.guild.id, "announcementCh", channel.id, "guildChannels" diff --git a/exts/mod/mod.py b/exts/mod/mod.py index 3c7cd381..4632891e 100644 --- a/exts/mod/mod.py +++ b/exts/mod/mod.py @@ -30,9 +30,7 @@ class Moderation(commands.Cog, CogMixin): icon = "🛠️" async def cog_check(self, ctx): - if not ctx.guild: - return False - return True + return ctx.guild is not None async def doModeration( self, ctx, user, _time: Optional[TimeAndArgument], action: str, **kwargs From 42d1cbda158be5c1ffc61b247a1ea78e44778cf4 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 30 Aug 2021 08:48:00 +0700 Subject: [PATCH 13/71] + [ 3 files changed ] - Moved to edpy 2.0 branch --- README.md | 1 - poetry.lock | 57 ++++++++++++++++++++++++++++++++++++-------------- pyproject.toml | 2 +- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 5820d6e8..8ce56432 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,6 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) ## Plans -- Use [enhanced-discord.py](https://github.com/iDevision/enhanced-discord.py) - Event for ~~member boosting a guild~~ (Just need to implement setup for it) - Tags (stripped version of custom command) - Unify categories/exts emoji diff --git a/poetry.lock b/poetry.lock index 456d7f73..b449dd92 100644 --- a/poetry.lock +++ b/poetry.lock @@ -160,6 +160,30 @@ d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] python2 = ["typed-ast (>=1.4.2)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "black" +version = "21.8b0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0,<1" +platformdirs = ">=2" +regex = ">=2020.1.8" +tomli = ">=0.2.6,<2.0.0" +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +python2 = ["typed-ast (>=1.4.2)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "braceexpand" version = "0.1.7" @@ -263,7 +287,7 @@ python-versions = ">=3.5.3" [[package]] name = "discord.py" -version = "2.0.0a3575+g45d498c1" +version = "2.0.0a3582+g773ad6f5" description = "A Python wrapper for the Discord API" category = "main" optional = false @@ -280,9 +304,9 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "git" -url = "https://github.com/Rapptz/discord.py" -reference = "45d498c1b76deaf3b394d17ccf56112fa691d160" -resolved_reference = "45d498c1b76deaf3b394d17ccf56112fa691d160" +url = "https://github.com/iDevision/enhanced-discord.py" +reference = "2.0" +resolved_reference = "773ad6f5bfa1c877085edd090f6fa0def1cbc704" [[package]] name = "distlib" @@ -384,7 +408,7 @@ plugins = ["setuptools"] [[package]] name = "jishaku" -version = "2.2.0" +version = "2.3.0" description = "A discord.py extension including useful tools for bot development and debugging." category = "main" optional = false @@ -393,7 +417,6 @@ python-versions = ">=3.8.0" [package.dependencies] braceexpand = ">=0.1.7" click = ">=8.0.1" -"discord.py" = ">=1.7.2" import-expression = ">=1.0.0,<2.0.0" [package.extras] @@ -401,7 +424,7 @@ docs = ["sphinx (>=3.5.4)", "sphinxcontrib-asyncio"] procinfo = ["psutil"] publish = ["jinja2"] test = ["click", "coverage", "flake8", "isort", "pylint", "pytest", "pytest-cov", "pytest-mock"] -voice = ["discord.py[voice] (>=1.7.2)", "youtube-dl"] +voice = ["youtube-dl"] [[package]] name = "mccabe" @@ -703,7 +726,7 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "3.10.0.0" +version = "3.10.0.1" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -776,7 +799,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "bc4c7a4936a8860abec2d0f5e6a02ff411685a6d340bf7d19f705c4ca4a0c240" +content-hash = "e7f953c1b15c82571d52893b258bac93281712b0cddf63dacbd882448f5b1010" [metadata.files] aiohttp = [ @@ -875,6 +898,8 @@ beautifulsoup4 = [ black = [ {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"}, {file = "black-21.7b0.tar.gz", hash = "sha256:c8373c6491de9362e39271630b65b964607bc5c79c83783547d76c839b3aa219"}, + {file = "black-21.8b0-py3-none-any.whl", hash = "sha256:2a0f9a8c2b2a60dbcf1ccb058842fb22bdbbcb2f32c6cc02d9578f90b92ce8b7"}, + {file = "black-21.8b0.tar.gz", hash = "sha256:570608d28aa3af1792b98c4a337dbac6367877b47b12b88ab42095cfc1a627c2"}, ] braceexpand = [ {file = "braceexpand-0.1.7-py2.py3-none-any.whl", hash = "sha256:91332d53de7828103dcae5773fb43bc34950b0c8160e35e0f44c4427a3b85014"}, @@ -997,10 +1022,10 @@ isort = [ {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, ] jishaku = [ - {file = "jishaku-2.2.0-py3-none-any.whl", hash = "sha256:a012a751cee43e32a108e8a04266a0d0b7a898e18ef12aac33699bcc9b5f9264"}, - {file = "jishaku-2.2.0-py3.8.egg", hash = "sha256:e33e7b943f8db825d5e0d3adf685727a0bbcd1fa3210b79608df8da6a070e7d4"}, - {file = "jishaku-2.2.0-py3.9.egg", hash = "sha256:f31c69d0122d27fba27fdc00052c58ccf90a15acb4c3ecc32dea167f5cd0605c"}, - {file = "jishaku-2.2.0.tar.gz", hash = "sha256:89ff33d8eb620311df1ff3c92dc4872b6560b58a70c181b0354e51ddd5fc6645"}, + {file = "jishaku-2.3.0-py3-none-any.whl", hash = "sha256:61d38ca408bf59dd3d8fd0b5f2c4d520e6228aa6234e9c47c54a37fcdb0e7d3c"}, + {file = "jishaku-2.3.0-py3.8.egg", hash = "sha256:9dcd433d032963e44976ceafcf911013cca16025f4c3d175e6bcc8c904632af3"}, + {file = "jishaku-2.3.0-py3.9.egg", hash = "sha256:7a763b6d19b799b0770ad7bc8a72f8e2a44f0e5196378424674bef99da20e529"}, + {file = "jishaku-2.3.0.tar.gz", hash = "sha256:620105cc2b5c0dd6e232b35988e530460a35972ada7a84ab031e2ac1213f11eb"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, @@ -1325,9 +1350,9 @@ tomli = [ {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, - {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, - {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, + {file = "typing_extensions-3.10.0.1-py2-none-any.whl", hash = "sha256:8bbffbd37fbeb9747a0241fdfde5ae99d4531ad1d1a41ccaea62100e15a5814c"}, + {file = "typing_extensions-3.10.0.1-py3-none-any.whl", hash = "sha256:045dd532231acfa03628df5e0c66dba64e2cc8fc8b844538d4ad6d5dd6cb82dc"}, + {file = "typing_extensions-3.10.0.1.tar.gz", hash = "sha256:83af6730a045fda60f46510f7f1f094776d90321caa4d97d20ef38871bef4bd3"}, ] urllib3 = [ {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, diff --git a/pyproject.toml b/pyproject.toml index b5b7d217..da6c6987 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" aiohttp = "3.7.3" python = "^3.8" beautifulsoup4 = "^4.9.3" -"discord.py" = {git = "https://github.com/Rapptz/discord.py", rev = "45d498c1b76deaf3b394d17ccf56112fa691d160"} +"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", branch = "2.0", rev = "773ad6f5bfa1c877085edd090f6fa0def1cbc704"} discord-ext-menus = "^1.1" fuzzywuzzy = "0.18.0" humanize = "3.7.0" From 1c3ace64dc90bec2d9034a1719dc24f04e88d6e4 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 30 Aug 2021 09:05:30 +0700 Subject: [PATCH 14/71] + Modlog require "View Audit Log" perm --- exts/admin/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exts/admin/admin.py b/exts/admin/admin.py index 088bd4a4..d6145556 100644 --- a/exts/admin/admin.py +++ b/exts/admin/admin.py @@ -209,7 +209,7 @@ async def handleLogConfig(self, ctx, arguments, type: str): "disable": "Disable modlog", }, perms={ - "bot": "Manage Channels", + "bot": "Manage Channels and View Audit Log", "user": "Moderator Role or Manage Channels", }, ), From 624b42e7630a1c052aa14026d1fa25f2a51541a0 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 30 Aug 2021 09:09:11 +0700 Subject: [PATCH 15/71] + Add checks for bot perms --- exts/admin/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/exts/admin/admin.py b/exts/admin/admin.py index d6145556..c8ecb58d 100644 --- a/exts/admin/admin.py +++ b/exts/admin/admin.py @@ -214,6 +214,7 @@ async def handleLogConfig(self, ctx, arguments, type: str): }, ), ) + @commands.bot_has_guild_permissions(view_audit_log=True, manage_channels=True) @checks.mod_or_permissions(manage_channels=True) async def modlog(self, ctx, *, arguments): await self.handleLogConfig(ctx, arguments, "modlog") From 3e53a8012505699cae3073636e989b1b1095867b Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 30 Aug 2021 09:44:48 +0700 Subject: [PATCH 16/71] + Renamed bot.master -> bot.owner_ids --- core/bot.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/core/bot.py b/core/bot.py index 97400d24..1c143c80 100644 --- a/core/bot.py +++ b/core/bot.py @@ -6,6 +6,7 @@ import logging import os import re +import warnings from collections import Counter from contextlib import suppress from typing import Any, Dict, Iterable, List, Optional, Union @@ -98,7 +99,7 @@ def __init__(self) -> None: # Bot master(s) # self.master = (186713080841895936,) - self.master: tuple = ( + self.owner_ids: tuple = ( tuple() if not hasattr(config, "botMasters") else tuple([int(master) for master in config.botMasters]) @@ -197,16 +198,17 @@ async def asyncInit(self) -> None: async def startUp(self) -> None: """Will run when the bot ready""" await self.wait_until_ready() - if not self.master: + + if not self.owner_ids: # If self.master not set, warn the hoster self.logger.warning( "No master is set, you may not able to use certain commands! (Unless you own the Bot Application)" ) - # Add application owner into bot master list + # Add application owner into owner_ids list owner: discord.User = (await self.application_info()).owner - if owner and owner.id not in self.master: - self.master += (owner.id,) + if owner and owner.id not in self.owner_ids: + self.owner_ids += (owner.id,) # change bot's presence into guild live count self.changing_presence.start() @@ -216,6 +218,11 @@ async def startUp(self) -> None: if not hasattr(self, "uptime"): self.uptime: datetime.datetime = utcnow() + @property + def master(self): + warnings.warn("Bot.master is deprecated, use self.owner_ids instead") + return self.owner_ids + async def getGuildConfigs( self, guildId: int, filters: Iterable = "*", table: str = "guildConfigs" ) -> Dict[str, Any]: @@ -609,7 +616,7 @@ async def on_message(self, message) -> None: message.author.bot or message.author.id in self.blacklist.users or (message.guild and message.guild.id in self.blacklist.guilds) - ) and message.author.id not in self.master: + ) and message.author.id not in self.owner_ids: return # if bot is mentioned without any other message, send prefix list @@ -636,7 +643,7 @@ async def on_message_edit(self, before, after): message.author.bot or message.author.id in self.blacklist.users or (message.guild and message.guild.id in self.blacklist.guilds) - ) and message.author.id not in self.master: + ) and message.author.id not in self.owner_ids: return await self.process(message) From c2f759a5ce32facf188cbce34c7833595bc312aa Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 30 Aug 2021 11:11:48 +0700 Subject: [PATCH 17/71] + [ 2 files changed ] - Typehint and Ext's description --- exts/admin/admin.py | 7 +++++-- exts/anilist/anilist.py | 35 ++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/exts/admin/admin.py b/exts/admin/admin.py index c8ecb58d..2f066212 100644 --- a/exts/admin/admin.py +++ b/exts/admin/admin.py @@ -28,11 +28,14 @@ class Admin(commands.Cog, CogMixin): - """Admin-only commands to configure the bot.""" + """Collection of commands for admin/mods to configure the bot. + + Some commands may require `Administrator` permission. + """ icon = "\u2699" - def __init__(self, bot): + def __init__(self, bot) -> None: super().__init__(bot) @staticmethod diff --git a/exts/anilist/anilist.py b/exts/anilist/anilist.py index 7f1fb588..8b26c7f4 100644 --- a/exts/anilist/anilist.py +++ b/exts/anilist/anilist.py @@ -3,7 +3,10 @@ License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. """ +from __future__ import annotations + from random import randrange +from typing import Optional import discord from discord.ext import commands @@ -12,7 +15,7 @@ from core.enums import Emojis from core.menus import ZMenuPagesView from core.mixin import CogMixin -from utils.api import graphql +from utils.api.graphql import GraphQL from ._flags import AnimeSearchFlags from ._pages import AnimeSearchPageSource @@ -20,8 +23,8 @@ class ReadMore(discord.ui.Button): - async def callback(self, interaction: discord.Interaction): - view: ZMenuPagesView = self.view + async def callback(self, interaction: discord.Interaction) -> None: + view: Optional[ZMenuPagesView] = self.view page = await view._source.get_page(view.currentPage) # type: ignore synopsis = view._source.sendSynopsis(page) # type: ignore e = ZEmbed(description=synopsis) @@ -33,13 +36,15 @@ class AniList(commands.Cog, CogMixin): icon = "<:AniList:872771143797440533>" - def __init__(self, bot): + def __init__(self, bot) -> None: super().__init__(bot) - self.anilist = graphql.GraphQL( + self.anilist: GraphQL = GraphQL( "https://graphql.anilist.co", session=self.bot.session ) - async def anilistSearch(self, ctx, name: str, parsed, type: str = "ANIME"): + async def anilistSearch( + self, ctx, name: str, parsed, type: str = "ANIME" + ) -> Optional[discord.Message]: """Function for 'manga search' and 'anime search' command""" type = type.upper().replace(" ", "_") @@ -70,7 +75,7 @@ async def anilistSearch(self, ctx, name: str, parsed, type: str = "ANIME"): menu.add_item(ReadMore(emoji=Emojis.info)) await menu.start() - async def anilistRandom(self, ctx, type: str = "ANIME"): + async def anilistRandom(self, ctx, type: str = "ANIME") -> None: query = await self.anilist.queryPost( """ query ($type: MediaType) { @@ -120,7 +125,7 @@ async def anilistRandom(self, ctx, type: str = "ANIME"): aliases=("ani",), brief="Get anime's information", ) - async def anime(self, ctx): + async def anime(self, ctx) -> None: pass @anime.command( @@ -137,18 +142,18 @@ async def anime(self, ctx): ), ) @commands.cooldown(1, 5, commands.BucketType.user) - async def animeSearch(self, ctx, *, arguments: AnimeSearchFlags): + async def animeSearch(self, ctx, *, arguments: AnimeSearchFlags) -> None: name, parsed = arguments - await self.anilistSearch(ctx, name, parsed, "ANIME") + await self.anilistSearch(ctx, name, parsed, "ANIME") # type: ignore @anime.command(name="random", brief="Get random anime") @commands.cooldown(1, 5, commands.BucketType.user) - async def animeRandom(self, ctx): + async def animeRandom(self, ctx) -> None: await self.anilistRandom(ctx) @commands.group(brief="Get manga's information") - async def manga(self, ctx): + async def manga(self, ctx) -> None: pass @manga.command( @@ -163,12 +168,12 @@ async def manga(self, ctx): ), ) @commands.cooldown(1, 5, commands.BucketType.user) - async def mangaSearch(self, ctx, *, arguments: AnimeSearchFlags): + async def mangaSearch(self, ctx, *, arguments: AnimeSearchFlags) -> None: name, parsed = arguments - await self.anilistSearch(ctx, name, parsed, "MANGA") + await self.anilistSearch(ctx, name, parsed, "MANGA") # type: ignore @manga.command(name="random", brief="Get random manga") @commands.cooldown(1, 5, commands.BucketType.user) - async def mangaRandom(self, ctx): + async def mangaRandom(self, ctx) -> None: await self.anilistRandom(ctx, type="MANGA") From 5c8fdad8491d5cea68d4a9a288444332d60705a9 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 30 Aug 2021 11:22:49 +0700 Subject: [PATCH 18/71] + Added default value for cc and icon to Mixin --- core/mixin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/mixin.py b/core/mixin.py index 66baa2a5..eae9a3a0 100644 --- a/core/mixin.py +++ b/core/mixin.py @@ -12,6 +12,9 @@ class CogMixin: """Mixin for Cogs/Exts.""" + icon = "❓" + cc = False + def __init__(self, bot: ziBot) -> None: self.bot: ziBot = bot From 4086fc9e544254d37dbeb45d4f160c13289e5768 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 09:06:21 +0700 Subject: [PATCH 19/71] + [ 2 files changed ] - Added custom intents --- core/bot.py | 16 ++++++++++++- exts/events/events.py | 52 ++++++++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/core/bot.py b/core/bot.py index 1c143c80..463190f5 100644 --- a/core/bot.py +++ b/core/bot.py @@ -75,6 +75,19 @@ class ziBot(commands.Bot): # --- def __init__(self) -> None: + # custom intents, required since dpy v1.5 + intents = discord.Intents( + # bans are handled with on_member_remove, + # so only members intent is needed + bans=False, + members=True, + guilds=True, + messages=True, + emojis=True, + presences=True, + reactions=True, + ) + super().__init__( command_prefix=_callablePrefix, description=( @@ -82,9 +95,10 @@ def __init__(self) -> None: "created by ZiRO2264, formerly called `ziBot`." ), case_insensitive=True, - intents=discord.Intents.all(), + intents=intents, heartbeat_timeout=150.0, ) + # make cogs case insensitive self._BotBase__cogs: commands.core._CaseInsensitiveDict = ( commands.core._CaseInsensitiveDict() diff --git a/exts/events/events.py b/exts/events/events.py index 37c02710..2ea5bf68 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -166,45 +166,55 @@ async def onMemberJoin(self, member: discord.Member) -> None: return @commands.Cog.listener("on_member_remove") - async def onMemberRemove(self, user: discord.User) -> None: + async def onMemberRemove(self, member: discord.Member) -> None: """Farewell message""" + guild: discord.Guild = member.guild + with suppress(discord.Forbidden): - await asyncio.sleep(5) - # TODO: Add muted_member table to database to prevent mute evasion - entry = (await user.guild.audit_logs(limit=1).flatten())[0] + # discord needs a few second to update Audit Logs + await asyncio.sleep(2) - if entry.target == user: + entry = (await guild.audit_logs(limit=1).flatten())[0] + + if entry.target == member: # TODO: Filters bot's action if entry.action == discord.AuditLogAction.kick: - self.bot.dispatch("member_kick", user, entry) + self.bot.dispatch("member_kick", member, entry) return if entry.action == discord.AuditLogAction.ban: + # Intents.bans are disabled to make this works + self.bot.dispatch("member_ban", member, entry) return - return await self.handleGreeting(user, "farewell") + # fallback to farewell message + return await self.handleGreeting(member, "farewell") @commands.Cog.listener("on_member_kick") async def onMemberKick( - self, member: discord.User, entry: discord.AuditLogEntry + self, member: discord.Member, entry: discord.AuditLogEntry ) -> None: await doModlog( - self.bot, member.guild, entry.target, entry.user, "kick", entry.reason + self.bot, + member.guild, + entry.target, # type: ignore + entry.user, + "kick", + entry.reason, ) @commands.Cog.listener("on_member_ban") - async def onMemberBan(self, guild: discord.Guild, user: discord.User) -> None: - with suppress(discord.Forbidden): - await asyncio.sleep(5) - entry = ( - await guild.audit_logs( - limit=1, action=discord.AuditLogAction.ban - ).flatten() - )[0] - if entry.target == user: - await doModlog( - self.bot, guild, entry.target, entry.user, "ban", entry.reason - ) + async def onMemberBan( + self, member: discord.Member, entry: discord.AuditLogEntry + ) -> None: + await doModlog( + self.bot, + member.guild, + entry.target, # type: ignore + entry.user, + "ban", + entry.reason, + ) @commands.Cog.listener("on_command_error") async def onCommandError(self, ctx, error) -> Optional[discord.Message]: From a668537a4bd5416d4edadd8f9bd2c1e73e84fed5 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 09:19:22 +0700 Subject: [PATCH 20/71] + Changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a8e7baf..8f6b0021 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ - [**Improved**] Added case number to modlog message (for now only work with manual moderation action) - [**Fixed**] Fix Admin commands' checks not working properly +- [**Improved**] Manually input Intents, this should slightly improve the + performance +- [**Improved**] Merged `on_member_ban` with `on_member_remove`, so it doesn't + request audit logs twice +- [**Improved**] Decrease modlog delay to 2 seconds delay # v3.2 @@ -25,7 +30,7 @@ ## 3.2.6 -- [**Fixed**] Fixed modlog. Added 5 second delay, letting Audit Logs to update +- [**Fixed**] Fixed modlog. Added 5 seconds delay, letting Audit Logs to update before sending modlog ## 3.2.5 From aebadc763d074f701fa7ddb3f32f317d8fb4c93b Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 09:39:25 +0700 Subject: [PATCH 21/71] + [ 2 files changed ] - Fix `>dev reload`, and replace `master` -> `owner_ids` --- exts/dev/dev.py | 3 ++- poetry.lock | 55 ++++++++++--------------------------------------- 2 files changed, 13 insertions(+), 45 deletions(-) diff --git a/exts/dev/dev.py b/exts/dev/dev.py index 812dc92e..c5bad693 100644 --- a/exts/dev/dev.py +++ b/exts/dev/dev.py @@ -29,7 +29,7 @@ class Developer(*STANDARD_FEATURES, *OPTIONAL_FEATURES): async def cog_check(self, ctx): """Only bot master able to use debug cogs.""" - return self.bot.master and ctx.author.id in self.bot.master + return self.bot.owner_ids and ctx.author.id in self.bot.owner_ids # def notMe(): # async def pred(ctx): @@ -122,6 +122,7 @@ async def jsk_load(self, ctx, *extensions): ["{} | `{}`".format(v, k) for k, v in status.items()] ) else: + extension = exts[0] e.title = "{} | {} {}".format( status[extension], extension, diff --git a/poetry.lock b/poetry.lock index b449dd92..6bb14a15 100644 --- a/poetry.lock +++ b/poetry.lock @@ -57,14 +57,6 @@ python-versions = ">=3.6" [package.dependencies] typing_extensions = ">=3.7.2" -[[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "astunparse" version = "1.6.3" @@ -138,28 +130,6 @@ soupsieve = {version = ">1.2", markers = "python_version >= \"3.0\""} html5lib = ["html5lib"] lxml = ["lxml"] -[[package]] -name = "black" -version = "21.7b0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -appdirs = "*" -click = ">=7.1.2" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.8.1,<1" -regex = ">=2020.1.8" -tomli = ">=0.2.6,<2.0.0" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] -python2 = ["typed-ast (>=1.4.2)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "black" version = "21.8b0" @@ -175,7 +145,10 @@ pathspec = ">=0.9.0,<1" platformdirs = ">=2" regex = ">=2020.1.8" tomli = ">=0.2.6,<2.0.0" -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +typing-extensions = [ + {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, + {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, +] [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -476,7 +449,7 @@ python-versions = ">=3.6" [[package]] name = "platformdirs" -version = "2.2.0" +version = "2.3.0" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false @@ -726,7 +699,7 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "3.10.0.1" +version = "3.10.0.2" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -853,10 +826,6 @@ aiosqlite = [ {file = "aiosqlite-0.17.0-py3-none-any.whl", hash = "sha256:6c49dc6d3405929b1d08eeccc72306d3677503cc5e5e43771efc1e00232e8231"}, {file = "aiosqlite-0.17.0.tar.gz", hash = "sha256:f0e6acc24bc4864149267ac82fb46dfb3be4455f99fe21df82609cc6e6baee51"}, ] -appdirs = [ - {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, - {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, -] astunparse = [ {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"}, {file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"}, @@ -896,8 +865,6 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"}, ] black = [ - {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"}, - {file = "black-21.7b0.tar.gz", hash = "sha256:c8373c6491de9362e39271630b65b964607bc5c79c83783547d76c839b3aa219"}, {file = "black-21.8b0-py3-none-any.whl", hash = "sha256:2a0f9a8c2b2a60dbcf1ccb058842fb22bdbbcb2f32c6cc02d9578f90b92ce8b7"}, {file = "black-21.8b0.tar.gz", hash = "sha256:570608d28aa3af1792b98c4a337dbac6367877b47b12b88ab42095cfc1a627c2"}, ] @@ -1124,8 +1091,8 @@ pillow = [ {file = "Pillow-8.3.1.tar.gz", hash = "sha256:2cac53839bfc5cece8fdbe7f084d5e3ee61e1303cccc86511d351adcb9e2c792"}, ] platformdirs = [ - {file = "platformdirs-2.2.0-py3-none-any.whl", hash = "sha256:4666d822218db6a262bdfdc9c39d21f23b4cfdb08af331a81e92751daf6c866c"}, - {file = "platformdirs-2.2.0.tar.gz", hash = "sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e"}, + {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, + {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, ] pre-commit = [ {file = "pre_commit-2.14.1-py2.py3-none-any.whl", hash = "sha256:a22d12a02da4d8df314187dfe7a61bda6291d57992060522feed30c8cd658b68"}, @@ -1350,9 +1317,9 @@ tomli = [ {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.1-py2-none-any.whl", hash = "sha256:8bbffbd37fbeb9747a0241fdfde5ae99d4531ad1d1a41ccaea62100e15a5814c"}, - {file = "typing_extensions-3.10.0.1-py3-none-any.whl", hash = "sha256:045dd532231acfa03628df5e0c66dba64e2cc8fc8b844538d4ad6d5dd6cb82dc"}, - {file = "typing_extensions-3.10.0.1.tar.gz", hash = "sha256:83af6730a045fda60f46510f7f1f094776d90321caa4d97d20ef38871bef4bd3"}, + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] urllib3 = [ {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, From 282fbc758d747f31d25fe8174133dabe137867b1 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 09:44:21 +0700 Subject: [PATCH 22/71] + Typehint and fix breaking change --- exts/meta/_help.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index 03ee8604..67b84568 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -1,4 +1,7 @@ +from __future__ import annotations + from contextlib import suppress +from typing import TYPE_CHECKING import discord from discord.ext import commands @@ -15,7 +18,14 @@ from ._pages import HelpCogPage, HelpCommandPage +if TYPE_CHECKING: + from core.context import Context + + class CustomHelp(commands.HelpCommand): + if TYPE_CHECKING: + context: Context # stop pyright from yelling at me + async def send_bot_help(self, mapping): ctx = self.context @@ -30,7 +40,7 @@ async def send_bot_help(self, mapping): ) + " | ".join("[{}]({})".format(k, v) for k, v in ctx.bot.links.items()), ) - e.set_author(name=ctx.author, icon_url=ctx.author.avatar.url) + e.set_author(name=ctx.author, icon_url=ctx.author.display_avatar.url) e.set_footer( text="Use `{}help [category / command]` for more information".format( ctx.prefix From 9f41f04180d6784dbc5d73baa51c9d6f250dd901 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 09:46:12 +0700 Subject: [PATCH 23/71] + Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f6b0021..b061c0c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [**New**] Added realurl (get real url of a shorten url) - [**Improved**] Added case number to modlog message (for now only work with manual moderation action) +- [**Changed**] Rename `Bot.master` -> `Bot.owner_ids` - [**Fixed**] Fix Admin commands' checks not working properly - [**Improved**] Manually input Intents, this should slightly improve the performance From 5884c7ac23c7d66f701b068893696870cc5d709a Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 10:02:33 +0700 Subject: [PATCH 24/71] + [ 3 files changed ] - Merged `>cmds`/`>cmd list` with `>help filter: custom` --- CHANGELOG.md | 1 + exts/meta/_help.py | 65 +++++++++++++++++++++++++++++++--------------- exts/meta/meta.py | 16 +++--------- 3 files changed, 49 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b061c0c4..2ab3ce33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - [**Improved**] Merged `on_member_ban` with `on_member_remove`, so it doesn't request audit logs twice - [**Improved**] Decrease modlog delay to 2 seconds delay +- [**Improved**] Merged `>help filter: custom` with `>command list` # v3.2 diff --git a/exts/meta/_help.py b/exts/meta/_help.py index 67b84568..db1302df 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -146,17 +146,17 @@ async def send_command_help(self, commands_): await view.start() async def prepare_help_command(self, ctx, arguments) -> tuple: + # default filters, based on original help cmd + defFilters = ("built-in", "custom") + if arguments is None: - return None, None + return None, defFilters # separate string from flags # String filters: String -> ("String", "filters: String") command, parsed = await HelpFlags.convert(ctx, arguments) await super().prepare_help_command(ctx, command) - # default filters, based on original help cmd - defFilters = ("built-in", "custom") - filters = [] for f in parsed.filters: filters.extend(f.strip().split()) @@ -186,14 +186,34 @@ async def prepare_help_command(self, ctx, arguments) -> tuple: return command, unique + async def send_custom_help(self): + ctx = self.context + + if not (guild := ctx.guild): + return + + cmds = await getCustomCommands(ctx.db, guild.id) + cmds = sorted(cmds, key=lambda cmd: cmd.uses, reverse=True) + e = ZEmbed.default(ctx, title="Custom Commands", description="") + if cmds: + for k, v in enumerate(cmds): + e.description += "**`{}`** {} [`{}` uses]\n".format( + k + 1, v.name, v.uses + ) + else: + e.description = "This server doesn't have custom command" + await ctx.try_reply(embed=e) + async def command_callback(self, ctx, *, arguments=None): command, filters = await self.prepare_help_command(ctx, arguments) bot = ctx.bot - if command is None: - mapping = self.get_bot_mapping() - return await self.send_bot_help(mapping) + if not command: + if "built-in" in filters: + mapping = self.get_bot_mapping() + return await self.send_bot_help(mapping) + return await self.send_custom_help() cog = bot.get_cog(command) if cog: @@ -203,20 +223,23 @@ async def command_callback(self, ctx, *, arguments=None): # contains custom commands and built-in commands foundList = [] - if ctx.guild: - with suppress(CCommandNotFound): - cc = await getCustomCommand(ctx, command) - foundList.append(cc) - - keys = command.split(" ") - cmd = bot.all_commands.get(keys[0]) - if cmd: - for key in keys[1:]: - with suppress(AttributeError): - found = cmd.all_commands.get(key) - if found: - cmd = found - foundList.append(cmd) + + if "custom" in filters: + if ctx.guild: + with suppress(CCommandNotFound): + cc = await getCustomCommand(ctx, command) + foundList.append(cc) + + if "built-in" in filters: + keys = command.split(" ") + cmd = bot.all_commands.get(keys[0]) + if cmd: + for key in keys[1:]: + with suppress(AttributeError): + found = cmd.all_commands.get(key) + if found: + cmd = found + foundList.append(cmd) if not foundList: string = await maybeCoro( diff --git a/exts/meta/meta.py b/exts/meta/meta.py index 4e3ef4b8..90a14063 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -1038,18 +1038,10 @@ async def info(self, ctx, *, name: str = None): @command.command(name="list", aliases=("ls",), brief="Show all custom commands") async def cmdList(self, ctx): - # TODO: Merge this command with help command - cmds = await getCustomCommands(ctx.db, ctx.guild.id) - cmds = sorted(cmds, key=lambda cmd: cmd.uses, reverse=True) - e = ZEmbed.default(ctx, title="Custom Commands", description="") - if cmds: - for k, v in enumerate(cmds): - e.description += "**`{}`** {} [`{}` uses]\n".format( - k + 1, v.name, v.uses - ) - else: - e.description = "This server doesn't have custom command" - await ctx.try_reply(embed=e) + cmd: CustomHelp = ctx.bot.help_command + cmd = cmd.copy() + cmd.context = ctx + await cmd.command_callback(ctx, arguments="filter: custom") @command.command(name="mode", brief="Show current custom command mode") @commands.cooldown(1, 5, commands.BucketType.user) From 3ad1ce9da9f9d5d9738b56f82bb4da960834839c Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 12:08:24 +0700 Subject: [PATCH 25/71] + Fixed issue with `emoji info` --- exts/info/info.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/exts/info/info.py b/exts/info/info.py index 082fa410..f1f07f00 100644 --- a/exts/info/info.py +++ b/exts/info/info.py @@ -207,15 +207,16 @@ async def emojiInfo( ) e.set_image(url=emoji.url) # type: ignore except AttributeError: - # TODO: Doesn't work with :rock:, find a fix try: + strEm: str = str(emoji) + digit = f"{ord(strEm):x}" e = ZEmbed.default( ctx, title=" - ".join( ( - emoji, - hex(ord(emoji)).replace("0x", r"\u"), - unicodedata.name(emoji), + strEm, + f"\\u{digit}", + unicodedata.name(strEm, "Name not found"), ) ), description="`Type: Unicode`", From c86f8d2ca23994d43e54874bd590c082b70e7db7 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 18:54:48 +0700 Subject: [PATCH 26/71] + discord.Emoji is technically useless --- exts/info/info.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/exts/info/info.py b/exts/info/info.py index f1f07f00..4d9ae311 100644 --- a/exts/info/info.py +++ b/exts/info/info.py @@ -196,9 +196,7 @@ async def emoji(self, ctx, emoji: Union[discord.Emoji, discord.PartialEmoji, str ), ) @commands.cooldown(1, 5, commands.BucketType.user) - async def emojiInfo( - self, ctx, emoji: Union[discord.Emoji, discord.PartialEmoji, str] - ): + async def emojiInfo(self, ctx, emoji: Union[discord.PartialEmoji, str]): try: e = ZEmbed.default( ctx, @@ -287,7 +285,7 @@ async def emojiAdd( except AttributeError: # Probably a url? try: - async with self.bot.session.get(emoji) as req: + async with self.bot.session.get(emoji) as req: # type: ignore emojiByte = await req.read() except InvalidURL: return await ctx.error( From 53bf1c4cafb2e1ba3a30c82064ef3cbbae487340 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 19:01:11 +0700 Subject: [PATCH 27/71] + [ 2 files changed ] - Moved `authorOrReferenced` and more typehint --- exts/info/info.py | 32 +++++++++----------------------- utils/other.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/exts/info/info.py b/exts/info/info.py index 4d9ae311..911982f4 100644 --- a/exts/info/info.py +++ b/exts/info/info.py @@ -21,20 +21,7 @@ from utils.api.openweather import CityNotFound, OpenWeatherAPI from utils.format import formatDiscordDT, renderBar from utils.infoQuote import * # noqa: F403 -from utils.other import utcnow - - -# TODO: Move this somewhere in `exts/utils/` folder -async def authorOrReferenced(ctx): - if ref := ctx.replied_reference: - # Get referenced message author - # if user reply to a message while doing this command - return ( - ref.cached_message.author - if ref.cached_message - else (await ctx.fetch_message(ref.message_id)).author - ) - return ctx.author +from utils.other import authorOrReferenced, utcnow class Info(commands.Cog, CogMixin): @@ -547,11 +534,10 @@ async def guildinfo(self, ctx): status[str(m.status)][0] += 1 - e = ( - ZEmbed() - .set_author(name=guild, icon_url=guild.icon.url) - .set_thumbnail(url=guild.icon.url) - ) + e = ZEmbed() + + if icon := guild.icon: + e.set_author(name=guild, icon_url=icon.url).set_thumbnail(url=icon.url) e.add_field( name="General", @@ -562,7 +548,7 @@ async def guildinfo(self, ctx): formatDiscordDT(createdAt, "F"), formatDiscordDT(createdAt, "R") ) + "**Owner**: {0} / {0.mention}\n".format(guild.owner) - + "**Owner ID**: `{}`".format(guild.owner.id) + + "**Owner ID**: `{}`".format(guild.owner.id) # type: ignore ), inline=False, ) @@ -619,8 +605,8 @@ async def spotifyinfo(self, ctx, user: discord.Member = None): user = user or ctx.author spotify: discord.Spotify = discord.utils.find( - lambda s: isinstance(s, discord.Spotify), user.activities - ) + lambda s: isinstance(s, discord.Spotify), user.activities # type: ignore + ) # discord.Spotify is ActivityTypes if not spotify: return await ctx.error( "{} is not listening to Spotify!".format(user.mention) @@ -645,7 +631,7 @@ async def spotifyinfo(self, ctx, user: discord.Member = None): # Bar stuff barLength = 5 if user.is_on_mobile() else 17 bar = renderBar( - (cur.seconds / dur.seconds) * 100, + int(cur.seconds / dur.seconds) * 100, fill="─", empty="─", point="⬤", diff --git a/utils/other.py b/utils/other.py index 6f439e75..4060778e 100644 --- a/utils/other.py +++ b/utils/other.py @@ -472,6 +472,18 @@ def handle_data(self, data): self.result += data +async def authorOrReferenced(ctx): + if ref := ctx.replied_reference: + # Get referenced message author + # if user reply to a message while doing this command + return ( + ref.cached_message.author + if ref.cached_message + else (await ctx.fetch_message(ref.message_id)).author + ) + return ctx.author + + if __name__ == "__main__": # For testing print(encodeMorse("test 123")) From 442497a4bc70bfd1f00ae73d5e1e518cac28ccbf Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 19:04:27 +0700 Subject: [PATCH 28/71] + Typehint --- exts/info/info.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/exts/info/info.py b/exts/info/info.py index 911982f4..daad0169 100644 --- a/exts/info/info.py +++ b/exts/info/info.py @@ -14,6 +14,7 @@ from discord.ext import commands from core import checks +from core.context import Context from core.converter import MemberOrUser from core.embed import ZEmbed from core.mixin import CogMixin @@ -40,7 +41,7 @@ def __init__(self, bot): aliases=("av", "userpfp", "pfp"), brief="Get member's avatar image" ) @commands.cooldown(1, 5, commands.BucketType.user) - async def avatar(self, ctx, _user: MemberOrUser = None): + async def avatar(self, ctx: Context, _user: MemberOrUser = None): user: Union[discord.Member, discord.User] = _user or await authorOrReferenced( ctx ) # type: ignore @@ -75,7 +76,7 @@ async def avatar(self, ctx, _user: MemberOrUser = None): extras=dict(example=("weather Palembang", "w London")), ) @commands.cooldown(1, 5, commands.BucketType.user) - async def weather(self, ctx, *, city): + async def weather(self, ctx: Context, *, city): if not self.openweather.apiKey: return await ctx.error( "OpenWeather's API Key is not set! Please contact the bot owner to solve this issue." @@ -114,7 +115,7 @@ async def weather(self, ctx, *, city): extras=dict(example=("colour ffffff", "clr 0xffffff", "color #ffffff")), ) @commands.cooldown(1, 5, commands.BucketType.user) - async def colour(self, ctx, value: str): + async def colour(self, ctx: Context, value: str): # Pre processing value = value.lstrip("#")[:6] value = value.ljust(6, "0") @@ -165,7 +166,9 @@ async def level(self, ctx): invoke_without_command=True, ) @commands.cooldown(1, 5, commands.BucketType.user) - async def emoji(self, ctx, emoji: Union[discord.Emoji, discord.PartialEmoji, str]): + async def emoji( + self, ctx: Context, emoji: Union[discord.Emoji, discord.PartialEmoji, str] + ): # TODO: Add emoji list await ctx.try_invoke(self.emojiInfo, emoji) @@ -183,7 +186,7 @@ async def emoji(self, ctx, emoji: Union[discord.Emoji, discord.PartialEmoji, str ), ) @commands.cooldown(1, 5, commands.BucketType.user) - async def emojiInfo(self, ctx, emoji: Union[discord.PartialEmoji, str]): + async def emojiInfo(self, ctx: Context, emoji: Union[discord.PartialEmoji, str]): try: e = ZEmbed.default( ctx, @@ -224,7 +227,9 @@ async def emojiInfo(self, ctx, emoji: Union[discord.PartialEmoji, str]): ) @commands.guild_only() @checks.mod_or_permissions(manage_emojis=True) - async def emojiSteal(self, ctx, emoji: Union[discord.Emoji, discord.PartialEmoji]): + async def emojiSteal( + self, ctx: Context, emoji: Union[discord.Emoji, discord.PartialEmoji] + ): emojiByte = await emoji.read() try: @@ -318,7 +323,7 @@ async def emojiAdd( ), ) @commands.cooldown(1, 5, commands.BucketType.user) - async def jisho(self, ctx, *, words): + async def jisho(self, ctx: Context, *, words): async with ctx.bot.session.get( "https://jisho.org/api/v1/search/words", params={"keyword": words} ) as req: @@ -357,7 +362,7 @@ async def jisho(self, ctx, *, words): brief="Show covid information on certain country", ) @commands.cooldown(1, 5, commands.BucketType.user) - async def covid(self, ctx, *, country): + async def covid(self, ctx: Context, *, country): # TODO: Remove later if country.lower() in ("united state of america", "america"): country = "US" @@ -387,7 +392,7 @@ async def covid(self, ctx, *, country): brief="Get user's information", ) @commands.cooldown(1, 5, commands.BucketType.user) - async def userinfo(self, ctx, *, _user: MemberOrUser = None): + async def userinfo(self, ctx: Context, *, _user: MemberOrUser = None): user: Union[discord.User, discord.Member] = _user or await authorOrReferenced( ctx ) # type: ignore # MemberOrUser or authorOrReferenced will return user/member @@ -601,7 +606,7 @@ async def guildinfo(self, ctx): ) @commands.cooldown(1, 5, commands.BucketType.user) @commands.guild_only() - async def spotifyinfo(self, ctx, user: discord.Member = None): + async def spotifyinfo(self, ctx: Context, user: discord.Member = None): user = user or ctx.author spotify: discord.Spotify = discord.utils.find( @@ -662,7 +667,9 @@ async def spotifyinfo(self, ctx, user: discord.Member = None): @commands.cooldown(1, 5, commands.BucketType.user) @commands.guild_only() async def permissions( - self, ctx, memberOrRole: Union[discord.Member, discord.Role, str] = None + self, + ctx: Context, + memberOrRole: Union[discord.Member, discord.User, discord.Role, str] = None, ): if isinstance(memberOrRole, str) or memberOrRole is None: memberOrRole = ctx.author @@ -693,7 +700,7 @@ async def permissions( usage="(project name)", ) @commands.cooldown(1, 5, commands.BucketType.user) - async def pypi(self, ctx, project: str): + async def pypi(self, ctx: Context, project: str): async with self.bot.session.get(f"https://pypi.org/pypi/{project}/json") as res: try: res = await res.json() From df729818fb1ceda091399642f8e0bca408f26d86 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 19:28:03 +0700 Subject: [PATCH 29/71] + [ 2 files changed ] - Make spotifyinfo uses authorOrReferenced --- README.md | 2 +- exts/info/info.py | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8ce56432..60c30e38 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) ### Pending Plan - i18n using gettext (Learning how gettext works) -- Slash command (RIP dpy, have to design this myself for now) +- Slash command (Waiting for ed.py's implementation) - Properly support different SQL scheme (designing best way to do this) ### Scrapped Plan diff --git a/exts/info/info.py b/exts/info/info.py index daad0169..b46f1587 100644 --- a/exts/info/info.py +++ b/exts/info/info.py @@ -41,12 +41,10 @@ def __init__(self, bot): aliases=("av", "userpfp", "pfp"), brief="Get member's avatar image" ) @commands.cooldown(1, 5, commands.BucketType.user) - async def avatar(self, ctx: Context, _user: MemberOrUser = None): - user: Union[discord.Member, discord.User] = _user or await authorOrReferenced( - ctx - ) # type: ignore + async def avatar(self, ctx: Context, user: MemberOrUser = None): + user = user or authorOrReferenced(ctx) # type: ignore - avatar = user.display_avatar + avatar: discord.Asset = user.display_avatar # type: ignore # Links to avatar (with different formats) links = ( @@ -64,7 +62,7 @@ async def avatar(self, ctx: Context, _user: MemberOrUser = None): # Embed stuff e = ZEmbed.default( ctx, - title="{}'s Avatar".format(user.name), + title="{}'s Avatar".format(user.name), # type: ignore description=links, ) e.set_image(url=avatar.with_size(1024).url) @@ -233,7 +231,7 @@ async def emojiSteal( emojiByte = await emoji.read() try: - addedEmoji = await ctx.guild.create_custom_emoji( + addedEmoji = await ctx.guild.create_custom_emoji( # type: ignore name=emoji.name, image=emojiByte ) except discord.Forbidden: @@ -440,7 +438,7 @@ def activity(x): }.get(x.type, "") + detail badges = [badge(x) for x in user.public_flags.all()] - if user == ctx.guild.owner: + if (guild := ctx.guild) and user == guild.owner: badges.append("<:owner:747802537402564758>") createdAt = user.created_at.replace(tzinfo=dt.timezone.utc) @@ -607,7 +605,7 @@ async def guildinfo(self, ctx): @commands.cooldown(1, 5, commands.BucketType.user) @commands.guild_only() async def spotifyinfo(self, ctx: Context, user: discord.Member = None): - user = user or ctx.author + user = user or authorOrReferenced(ctx) # type: ignore spotify: discord.Spotify = discord.utils.find( lambda s: isinstance(s, discord.Spotify), user.activities # type: ignore From 1f0dd3bb081b309218f0d251e751d7a1bd62d8b7 Mon Sep 17 00:00:00 2001 From: ziro Date: Tue, 31 Aug 2021 19:41:31 +0700 Subject: [PATCH 30/71] + TODO --- exts/meta/_help.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index db1302df..047d0e94 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -178,15 +178,10 @@ async def prepare_help_command(self, ctx, arguments) -> tuple: if not unique: unique = defFilters - # if not command and len(unique) == 1: - # TODO: get command list if no command specified and 1 filters specified - # This will merge `>command list` - # return None, None, unique - # pass - return command, unique async def send_custom_help(self): + # TODO: Improve the output ctx = self.context if not (guild := ctx.guild): From ac1b045a5303129b8df22319ff87085dd5918b66 Mon Sep 17 00:00:00 2001 From: ziro Date: Wed, 1 Sep 2021 12:39:11 +0700 Subject: [PATCH 31/71] + Fixed missing await --- exts/info/info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exts/info/info.py b/exts/info/info.py index b46f1587..394ffe38 100644 --- a/exts/info/info.py +++ b/exts/info/info.py @@ -42,7 +42,7 @@ def __init__(self, bot): ) @commands.cooldown(1, 5, commands.BucketType.user) async def avatar(self, ctx: Context, user: MemberOrUser = None): - user = user or authorOrReferenced(ctx) # type: ignore + user = user or await authorOrReferenced(ctx) # type: ignore avatar: discord.Asset = user.display_avatar # type: ignore @@ -605,7 +605,7 @@ async def guildinfo(self, ctx): @commands.cooldown(1, 5, commands.BucketType.user) @commands.guild_only() async def spotifyinfo(self, ctx: Context, user: discord.Member = None): - user = user or authorOrReferenced(ctx) # type: ignore + user = user or await authorOrReferenced(ctx) # type: ignore spotify: discord.Spotify = discord.utils.find( lambda s: isinstance(s, discord.Spotify), user.activities # type: ignore From c05ae52c1e4624704929fefb005fd8f5b5813a47 Mon Sep 17 00:00:00 2001 From: ziro Date: Wed, 1 Sep 2021 12:40:09 +0700 Subject: [PATCH 32/71] + [ 2 files changed ] - Update discord.py --- poetry.lock | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6bb14a15..a73f00d0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -260,7 +260,7 @@ python-versions = ">=3.5.3" [[package]] name = "discord.py" -version = "2.0.0a3582+g773ad6f5" +version = "2.0.0a3600+g6f561437" description = "A Python wrapper for the Discord API" category = "main" optional = false @@ -279,7 +279,7 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] type = "git" url = "https://github.com/iDevision/enhanced-discord.py" reference = "2.0" -resolved_reference = "773ad6f5bfa1c877085edd090f6fa0def1cbc704" +resolved_reference = "6f5614373a3c178c82d5145205dbc7427bcdd7d0" [[package]] name = "distlib" @@ -772,7 +772,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "e7f953c1b15c82571d52893b258bac93281712b0cddf63dacbd882448f5b1010" +content-hash = "be41777d8eafd52b87029296e7b71fdf3dc442980d92bfafda75a67a6c96e2b3" [metadata.files] aiohttp = [ diff --git a/pyproject.toml b/pyproject.toml index da6c6987..2745b64e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" aiohttp = "3.7.3" python = "^3.8" beautifulsoup4 = "^4.9.3" -"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", branch = "2.0", rev = "773ad6f5bfa1c877085edd090f6fa0def1cbc704"} +"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", branch = "2.0", rev = "6f5614373a3c178c82d5145205dbc7427bcdd7d0"} discord-ext-menus = "^1.1" fuzzywuzzy = "0.18.0" humanize = "3.7.0" From 5db6464e3aaaed5f59be60973b4fc44c94e098eb Mon Sep 17 00:00:00 2001 From: ziro Date: Wed, 1 Sep 2021 19:13:19 +0700 Subject: [PATCH 33/71] + [ 2 files changed ] - Updated some packages * Updated TSE * Switched to enhanced-dpy fork (temporarily?), to fixed TypeError --- poetry.lock | 16 ++++++++-------- pyproject.toml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/poetry.lock b/poetry.lock index a73f00d0..8aedb5b2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -260,7 +260,7 @@ python-versions = ">=3.5.3" [[package]] name = "discord.py" -version = "2.0.0a3600+g6f561437" +version = "2.0.0a3601+g2367d9d7" description = "A Python wrapper for the Discord API" category = "main" optional = false @@ -277,9 +277,9 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "git" -url = "https://github.com/iDevision/enhanced-discord.py" -reference = "2.0" -resolved_reference = "6f5614373a3c178c82d5145205dbc7427bcdd7d0" +url = "https://github.com/ZiRO-Bot/enhanced-discord.py" +reference = "2367d9d7e2d9fec871e34c5b0f3b88f717060974" +resolved_reference = "2367d9d7e2d9fec871e34c5b0f3b88f717060974" [[package]] name = "distlib" @@ -668,7 +668,7 @@ pymysql = ["pymysql (<1)", "pymysql"] [[package]] name = "TagScriptEngine" -version = "2.5.7" +version = "2.5.10a134+g4b89a36" description = "" category = "main" optional = false @@ -678,8 +678,8 @@ develop = false [package.source] type = "git" url = "https://github.com/ZiRO-Bot/TagScript" -reference = "653a9f101f4a35b88db0ea30455d1741aa5dee3d" -resolved_reference = "653a9f101f4a35b88db0ea30455d1741aa5dee3d" +reference = "4b89a369bb6e36ec07da75834da67dee0e351051" +resolved_reference = "4b89a369bb6e36ec07da75834da67dee0e351051" [[package]] name = "toml" @@ -772,7 +772,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "be41777d8eafd52b87029296e7b71fdf3dc442980d92bfafda75a67a6c96e2b3" +content-hash = "61974c9485ef23b9fd29ed4d7c959a4492c5781ce52b2ba963e638b92b788a0c" [metadata.files] aiohttp = [ diff --git a/pyproject.toml b/pyproject.toml index 2745b64e..95d2f53b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" aiohttp = "3.7.3" python = "^3.8" beautifulsoup4 = "^4.9.3" -"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", branch = "2.0", rev = "6f5614373a3c178c82d5145205dbc7427bcdd7d0"} +"discord.py" = {git = "https://github.com/ZiRO-Bot/enhanced-discord.py", rev = "2367d9d7e2d9fec871e34c5b0f3b88f717060974"} discord-ext-menus = "^1.1" fuzzywuzzy = "0.18.0" humanize = "3.7.0" @@ -21,7 +21,7 @@ python-Levenshtein = "^0.12.2" pytz = "^2021.1" pyparsing = "^2.4.7" requests = "^2.26.0" -tagscriptengine = {git = "https://github.com/ZiRO-Bot/TagScript", rev = "653a9f101f4a35b88db0ea30455d1741aa5dee3d"} +tagscriptengine = {git = "https://github.com/ZiRO-Bot/TagScript", rev = "4b89a369bb6e36ec07da75834da67dee0e351051"} uvloop = "^0.15.3" typing-extensions = "^3.10.0" databases = "^0.4.3" From 0a3b645e93ed4170ca8f8116ca4383562194f07a Mon Sep 17 00:00:00 2001 From: ziro Date: Wed, 1 Sep 2021 20:33:44 +0700 Subject: [PATCH 34/71] + [ 2 files changed ] - Updated TSE --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8aedb5b2..2e1a74e2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -668,7 +668,7 @@ pymysql = ["pymysql (<1)", "pymysql"] [[package]] name = "TagScriptEngine" -version = "2.5.10a134+g4b89a36" +version = "2.5.11a135+g1c3d2b0" description = "" category = "main" optional = false @@ -678,8 +678,8 @@ develop = false [package.source] type = "git" url = "https://github.com/ZiRO-Bot/TagScript" -reference = "4b89a369bb6e36ec07da75834da67dee0e351051" -resolved_reference = "4b89a369bb6e36ec07da75834da67dee0e351051" +reference = "1c3d2b01c3228b44d26f0707c4809503fb6a2f50" +resolved_reference = "1c3d2b01c3228b44d26f0707c4809503fb6a2f50" [[package]] name = "toml" @@ -772,7 +772,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "61974c9485ef23b9fd29ed4d7c959a4492c5781ce52b2ba963e638b92b788a0c" +content-hash = "ce56565a0c9d079a093c9248cdf01dac38ffa2130b1446097bbba737891cf763" [metadata.files] aiohttp = [ diff --git a/pyproject.toml b/pyproject.toml index 95d2f53b..c84ade8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ python-Levenshtein = "^0.12.2" pytz = "^2021.1" pyparsing = "^2.4.7" requests = "^2.26.0" -tagscriptengine = {git = "https://github.com/ZiRO-Bot/TagScript", rev = "4b89a369bb6e36ec07da75834da67dee0e351051"} +tagscriptengine = {git = "https://github.com/ZiRO-Bot/TagScript", rev = "1c3d2b01c3228b44d26f0707c4809503fb6a2f50"} uvloop = "^0.15.3" typing-extensions = "^3.10.0" databases = "^0.4.3" From 4bfe5cd805b0561c9be67f4a600dcdb4e5b138e6 Mon Sep 17 00:00:00 2001 From: ziro Date: Thu, 2 Sep 2021 12:10:34 +0700 Subject: [PATCH 35/71] + [ 3 files changed ] - Added ZChoices * Command disabler now uses choices instead of flags --- core/menus.py | 53 +++++++++++++-- exts/dev/dev.py | 9 ++- exts/meta/meta.py | 168 ++++++++++++++++++++++++---------------------- 3 files changed, 141 insertions(+), 89 deletions(-) diff --git a/core/menus.py b/core/menus.py index 656b7785..7f7fe21b 100644 --- a/core/menus.py +++ b/core/menus.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import asyncio +from collections import namedtuple from contextlib import suppress -from typing import List, Optional, Union +from typing import TYPE_CHECKING, Any, Iterable, List, Optional, Union import discord from discord.ext import menus @@ -9,6 +12,10 @@ from core.views import ZView +if TYPE_CHECKING: + from core.context import Context + + class ZMenu(menus.MenuPages): def __init__(self, source, init_msg=None, check_embeds=True, ping=False, loop=None): super().__init__(source=source, check_embeds=check_embeds) @@ -46,7 +53,7 @@ async def finalize(self, timed_out): class ZReplyMenu(ZMenu): - def __init__(self, source, ping=False): + def __init__(self, source, ping=False) -> None: self.ping = ping or False super().__init__(source=source, check_embeds=True) @@ -74,7 +81,7 @@ class ZMenuView(ZView): def __init__( self, - ctx, + ctx: Context, *, timeout: float = 180.0, ownerOnly: bool = True, @@ -118,7 +125,7 @@ class ZMenuPagesView(ZMenuView): def __init__( self, - ctx, + ctx: Context, source: Union[menus.PageSource, Pages], **kwargs, ) -> None: @@ -176,7 +183,7 @@ async def sendPage( self.currentPage = pageNumber kwargs = await self.getPage(pageNumber) self._pageInfo.label = f"Page {pageNumber+1}/{self.getMaxPages()}" - await interaction.message.edit(view=self, **kwargs) + await interaction.message.edit(view=self, **kwargs) # type: ignore async def sendCheckedPage(self, interaction: discord.Interaction, pageNumber): maxPages = self.getMaxPages() @@ -228,8 +235,8 @@ async def _pageInfo( message: discord.Message = await self.context.bot.wait_for( "message", timeout=30.0, - check=lambda msg: msg.author.id == interaction.user.id - and msg.channel.id == interaction.channel.id + check=lambda msg: msg.author.id == interaction.user.id # type: ignore + and msg.channel.id == interaction.channel.id # type: ignore and msg.content.isdigit(), ) with suppress(discord.HTTPException, discord.NotFound): @@ -259,3 +266,35 @@ async def _last(self, button: discord.ui.Button, interaction: discord.Interactio ) async def _stop(self, button: discord.ui.Button, interaction: discord.Interaction): await self.stop() + + +choice = namedtuple("choice", ("label", "value")) + + +class ZChoices(ZView): + """Basically send choices as buttons""" + + def __init__(self, ctx: Context, choices: Iterable[Any]): + super().__init__(owner=ctx.author) + self.context = ctx + self.choices: Iterable[Any] = choices + self.value: Any = None + + def makeCallback(choice): + async def callback(interaction): + await interaction.response.defer() + self.value = choice.value + self.stop() + + return callback + + for choice in self.choices: + button = discord.ui.Button(label=choice.label) + button.callback = makeCallback(choice) + self.add_item(button) + + async def wait(self): + await super().wait() + + async def start(self): + await self.wait() diff --git a/exts/dev/dev.py b/exts/dev/dev.py index c5bad693..f1ead902 100644 --- a/exts/dev/dev.py +++ b/exts/dev/dev.py @@ -14,7 +14,7 @@ from core.bot import EXTS_DIR from core.embed import ZEmbed -from core.menus import ZMenuPagesView +from core.menus import ZChoices, ZMenuPagesView, choice # --- For reload all command status @@ -153,3 +153,10 @@ async def testloading(self, ctx): async with ctx.loading(): await asyncio.sleep(5) await ctx.send(":D") + + @commands.command() + async def testchoices(self, ctx): + res = ZChoices(ctx, [choice("a", "aa"), choice("b", "bb")]) + await ctx.send(":)", view=res) + await res.wait() + await ctx.send(res.value) diff --git a/exts/meta/meta.py b/exts/meta/meta.py index 90a14063..95c8c2ce 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -24,7 +24,7 @@ CCommandNotFound, CCommandNotInGuild, ) -from core.menus import ZMenuPagesView +from core.menus import ZChoices, ZMenuPagesView, choice from core.mixin import CogMixin from utils import dbQuery, sql, tseBlocks from utils.cache import CacheListProperty, CacheUniqueViolation @@ -735,114 +735,102 @@ async def remove(self, ctx, name: CMDName): brief="Disable a command", description=( "Disable a command.\n\n" - "Support both custom and built-in command.\n" - "(Will try to disable custom command or built-in if " - "you're a moderator by default)\n" - "Note: Server admin/mods still able to use disabled **built-in** " - "command." + "Support both custom and built-in command.\n\n" + "**New in `3.3.0`**: Removed options/flags. You'll get choices " + "when you can disable more than 1 type of command (or category)." ), extras=dict( example=( "command disable example", - "cmd disable built-in: on weather", - "command disable built-in: on cat: on info", - "cmd disable custom: on test", + "cmd disable weather", + "command disable info", + "cmd disable test", ), - flags={ - "built-in": "Disable built-in command", - "custom": "Disable custom command", - ( - "category", - "cat", - ): "Disable all command in a specific category (Requires `built-in` flag)", - }, perms={ "bot": None, - "user": "Moderator Role or Manage Guild (Built-in only)", + "user": "Depends on custom command mode or (Moderator Role or Manage Guild)", }, ), - usage="(name) [options]", + usage="(command/category name)", ) - async def disable(self, ctx, *, arguments: CmdManagerFlags): - name, parsed = arguments + async def disable(self, ctx, *, name): if not name: return await ctx.error("You need to specify the command's name!") isMod = await checks.isMod(ctx) - # default mode - mode = "built-in" if isMod else "custom" - - if parsed.built_in and not parsed.custom: - mode = "built-in" if not parsed.category else "category" - if not parsed.built_in and parsed.custom: - mode = "custom" - successMsg = "`{}` has been disabled" alreadyMsg = "`{}` already disabled!" - notFoundMsg = "There is not {} command called `{}`" immuneRoot = ("help", "command") - if mode in ("built-in", "category"): - # check if executor is a mod for built-in and category mode - if not isMod: - return await ctx.error( - title="Only mods allowed to disable built-in command" + foundList = [] + if isMod: + cmd = self.bot.get_command(str(name)) + if cmd: + cmdName = formatCmdName(cmd) + + if str(cmd.root_parent or cmdName) not in immuneRoot: + # check if command root parent is immune + foundList.append( + choice(f"{cmdName} (Built-in Command)", (cmdName, "command")) + ) + + category = self.bot.get_cog(str(name)) + if category: + foundList.append( + choice( + f"{category.qualified_name} (Category)", (category, "category") + ) ) - if mode == "built-in": - command = self.bot.get_command(name) - if not command: - # check if command exists - return await ctx.error(title=notFoundMsg.format(mode, name)) - - # format command name - cmdName = formatCmdName(command) - - if str(command.root_parent or cmdName) in immuneRoot: - # check if command root parent is immune - return await ctx.error(title="This command can't be disabled!") + try: + cc = await getCustomCommand(ctx, name) + except CCommandNotFound: + pass + else: + foundList.append(choice(f"{cc.name} (Custom Command)", (cc, "custom"))) - # Make sure disable command is cached from database - await getDisabledCommands(self.bot, ctx.guild.id) + if len(foundList) <= 0: + # Nothing found, abort + return await ctx.error( + f"No command/category called '{name}' can be disabled" + ) - try: - self.bot.cache.disabled.append(ctx.guild.id, cmdName) - except CacheUniqueViolation: - # check if command already disabled - return await ctx.error(title=alreadyMsg.format(cmdName)) + chosen = None - async with ctx.db.transaction(): - await ctx.db.execute( - """ - INSERT INTO disabled VALUES (:guildId, :command) - """, - values={"guildId": ctx.guild.id, "command": cmdName}, - ) + if len(foundList) == 1: + chosen = foundList[0].value + else: + choices = ZChoices(ctx, foundList) + msg = await ctx.send("Which one do you want to disable?", view=choices) + await choices.wait() + await msg.delete() + chosen = choices.value - return await ctx.success(title=successMsg.format(cmdName)) + if not chosen: + return - elif mode == "category": - category = self.bot.get_cog(name) - commands = [ - c.name for c in category.get_commands() if c.name not in immuneRoot - ] + mode = chosen[1] - # Make sure disable command is cached from database - await getDisabledCommands(self.bot, ctx.guild.id) + if mode == "category": + disabled = await getDisabledCommands(self.bot, ctx.guild.id) added = [] - for c in commands: - try: - self.bot.cache.disabled.append(ctx.guild.id, c) - added.append(c) - except CacheUniqueViolation: - continue + added.extend( + [ + c.name + for c in chosen[0].get_commands() + if c.name not in immuneRoot and c.name not in disabled + ] + ) if not added: return await ctx.error(title="No commands succesfully disabled") + self.bot.cache.disabled.extend(ctx.guild.id, added) + async with ctx.db.transaction(): + # TODO: Should also disable custom commands await ctx.db.execute_many( """ INSERT INTO disabled VALUES (:guildId, :command) @@ -854,12 +842,8 @@ async def disable(self, ctx, *, arguments: CmdManagerFlags): title="`{}` commands has been disabled".format(len(added)) ) - elif mode == "custom": - try: - command = await getCustomCommand(ctx, name) - except CCommandNotFound: - return await ctx.error(title=notFoundMsg.format(mode, name)) - + if mode == "custom": + command = chosen[0] perm = await self.ccModeCheck(ctx, command=command) if not perm: raise CCommandNoPerm @@ -878,6 +862,28 @@ async def disable(self, ctx, *, arguments: CmdManagerFlags): ) return await ctx.success(title=successMsg.format(name)) + if mode == "command": + cmdName = chosen[0] + + # Make sure disable command is cached from database + await getDisabledCommands(self.bot, ctx.guild.id) + + try: + self.bot.cache.disabled.append(ctx.guild.id, cmdName) + except CacheUniqueViolation: + # check if command already disabled + return await ctx.error(title=alreadyMsg.format(cmdName)) + + async with ctx.db.transaction(): + await ctx.db.execute( + """ + INSERT INTO disabled VALUES (:guildId, :command) + """, + values={"guildId": ctx.guild.id, "command": cmdName}, + ) + + return await ctx.success(title=successMsg.format(cmdName)) + @command.command( brief="Enable a command", description=( From b9bd93370f8d58e2f15ba1be6536b594174a178c Mon Sep 17 00:00:00 2001 From: ziro Date: Thu, 2 Sep 2021 19:56:20 +0700 Subject: [PATCH 36/71] + Command enabler now uses choices instead of flags * Added helper for command enabler and disabler to reduce duplication --- exts/meta/meta.py | 189 +++++++++++++++++++++++----------------------- 1 file changed, 96 insertions(+), 93 deletions(-) diff --git a/exts/meta/meta.py b/exts/meta/meta.py index 95c8c2ce..e659687c 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -8,7 +8,7 @@ import difflib import re import time -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Iterable, Tuple import discord import humanize @@ -731,41 +731,24 @@ async def remove(self, ctx, name: CMDName): ) ) - @command.command( - brief="Disable a command", - description=( - "Disable a command.\n\n" - "Support both custom and built-in command.\n\n" - "**New in `3.3.0`**: Removed options/flags. You'll get choices " - "when you can disable more than 1 type of command (or category)." - ), - extras=dict( - example=( - "command disable example", - "cmd disable weather", - "command disable info", - "cmd disable test", - ), - perms={ - "bot": None, - "user": "Depends on custom command mode or (Moderator Role or Manage Guild)", - }, - ), - usage="(command/category name)", - ) - async def disable(self, ctx, *, name): - if not name: - return await ctx.error("You need to specify the command's name!") - - isMod = await checks.isMod(ctx) - - successMsg = "`{}` has been disabled" - alreadyMsg = "`{}` already disabled!" - immuneRoot = ("help", "command") - - foundList = [] + @staticmethod + async def disableEnableHelper( + ctx, name, /, *, isMod: bool, immuneRoot: Iterable[str] = ("help", "command") + ) -> Tuple[Any, str]: + """Helper for `command disable` and `command enable` + + - Find built-in command, custom command, and category + - Give choices to user when there's more than 1 type is found + with identical name + - Return user's choice (or raise RuntimeError when user + doesn't choose anything) + """ + foundList = [] # contains built-in and custom command, also category + + # only mods allowed to disable built-in commands if isMod: - cmd = self.bot.get_command(str(name)) + # find built-in command + cmd = ctx.bot.get_command(str(name)) if cmd: cmdName = formatCmdName(cmd) @@ -775,7 +758,8 @@ async def disable(self, ctx, *, name): choice(f"{cmdName} (Built-in Command)", (cmdName, "command")) ) - category = self.bot.get_cog(str(name)) + # find category + category = ctx.bot.get_cog(str(name)) if category: foundList.append( choice( @@ -783,6 +767,7 @@ async def disable(self, ctx, *, name): ) ) + # find custom command try: cc = await getCustomCommand(ctx, name) except CCommandNotFound: @@ -799,8 +784,10 @@ async def disable(self, ctx, *, name): chosen = None if len(foundList) == 1: + # default chosen value chosen = foundList[0].value else: + # give user choices, since there's more than 1 type is found choices = ZChoices(ctx, foundList) msg = await ctx.send("Which one do you want to disable?", view=choices) await choices.wait() @@ -808,6 +795,48 @@ async def disable(self, ctx, *, name): chosen = choices.value if not chosen: + # nothing is chosen, abort (only happened when choices triggered) + raise RuntimeError("Nothing is chosen") + + return chosen + + @command.command( + brief="Disable a command", + description=( + "Disable a command.\n\n" + "Support both custom and built-in command.\n\n" + "**New in `3.3.0`**: Removed options/flags. You'll get choices " + "when you can disable more than 1 type of command (or category)." + ), + extras=dict( + example=( + "command disable example", + "cmd disable weather", + "command disable info", + "cmd disable test", + ), + perms={ + "bot": None, + "user": "Depends on custom command mode or (Moderator Role or Manage Guild)", + }, + ), + usage="(command/category name)", + ) + async def disable(self, ctx, *, name): + if not name: + return await ctx.error("You need to specify the command's name!") + + isMod = await checks.isMod(ctx) + + successMsg = "`{}` has been disabled" + alreadyMsg = "`{}` already disabled!" + immuneRoot = ("help", "command") + + try: + chosen = await self.disableEnableHelper( + ctx, name, isMod=isMod, immuneRoot=immuneRoot + ) + except RuntimeError: return mode = chosen[1] @@ -921,66 +950,23 @@ async def enable(self, ctx, *, arguments: CmdManagerFlags): isMod = await checks.isMod(ctx) - # default mode - mode = "built-in" if isMod else "custom" - - if parsed.built_in and not parsed.custom: - mode = "built-in" if not parsed.category else "category" - if not parsed.built_in and parsed.custom: - mode = "custom" - successMsg = "`{}` has been enabled" alreadyMsg = "`{}` already enabled!" notFoundMsg = "There is not {} command called `{}`" - if mode in ("built-in", "category"): - # check if executor is a mod for built-in and category mode - if not isMod: - return await ctx.error( - title="Only mods allowed to enable built-in command" - ) - - if mode == "built-in": - command = self.bot.get_command(name) - if not command: - # check if command exists - return await ctx.error(title=notFoundMsg.format(mode, name)) - - # format command name - cmdName = formatCmdName(command) - - await getDisabledCommands(self.bot, ctx.guild.id) - - try: - self.bot.cache.disabled.remove(ctx.guild.id, cmdName) - except ValueError: - # check if command already enabled - return await ctx.error(title=alreadyMsg.format(cmdName)) - - async with ctx.db.transaction(): - await ctx.db.execute( - """ - DELETE FROM disabled - WHERE - guildId=:guildId AND command=:command - """, - values={"guildId": ctx.guild.id, "command": cmdName}, - ) + chosen = await self.disableEnableHelper(ctx, name, isMod=isMod, immuneRoot=[]) - return await ctx.success(title=successMsg.format(cmdName)) + mode = chosen[1] - elif mode == "category": - category = self.bot.get_cog(name) - await getDisabledCommands(self.bot, ctx.guild.id) - commands = [c.name for c in category.get_commands()] + if mode == "category": + disabled = await getDisabledCommands(self.bot, ctx.guild.id) removed = [] - for c in commands: - try: - self.bot.cache.disabled.remove(c) - removed.append(c) - except ValueError: + for c in chosen[0].get_commands(): + if c.name not in disabled: continue + self.bot.cache.disabled.remove(c) + removed.append(c) if not removed: return await ctx.error(title="No commands succesfully enabled") @@ -999,12 +985,8 @@ async def enable(self, ctx, *, arguments: CmdManagerFlags): title="`{}` commands has been enabled".format(len(removed)) ) - elif mode == "custom": - try: - command = await getCustomCommand(ctx, name) - except CCommandNotFound: - return await ctx.error(title=notFoundMsg.format(mode, name)) - + if mode == "custom": + command = chosen[0] perm = await self.ccModeCheck(ctx, command=command) if not perm: raise CCommandNoPerm @@ -1023,6 +1005,27 @@ async def enable(self, ctx, *, arguments: CmdManagerFlags): ) return await ctx.success(title=successMsg.format(name)) + if mode == "command": + cmdName = chosen[0] + + try: + self.bot.cache.disabled.remove(ctx.guild.id, cmdName) + except ValueError: + # check if command already enabled + return await ctx.error(title=alreadyMsg.format(cmdName)) + + async with ctx.db.transaction(): + await ctx.db.execute( + """ + DELETE FROM disabled + WHERE + guildId=:guildId AND command=:command + """, + values={"guildId": ctx.guild.id, "command": cmdName}, + ) + + return await ctx.success(title=successMsg.format(cmdName)) + @command.command( aliases=("?",), brief="Show command's information", From faf1ec2fcb9faaef66d1d60159f365042f515bb8 Mon Sep 17 00:00:00 2001 From: ziro Date: Thu, 2 Sep 2021 19:58:29 +0700 Subject: [PATCH 37/71] + Handle RuntimeError --- exts/meta/meta.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/exts/meta/meta.py b/exts/meta/meta.py index e659687c..e91f787c 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -952,9 +952,13 @@ async def enable(self, ctx, *, arguments: CmdManagerFlags): successMsg = "`{}` has been enabled" alreadyMsg = "`{}` already enabled!" - notFoundMsg = "There is not {} command called `{}`" - chosen = await self.disableEnableHelper(ctx, name, isMod=isMod, immuneRoot=[]) + try: + chosen = await self.disableEnableHelper( + ctx, name, isMod=isMod, immuneRoot=[] + ) + except RuntimeError: + return mode = chosen[1] From 8a284d48a05198035f93b2adb412bb66413c1485 Mon Sep 17 00:00:00 2001 From: ziro Date: Thu, 2 Sep 2021 20:01:29 +0700 Subject: [PATCH 38/71] + [ 2 files changed ] - Changelog and remove stuff about flags on cmd enable --- CHANGELOG.md | 3 +++ exts/meta/meta.py | 24 ++++++++---------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ab3ce33..cc016db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ request audit logs twice - [**Improved**] Decrease modlog delay to 2 seconds delay - [**Improved**] Merged `>help filter: custom` with `>command list` +- [**Changed**] `>command disable` and `>command enable` no longer uses flag, + replaced with choice buttons when there's more than 1 type is found with + identical name # v3.2 diff --git a/exts/meta/meta.py b/exts/meta/meta.py index e91f787c..a5aad69b 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -917,31 +917,23 @@ async def disable(self, ctx, *, name): brief="Enable a command", description=( "Enable a command.\n\n" - "Support both custom and built-in command.\n" - "(Will try to enable custom command or built-in if " - "you're a moderator by default)" + "Support both custom and built-in command.\n\n" + "**New in `3.3.0`**: Removed options/flags. You'll get choices " + "when you can enable more than 1 type of command (or category)." ), extras=dict( example=( "command enable example", - "cmd enable built-in: on weather", - "cmd enable built-in: on cat: on info", - "cmd enable custom: on test", + "cmd enable weather", + "cmd enable info", + "cmd enable test", ), - flags={ - "built-in": "Emable built-in command", - "custom": "Enable custom command", - ( - "category", - "cat", - ): "Enable all command in a specific category (Requires `built-in` flag)", - }, perms={ "bot": None, - "user": "Moderator Role or Manage Guild (Built-in only)", + "user": "Depends on custom command mode or (Moderator Role or Manage Guild)", }, ), - usage="(name) [options]", + usage="(name)", ) async def enable(self, ctx, *, arguments: CmdManagerFlags): name, parsed = arguments From 1b20b93b87b2a5bb9ee73b3f83658ab30ac4d1b7 Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 06:28:26 +0700 Subject: [PATCH 39/71] + Temporarily disable google search --- exts/utilities/utilities.py | 110 ++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/exts/utilities/utilities.py b/exts/utilities/utilities.py index e290f2fd..dd487df3 100644 --- a/exts/utilities/utilities.py +++ b/exts/utilities/utilities.py @@ -165,69 +165,69 @@ async def unmorse(self, ctx, *, code): except ValueError: await ctx.error("Invalid morse code!") - @commands.command( - aliases=("g",), - brief="Searches Google", - description=( - "Searches Google\n" - 'Support "special" results, currently supports: Complementary ' - "Results, Currency Converter" - ), - ) - @commands.cooldown(1, 10, commands.BucketType.user) - async def google(self, ctx, *, query: str): - msg = await ctx.try_reply(embed=ZEmbed.loading(title="Searching...")) - results = await self.googlesearch.search(query) + # @commands.command( + # aliases=("g",), + # brief="Searches Google", + # description=( + # "Searches Google\n" + # 'Support "special" results, currently supports: Complementary ' + # "Results, Currency Converter" + # ), + # ) + # @commands.cooldown(1, 10, commands.BucketType.user) + # async def google(self, ctx, *, query: str): + # msg = await ctx.try_reply(embed=ZEmbed.loading(title="Searching...")) + # results = await self.googlesearch.search(query) - if results is None: - await msg.delete() - return await ctx.error( - "Your search - {} - did not match any documents.".format(query), - title="Not found!", - ) + # if results is None: + # await msg.delete() + # return await ctx.error( + # "Your search - {} - did not match any documents.".format(query), + # title="Not found!", + # ) - e = ZEmbed.default(ctx) - e.set_author(name="Search result for '{}'".format(query)) + # e = ZEmbed.default(ctx) + # e.set_author(name="Search result for '{}'".format(query)) - e.set_footer(text=results["stats"]) + # e.set_footer(text=results["stats"]) - complementary = results["complementary"] - special = results["special"] - limit = 3 + # complementary = results["complementary"] + # special = results["special"] + # limit = 3 - if complementary is not None: - limit -= 1 - e.add_field( - name=f"{complementary.title or 'Unknown'}", - value=( - f"`{complementary.subtitle or 'Unknown'}`\n" - if complementary.subtitle - else "" - ) - + ( - complementary.description + "\n" - if complementary.description - else "" - ) - + "\n".join([f"**{i}**`{j}`" for i, j in complementary.info]), - ) + # if complementary is not None: + # limit -= 1 + # e.add_field( + # name=f"{complementary.title or 'Unknown'}", + # value=( + # f"`{complementary.subtitle or 'Unknown'}`\n" + # if complementary.subtitle + # else "" + # ) + # + ( + # complementary.description + "\n" + # if complementary.description + # else "" + # ) + # + "\n".join([f"**{i}**`{j}`" for i, j in complementary.info]), + # ) - if special: - limit -= 1 - e.add_field( - name=str(special.type).title(), - value="\n".join(special.content), - ) + # if special: + # limit -= 1 + # e.add_field( + # name=str(special.type).title(), + # value="\n".join(special.content), + # ) - for res in results["web"][:limit]: - try: - content = res.contents[0] - except IndexError: - content = "" - e.add_field(name=res.title, value=f"{res.link}\n{content}", inline=False) + # for res in results["web"][:limit]: + # try: + # content = res.contents[0] + # except IndexError: + # content = "" + # e.add_field(name=res.title, value=f"{res.link}\n{content}", inline=False) - await msg.delete() - await ctx.try_reply(embed=e) + # await msg.delete() + # await ctx.try_reply(embed=e) @commands.command( brief="Get shorten url's real url. No more rick roll!", From 0a79f4d5ce0986b9fbebe7c92634062021a88e0d Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 06:45:19 +0700 Subject: [PATCH 40/71] + [ 2 files changed ] - Update some packages --- poetry.lock | 98 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/poetry.lock b/poetry.lock index 2e1a74e2..b557ffa4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -260,7 +260,7 @@ python-versions = ">=3.5.3" [[package]] name = "discord.py" -version = "2.0.0a3601+g2367d9d7" +version = "2.0.0a3619+g3ffe1348" description = "A Python wrapper for the Discord API" category = "main" optional = false @@ -277,9 +277,9 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "git" -url = "https://github.com/ZiRO-Bot/enhanced-discord.py" -reference = "2367d9d7e2d9fec871e34c5b0f3b88f717060974" -resolved_reference = "2367d9d7e2d9fec871e34c5b0f3b88f717060974" +url = "https://github.com/iDevision/enhanced-discord.py" +reference = "3ffe1348956ebc1e2512439b532fdb6516c267c6" +resolved_reference = "3ffe1348956ebc1e2512439b532fdb6516c267c6" [[package]] name = "distlib" @@ -441,7 +441,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "pillow" -version = "8.3.1" +version = "8.3.2" description = "Python Imaging Library (Fork)" category = "main" optional = false @@ -461,7 +461,7 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock [[package]] name = "pre-commit" -version = "2.14.1" +version = "2.15.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false @@ -772,7 +772,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "ce56565a0c9d079a093c9248cdf01dac38ffa2130b1446097bbba737891cf763" +content-hash = "353c0ab070d2656e0ece5311983ce57a5765972521eb44a48094bcc2e96b8ce9" [metadata.files] aiohttp = [ @@ -1050,53 +1050,55 @@ pathspec = [ {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] pillow = [ - {file = "Pillow-8.3.1-1-cp36-cp36m-win_amd64.whl", hash = "sha256:fd7eef578f5b2200d066db1b50c4aa66410786201669fb76d5238b007918fb24"}, - {file = "Pillow-8.3.1-1-cp37-cp37m-win_amd64.whl", hash = "sha256:75e09042a3b39e0ea61ce37e941221313d51a9c26b8e54e12b3ececccb71718a"}, - {file = "Pillow-8.3.1-1-cp38-cp38-win_amd64.whl", hash = "sha256:c0e0550a404c69aab1e04ae89cca3e2a042b56ab043f7f729d984bf73ed2a093"}, - {file = "Pillow-8.3.1-1-cp39-cp39-win_amd64.whl", hash = "sha256:479ab11cbd69612acefa8286481f65c5dece2002ffaa4f9db62682379ca3bb77"}, - {file = "Pillow-8.3.1-1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f156d6ecfc747ee111c167f8faf5f4953761b5e66e91a4e6767e548d0f80129c"}, - {file = "Pillow-8.3.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:196560dba4da7a72c5e7085fccc5938ab4075fd37fe8b5468869724109812edd"}, - {file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c9569049d04aaacd690573a0398dbd8e0bf0255684fee512b413c2142ab723"}, - {file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c088a000dfdd88c184cc7271bfac8c5b82d9efa8637cd2b68183771e3cf56f04"}, - {file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fc214a6b75d2e0ea7745488da7da3c381f41790812988c7a92345978414fad37"}, - {file = "Pillow-8.3.1-cp36-cp36m-win32.whl", hash = "sha256:a17ca41f45cf78c2216ebfab03add7cc350c305c38ff34ef4eef66b7d76c5229"}, - {file = "Pillow-8.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:67b3666b544b953a2777cb3f5a922e991be73ab32635666ee72e05876b8a92de"}, - {file = "Pillow-8.3.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:ff04c373477723430dce2e9d024c708a047d44cf17166bf16e604b379bf0ca14"}, - {file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9364c81b252d8348e9cc0cb63e856b8f7c1b340caba6ee7a7a65c968312f7dab"}, - {file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a2f381932dca2cf775811a008aa3027671ace723b7a38838045b1aee8669fdcf"}, - {file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d0da39795049a9afcaadec532e7b669b5ebbb2a9134576ebcc15dd5bdae33cc0"}, - {file = "Pillow-8.3.1-cp37-cp37m-win32.whl", hash = "sha256:2b6dfa068a8b6137da34a4936f5a816aba0ecc967af2feeb32c4393ddd671cba"}, - {file = "Pillow-8.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a4eef1ff2d62676deabf076f963eda4da34b51bc0517c70239fafed1d5b51500"}, - {file = "Pillow-8.3.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:660a87085925c61a0dcc80efb967512ac34dbb256ff7dd2b9b4ee8dbdab58cf4"}, - {file = "Pillow-8.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:15a2808e269a1cf2131930183dcc0419bc77bb73eb54285dde2706ac9939fa8e"}, - {file = "Pillow-8.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:969cc558cca859cadf24f890fc009e1bce7d7d0386ba7c0478641a60199adf79"}, - {file = "Pillow-8.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ee77c14a0299d0541d26f3d8500bb57e081233e3fa915fa35abd02c51fa7fae"}, - {file = "Pillow-8.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c11003197f908878164f0e6da15fce22373ac3fc320cda8c9d16e6bba105b844"}, - {file = "Pillow-8.3.1-cp38-cp38-win32.whl", hash = "sha256:3f08bd8d785204149b5b33e3b5f0ebbfe2190ea58d1a051c578e29e39bfd2367"}, - {file = "Pillow-8.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:70af7d222df0ff81a2da601fab42decb009dc721545ed78549cb96e3a1c5f0c8"}, - {file = "Pillow-8.3.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:37730f6e68bdc6a3f02d2079c34c532330d206429f3cee651aab6b66839a9f0e"}, - {file = "Pillow-8.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bc3c7ef940eeb200ca65bd83005eb3aae8083d47e8fcbf5f0943baa50726856"}, - {file = "Pillow-8.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c35d09db702f4185ba22bb33ef1751ad49c266534339a5cebeb5159d364f6f82"}, - {file = "Pillow-8.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b2efa07f69dc395d95bb9ef3299f4ca29bcb2157dc615bae0b42c3c20668ffc"}, - {file = "Pillow-8.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cc866706d56bd3a7dbf8bac8660c6f6462f2f2b8a49add2ba617bc0c54473d83"}, - {file = "Pillow-8.3.1-cp39-cp39-win32.whl", hash = "sha256:9a211b663cf2314edbdb4cf897beeb5c9ee3810d1d53f0e423f06d6ebbf9cd5d"}, - {file = "Pillow-8.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:c2a5ff58751670292b406b9f06e07ed1446a4b13ffced6b6cab75b857485cbc8"}, - {file = "Pillow-8.3.1-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c379425c2707078dfb6bfad2430728831d399dc95a7deeb92015eb4c92345eaf"}, - {file = "Pillow-8.3.1-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:114f816e4f73f9ec06997b2fde81a92cbf0777c9e8f462005550eed6bae57e63"}, - {file = "Pillow-8.3.1-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8960a8a9f4598974e4c2aeb1bff9bdd5db03ee65fd1fce8adf3223721aa2a636"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:147bd9e71fb9dcf08357b4d530b5167941e222a6fd21f869c7911bac40b9994d"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1fd5066cd343b5db88c048d971994e56b296868766e461b82fa4e22498f34d77"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f4ebde71785f8bceb39dcd1e7f06bcc5d5c3cf48b9f69ab52636309387b097c8"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c03e24be975e2afe70dfc5da6f187eea0b49a68bb2b69db0f30a61b7031cee4"}, - {file = "Pillow-8.3.1.tar.gz", hash = "sha256:2cac53839bfc5cece8fdbe7f084d5e3ee61e1303cccc86511d351adcb9e2c792"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, + {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, + {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, + {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, + {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, + {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, + {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, + {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, + {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, + {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, + {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, + {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, + {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, + {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, ] platformdirs = [ {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, ] pre-commit = [ - {file = "pre_commit-2.14.1-py2.py3-none-any.whl", hash = "sha256:a22d12a02da4d8df314187dfe7a61bda6291d57992060522feed30c8cd658b68"}, - {file = "pre_commit-2.14.1.tar.gz", hash = "sha256:7977a3103927932d4823178cbe4719ab55bb336f42a9f3bb2776cff99007a117"}, + {file = "pre_commit-2.15.0-py2.py3-none-any.whl", hash = "sha256:a4ed01000afcb484d9eb8d504272e642c4c4099bbad3a6b27e519bd6a3e928a6"}, + {file = "pre_commit-2.15.0.tar.gz", hash = "sha256:3c25add78dbdfb6a28a651780d5c311ac40dd17f160eb3954a0c59da40a505a7"}, ] "prettify.py" = [] psycopg2-binary = [ diff --git a/pyproject.toml b/pyproject.toml index c84ade8c..1fe29ad9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" aiohttp = "3.7.3" python = "^3.8" beautifulsoup4 = "^4.9.3" -"discord.py" = {git = "https://github.com/ZiRO-Bot/enhanced-discord.py", rev = "2367d9d7e2d9fec871e34c5b0f3b88f717060974"} +"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", rev = "3ffe1348956ebc1e2512439b532fdb6516c267c6"} discord-ext-menus = "^1.1" fuzzywuzzy = "0.18.0" humanize = "3.7.0" From d45f5df9463b9df4a4e98afa8cf3b372d6194488 Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 07:53:40 +0700 Subject: [PATCH 41/71] + [ 2 files changed ] - Downgrade, cuz someone broke it again... --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index b557ffa4..c5d8e854 100644 --- a/poetry.lock +++ b/poetry.lock @@ -260,7 +260,7 @@ python-versions = ">=3.5.3" [[package]] name = "discord.py" -version = "2.0.0a3619+g3ffe1348" +version = "2.0.0a3617+g33470ff1" description = "A Python wrapper for the Discord API" category = "main" optional = false @@ -278,8 +278,8 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "git" url = "https://github.com/iDevision/enhanced-discord.py" -reference = "3ffe1348956ebc1e2512439b532fdb6516c267c6" -resolved_reference = "3ffe1348956ebc1e2512439b532fdb6516c267c6" +reference = "33470ff1960285b5e5d5e0b277ee76a1e71dc1e2" +resolved_reference = "33470ff1960285b5e5d5e0b277ee76a1e71dc1e2" [[package]] name = "distlib" @@ -772,7 +772,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "353c0ab070d2656e0ece5311983ce57a5765972521eb44a48094bcc2e96b8ce9" +content-hash = "c5d20bc1b62e18c166dcf40e3cb9a44813e27cff2adfc20722378ed86df9a1f8" [metadata.files] aiohttp = [ diff --git a/pyproject.toml b/pyproject.toml index 1fe29ad9..99c75c56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" aiohttp = "3.7.3" python = "^3.8" beautifulsoup4 = "^4.9.3" -"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", rev = "3ffe1348956ebc1e2512439b532fdb6516c267c6"} +"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", rev = "33470ff1960285b5e5d5e0b277ee76a1e71dc1e2"} discord-ext-menus = "^1.1" fuzzywuzzy = "0.18.0" humanize = "3.7.0" From df9cb502e542c90e73d718f2669af98aedcd4bb4 Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 07:56:26 +0700 Subject: [PATCH 42/71] + Fixed helper output only returning "disable" --- exts/meta/meta.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/exts/meta/meta.py b/exts/meta/meta.py index a5aad69b..c6d2f4bd 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -733,7 +733,13 @@ async def remove(self, ctx, name: CMDName): @staticmethod async def disableEnableHelper( - ctx, name, /, *, isMod: bool, immuneRoot: Iterable[str] = ("help", "command") + ctx, + name, + /, + *, + action: str, + isMod: bool, + immuneRoot: Iterable[str] = ("help", "command"), ) -> Tuple[Any, str]: """Helper for `command disable` and `command enable` @@ -745,7 +751,7 @@ async def disableEnableHelper( """ foundList = [] # contains built-in and custom command, also category - # only mods allowed to disable built-in commands + # only mods allowed to disable/enable built-in commands if isMod: # find built-in command cmd = ctx.bot.get_command(str(name)) @@ -778,7 +784,7 @@ async def disableEnableHelper( if len(foundList) <= 0: # Nothing found, abort return await ctx.error( - f"No command/category called '{name}' can be disabled" + f"No command/category called '{name}' can be {action}d" ) chosen = None @@ -789,7 +795,7 @@ async def disableEnableHelper( else: # give user choices, since there's more than 1 type is found choices = ZChoices(ctx, foundList) - msg = await ctx.send("Which one do you want to disable?", view=choices) + msg = await ctx.send(f"Which one do you want to {action}?", view=choices) await choices.wait() await msg.delete() chosen = choices.value @@ -834,7 +840,7 @@ async def disable(self, ctx, *, name): try: chosen = await self.disableEnableHelper( - ctx, name, isMod=isMod, immuneRoot=immuneRoot + ctx, name, action="disable", isMod=isMod, immuneRoot=immuneRoot ) except RuntimeError: return @@ -947,7 +953,7 @@ async def enable(self, ctx, *, arguments: CmdManagerFlags): try: chosen = await self.disableEnableHelper( - ctx, name, isMod=isMod, immuneRoot=[] + ctx, name, action="enable", isMod=isMod, immuneRoot=[] ) except RuntimeError: return From a9f7d86d3162b8b1c854a04b4b59c34f0d26b0d9 Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 08:01:01 +0700 Subject: [PATCH 43/71] + Fix some issue with helper, and removed staticmethod (no reason for it to be static) --- exts/meta/meta.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/exts/meta/meta.py b/exts/meta/meta.py index c6d2f4bd..d6443620 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -8,7 +8,7 @@ import difflib import re import time -from typing import TYPE_CHECKING, Any, Iterable, Tuple +from typing import TYPE_CHECKING, Any, Iterable, Optional, Tuple import discord import humanize @@ -731,8 +731,8 @@ async def remove(self, ctx, name: CMDName): ) ) - @staticmethod async def disableEnableHelper( + self, ctx, name, /, @@ -740,7 +740,7 @@ async def disableEnableHelper( action: str, isMod: bool, immuneRoot: Iterable[str] = ("help", "command"), - ) -> Tuple[Any, str]: + ) -> Optional[Tuple[Any, str]]: """Helper for `command disable` and `command enable` - Find built-in command, custom command, and category @@ -802,7 +802,7 @@ async def disableEnableHelper( if not chosen: # nothing is chosen, abort (only happened when choices triggered) - raise RuntimeError("Nothing is chosen") + return return chosen @@ -838,11 +838,11 @@ async def disable(self, ctx, *, name): alreadyMsg = "`{}` already disabled!" immuneRoot = ("help", "command") - try: - chosen = await self.disableEnableHelper( - ctx, name, action="disable", isMod=isMod, immuneRoot=immuneRoot - ) - except RuntimeError: + chosen = await self.disableEnableHelper( + ctx, name, action="disable", isMod=isMod, immuneRoot=immuneRoot + ) + + if not chosen or isinstance(chosen, discord.Message): return mode = chosen[1] @@ -951,11 +951,11 @@ async def enable(self, ctx, *, arguments: CmdManagerFlags): successMsg = "`{}` has been enabled" alreadyMsg = "`{}` already enabled!" - try: - chosen = await self.disableEnableHelper( - ctx, name, action="enable", isMod=isMod, immuneRoot=[] - ) - except RuntimeError: + chosen = await self.disableEnableHelper( + ctx, name, action="enable", isMod=isMod, immuneRoot=[] + ) + + if not chosen or isinstance(chosen, discord.Message): return mode = chosen[1] From 7e26b6299f85cea1d66d419457e811b9e2e4488b Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 08:07:22 +0700 Subject: [PATCH 44/71] + TODO --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60c30e38..e131fc13 100644 --- a/README.md +++ b/README.md @@ -91,13 +91,13 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) - Tags (stripped version of custom command) - Unify categories/exts emoji - Channel manager commands -- Reaction Role +- Reaction Role (With buttons... button role?) - Starboard ### Pending Plan - i18n using gettext (Learning how gettext works) -- Slash command (Waiting for ed.py's implementation) +- Slash command (Waiting for implementation) - Properly support different SQL scheme (designing best way to do this) ### Scrapped Plan From 02c65b50c7f5ce012ab9a547a04d4f6b0b74bc01 Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 08:17:04 +0700 Subject: [PATCH 45/71] + [ 2 files changed ] - Fix error in DM --- exts/anilist/_pages.py | 4 ++-- utils/other.py | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/exts/anilist/_pages.py b/exts/anilist/_pages.py index 2d4003d6..c79fedc6 100644 --- a/exts/anilist/_pages.py +++ b/exts/anilist/_pages.py @@ -5,7 +5,7 @@ from core.embed import ZEmbed from core.enums import Emojis -from utils.other import Markdownify +from utils.other import Markdownify, isNsfw STREAM_SITES = ( @@ -70,7 +70,7 @@ async def format_page(self, menu: menus.MenuPages, data): icon_url="https://gblobscdn.gitbook.com/spaces%2F-LHizcWWtVphqU90YAXO%2Favatar.png", ) - chNsfw = ctx.channel.is_nsfw() + chNsfw = isNsfw(ctx.channel) cover = data["coverImage"]["large"] banner = data["bannerImage"] if not isAdult or (isAdult and chNsfw): diff --git a/utils/other.py b/utils/other.py index 4060778e..4dd0562a 100644 --- a/utils/other.py +++ b/utils/other.py @@ -1,4 +1,4 @@ -from __future__ import division +from __future__ import annotations, division import argparse import datetime as dt @@ -484,6 +484,13 @@ async def authorOrReferenced(ctx): return ctx.author +def isNsfw(channel) -> bool: + try: + return channel.is_nsfw() + except AttributeError: # Mark DMs as NSFW channel + return isinstance(channel, discord.DMChannel) + + if __name__ == "__main__": # For testing print(encodeMorse("test 123")) From 2c1cca3aa1ca68b6325e02c8eb3b4cca09eedde5 Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 08:21:48 +0700 Subject: [PATCH 46/71] + [ 2 files changed ] - Fix some issue with Anilist commands --- CHANGELOG.md | 2 ++ exts/anilist/anilist.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc016db0..3ffb3886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - [**Changed**] `>command disable` and `>command enable` no longer uses flag, replaced with choice buttons when there's more than 1 type is found with identical name +- [**Fixed**] Anilist commands now works in DMs +- [**Fixed**] `>manga search` actually search for manga not anime # v3.2 diff --git a/exts/anilist/anilist.py b/exts/anilist/anilist.py index 8b26c7f4..35ae5e11 100644 --- a/exts/anilist/anilist.py +++ b/exts/anilist/anilist.py @@ -55,7 +55,7 @@ async def anilistSearch( "name": name, "page": 1, "perPage": 25, - "type": "ANIME", + "type": type, } if parsed.format_: kwargs["format"] = parsed.format_.strip().upper().replace(" ", "_") From dc422fb78b3882e96ce789fb24934a68f4be6d5b Mon Sep 17 00:00:00 2001 From: ziro Date: Sat, 4 Sep 2021 08:37:59 +0700 Subject: [PATCH 47/71] + Use utils isNsfw --- exts/nsfw/nsfw.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/exts/nsfw/nsfw.py b/exts/nsfw/nsfw.py index a7cf99eb..5ff64237 100644 --- a/exts/nsfw/nsfw.py +++ b/exts/nsfw/nsfw.py @@ -11,6 +11,7 @@ from core.embed import ZEmbed from core.menus import ZMenuView from core.mixin import CogMixin +from utils.other import isNsfw NEKO_API = "https://api.nekos.dev/api/v3" @@ -88,9 +89,7 @@ class NSFW(commands.Cog, CogMixin): async def cog_check(self, ctx): """Only for NSFW channels""" - if not ctx.guild: - return True - return ctx.channel.is_nsfw() + return isNsfw(ctx.channel) @commands.command() async def pussy(self, ctx): From 107c4c48dc2b096141c3708bdfd2cc46fb1718a6 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 11:55:20 +0700 Subject: [PATCH 48/71] + [ 2 files changed ] - Adjust help command UX, and improve consistency * User now can choose between command and category when there's conflicted name * Replace ctx.send with ctx.try_reply to stay consistant with other response --- exts/meta/_help.py | 23 ++++++++++++++++++++--- exts/meta/meta.py | 6 ++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index 047d0e94..fa499fb1 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -8,7 +8,7 @@ from core.embed import ZEmbed from core.errors import CCommandNotFound -from core.menus import ZMenuPagesView +from core.menus import ZChoices, ZMenuPagesView, choice from utils import infoQuote from utils.format import formatDiscordDT @@ -211,8 +211,6 @@ async def command_callback(self, ctx, *, arguments=None): return await self.send_custom_help() cog = bot.get_cog(command) - if cog: - return await self.send_cog_help(cog, filters) maybeCoro = discord.utils.maybe_coroutine @@ -242,4 +240,23 @@ async def command_callback(self, ctx, *, arguments=None): ) return await self.send_error_message(string) + choiceList = [choice(f"{command} (Command)", foundList)] + + selected = None + if cog: + choiceList.append(choice(f"{command} (Category)", cog)) + # both cog and command is found, lets give user a choice + choices = ZChoices(ctx, choiceList) + msg = await ctx.try_reply("Which one?", view=choices) + + await choices.wait() + await msg.delete() + selected = choices.value + + if not selected: + return + + if not isinstance(selected, list): + return await self.send_cog_help(cog, filters) + await self.send_command_help(foundList) diff --git a/exts/meta/meta.py b/exts/meta/meta.py index d6443620..403a242f 100644 --- a/exts/meta/meta.py +++ b/exts/meta/meta.py @@ -795,7 +795,9 @@ async def disableEnableHelper( else: # give user choices, since there's more than 1 type is found choices = ZChoices(ctx, foundList) - msg = await ctx.send(f"Which one do you want to {action}?", view=choices) + msg = await ctx.try_reply( + f"Which one do you want to {action}?", view=choices + ) await choices.wait() await msg.delete() chosen = choices.value @@ -1090,7 +1092,7 @@ async def _commands(self, ctx): @commands.command(brief="Get link to my source code") @commands.cooldown(1, 5, commands.BucketType.user) async def source(self, ctx): - await ctx.send("My source code: {}".format(self.bot.links["Source Code"])) + await ctx.try_reply("My source code: {}".format(self.bot.links["Source Code"])) @commands.command(aliases=("botinfo", "bi"), brief="Information about me") @commands.cooldown(1, 5, commands.BucketType.user) From f7da6a98b6f1acac93277fed1e4bbf98f2ed0f9c Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 11:58:09 +0700 Subject: [PATCH 49/71] + CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ffb3886..95636b56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ identical name - [**Fixed**] Anilist commands now works in DMs - [**Fixed**] `>manga search` actually search for manga not anime +- [**Improved**] User now given choices between command and category when their + names are conflicted # v3.2 From faad809ec0bd25a28e163231e38a0df91daf6592 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 11:59:54 +0700 Subject: [PATCH 50/71] + Fixed an issue with previous commit --- exts/meta/_help.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index fa499fb1..d4d96b21 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -242,7 +242,8 @@ async def command_callback(self, ctx, *, arguments=None): choiceList = [choice(f"{command} (Command)", foundList)] - selected = None + # default to foundList + selected = foundList if cog: choiceList.append(choice(f"{command} (Category)", cog)) # both cog and command is found, lets give user a choice From ed4eb9a2430d90eb948266d14b2b3a9a330af186 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 12:11:08 +0700 Subject: [PATCH 51/71] + [ 2 files changed ] - Replace bot.master -> bot.owner_ids --- CHANGELOG.md | 2 +- core/checks.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95636b56..6759bbda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ manual moderation action) - [**Changed**] Rename `Bot.master` -> `Bot.owner_ids` - [**Fixed**] Fix Admin commands' checks not working properly -- [**Improved**] Manually input Intents, this should slightly improve the +- [**Improved**] Manually set Intents, this should slightly improve the performance - [**Improved**] Merged `on_member_ban` with `on_member_remove`, so it doesn't request audit logs twice diff --git a/core/checks.py b/core/checks.py index 1cf73014..c0e8c32f 100644 --- a/core/checks.py +++ b/core/checks.py @@ -8,7 +8,7 @@ def has_guild_permissions(**perms): async def predicate(ctx): orig = commands.has_guild_permissions(**perms).predicate try: - isMaster = ctx.author.id in ctx.bot.master + isMaster = ctx.author.id in ctx.bot.owner_ids except AttributeError: isMaster = False return isMaster or await orig(ctx) @@ -21,7 +21,7 @@ async def predicate(ctx): def is_botmaster(): def predicate(ctx): - return ctx.author.id in ctx.bot.master + return ctx.author.id in ctx.bot.owner_ids return commands.check(predicate) From 103175a2b62cda779fa7c1886d497de7ed7b9c12 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 12:25:48 +0700 Subject: [PATCH 52/71] + Fixed more issue with help's choices --- exts/meta/_help.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index d4d96b21..35fd3f21 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -234,25 +234,28 @@ async def command_callback(self, ctx, *, arguments=None): cmd = found foundList.append(cmd) - if not foundList: - string = await maybeCoro( - self.command_not_found, self.remove_mentions(command) - ) - return await self.send_error_message(string) - choiceList = [choice(f"{command} (Command)", foundList)] # default to foundList selected = foundList if cog: - choiceList.append(choice(f"{command} (Category)", cog)) - # both cog and command is found, lets give user a choice - choices = ZChoices(ctx, choiceList) - msg = await ctx.try_reply("Which one?", view=choices) - - await choices.wait() - await msg.delete() - selected = choices.value + if foundList: + choiceList.append(choice(f"{command} (Category)", cog)) + # both cog and command is found, lets give user a choice + choices = ZChoices(ctx, choiceList) + msg = await ctx.try_reply("Which one?", view=choices) + + await choices.wait() + await msg.delete() + selected = choices.value + else: + selected = cog + + elif not foundList: + string = await maybeCoro( + self.command_not_found, self.remove_mentions(command) + ) + return await self.send_error_message(string) if not selected: return From 115c72282ebb52433d718d9923d0a34087a7f4bd Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 15:36:24 +0700 Subject: [PATCH 53/71] + Typehint --- exts/meta/_help.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index 35fd3f21..17c95572 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -26,7 +26,7 @@ class CustomHelp(commands.HelpCommand): if TYPE_CHECKING: context: Context # stop pyright from yelling at me - async def send_bot_help(self, mapping): + async def send_bot_help(self, mapping) -> discord.Message: ctx = self.context e = ZEmbed( @@ -80,7 +80,7 @@ async def send_bot_help(self, mapping): return await ctx.try_reply(embed=e) - async def filter_commands(self, _commands): + async def filter_commands(self, _commands) -> list: async def predicate(cmd): try: return await cmd.can_run(self.context) @@ -97,7 +97,7 @@ async def predicate(cmd): return ret - async def send_cog_help(self, cog, filters): + async def send_cog_help(self, cog, filters) -> None: ctx = self.context filtered = [] @@ -121,15 +121,15 @@ async def send_cog_help(self, cog, filters): view = ZMenuPagesView(ctx, source=HelpCogPage(cog, filtered)) await view.start() - async def command_not_found(self, string): + async def command_not_found(self, string) -> str: return "No command/category called `{}` found.".format(string) - async def send_error_message(self, error): + async def send_error_message(self, error) -> None: if isinstance(error, CustomCommand): return await self.context.error(error) - async def send_command_help(self, commands_): + async def send_command_help(self, commands_) -> None: ctx = self.context filtered = [] @@ -180,7 +180,7 @@ async def prepare_help_command(self, ctx, arguments) -> tuple: return command, unique - async def send_custom_help(self): + async def send_custom_help(self) -> None: # TODO: Improve the output ctx = self.context From c7fbcd4e1a3713dee18afd503e98d3bf7a631960 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 16:49:58 +0700 Subject: [PATCH 54/71] + Added compact status if user is on mobile and simplify page display --- core/menus.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/menus.py b/core/menus.py index 7f7fe21b..b103d963 100644 --- a/core/menus.py +++ b/core/menus.py @@ -86,10 +86,15 @@ def __init__( timeout: float = 180.0, ownerOnly: bool = True, ) -> None: - super().__init__(ctx.author, timeout=timeout) + owner: Union[discord.User, discord.Member] = ctx.author + super().__init__(owner, timeout=timeout) self.context = ctx self._message: Optional[discord.Message] = None self.currentPage: int = 0 + if isinstance(owner, discord.Member): + self.compact = owner.is_on_mobile() + else: + self.compact = False def shouldAddButtons(self): return True @@ -131,6 +136,8 @@ def __init__( ) -> None: self._source: Union[menus.PageSource, Pages] = source super().__init__(ctx, **kwargs) + self.pageFmt = ("Page " if not self.compact else "") + "{current}/{last}" + self._pageInfo.label = self.pageFmt.format(current="N/A", last="N/A") def shouldAddButtons(self): source = self._source @@ -168,10 +175,12 @@ async def sendInitialMessage(self, ctx): kwargs = await self.getPage(0) if self.shouldAddButtons(): kwargs["view"] = self - self._pageInfo.label = f"Page 1/{self.getMaxPages()}" + self._pageInfo.label = self.pageFmt.format( + current="1", last=self.getMaxPages() + ) if self.getMaxPages() == 2: - self.remove_item(self._first) - self.remove_item(self._last) + self.remove_item(self._first) # type: ignore + self.remove_item(self._last) # type: ignore return await ctx.try_reply(**kwargs) async def sendPage( @@ -182,7 +191,9 @@ async def sendPage( self.currentPage = pageNumber kwargs = await self.getPage(pageNumber) - self._pageInfo.label = f"Page {pageNumber+1}/{self.getMaxPages()}" + self._pageInfo.label = self.pageFmt.format( + current=pageNumber + 1, last=self.getMaxPages() + ) await interaction.message.edit(view=self, **kwargs) # type: ignore async def sendCheckedPage(self, interaction: discord.Interaction, pageNumber): From b05a308dc9573a861c812948aefec9a28147d173 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 16:57:44 +0700 Subject: [PATCH 55/71] + [ 2 files changed ] - Format custom command list using ZMenuView --- exts/meta/_help.py | 18 ++++++++---------- exts/meta/_pages.py | 24 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index 17c95572..88888790 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -15,7 +15,7 @@ from ._custom_command import getCustomCommand, getCustomCommands from ._flags import HelpFlags from ._objects import CustomCommand, Group -from ._pages import HelpCogPage, HelpCommandPage +from ._pages import CustomCommandsListSource, HelpCogPage, HelpCommandPage if TYPE_CHECKING: @@ -189,15 +189,13 @@ async def send_custom_help(self) -> None: cmds = await getCustomCommands(ctx.db, guild.id) cmds = sorted(cmds, key=lambda cmd: cmd.uses, reverse=True) - e = ZEmbed.default(ctx, title="Custom Commands", description="") - if cmds: - for k, v in enumerate(cmds): - e.description += "**`{}`** {} [`{}` uses]\n".format( - k + 1, v.name, v.uses - ) - else: - e.description = "This server doesn't have custom command" - await ctx.try_reply(embed=e) + view = ZMenuPagesView( + ctx, + source=CustomCommandsListSource( + [(count, command) for count, command in enumerate(cmds)] + ), + ) + await view.start() async def command_callback(self, ctx, *, arguments=None): command, filters = await self.prepare_help_command(ctx, arguments) diff --git a/exts/meta/_pages.py b/exts/meta/_pages.py index fc7764b9..78e9aa85 100644 --- a/exts/meta/_pages.py +++ b/exts/meta/_pages.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Any, List, Optional, Tuple from discord.ext import commands, menus @@ -179,3 +179,25 @@ async def format_page(self, menu: ZMenuView, command): value="\n".join([f"> `{formatCmd(prefix, cmd)}`" for cmd in subcmds]), ) return e + + +class CustomCommandsListSource(menus.ListPageSource): + def __init__(self, list_: List[Tuple[int, CustomCommand]]) -> None: + super().__init__(list_, per_page=6) + + def format_page( + self, menu: ZMenuView, list_: List[Tuple[int, CustomCommand]] + ) -> ZEmbed: + ctx = menu.context + e = ZEmbed( + title=f"Custom Commands in {ctx.guild}", + fields=[ + ( + f"**`{count+1}`** {command} (**`{command.uses}`** uses)", + command.description or "No description", + ) + for count, command in list_ + ], + field_inline=False, + ) + return e From ea7e76149350827274c5655f3579c0d78baca19e Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 16:59:57 +0700 Subject: [PATCH 56/71] + CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6759bbda..efea15b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ - [**Fixed**] `>manga search` actually search for manga not anime - [**Improved**] User now given choices between command and category when their names are conflicted +- [**Improved**] Custom command list now paginated +- [**Improved**] Added "compact mode" to paginator # v3.2 From ec915e80a4a14f23a6d47eb7112b79c19b5431f6 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 17:16:24 +0700 Subject: [PATCH 57/71] + [ 3 files changed ] - Properly handle NSFW check --- core/errors.py | 5 +++++ exts/events/events.py | 1 + exts/nsfw/nsfw.py | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/core/errors.py b/core/errors.py index 4f709344..4694f875 100644 --- a/core/errors.py +++ b/core/errors.py @@ -80,3 +80,8 @@ def __init__(self, missing_permissions=None, *args): ) super().__init__(message, *args) + + +class NotNSFWChannel(CommandError): + def __init__(self): + super().__init__("You're only allowed to use this command in a NSFW channels!") diff --git a/exts/events/events.py b/exts/events/events.py index 2ea5bf68..f111514b 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -240,6 +240,7 @@ async def onCommandError(self, ctx, error) -> Optional[discord.Message]: errors.MissingMuteRole, errors.CCommandNoPerm, errors.CCommandDisabled, + errors.NotNSFWChannel, ) if isinstance(error, commands.CommandNotFound) or isinstance( diff --git a/exts/nsfw/nsfw.py b/exts/nsfw/nsfw.py index 5ff64237..a88df35e 100644 --- a/exts/nsfw/nsfw.py +++ b/exts/nsfw/nsfw.py @@ -9,6 +9,7 @@ from discord.ext import commands, menus from core.embed import ZEmbed +from core.errors import NotNSFWChannel from core.menus import ZMenuView from core.mixin import CogMixin from utils.other import isNsfw @@ -89,7 +90,8 @@ class NSFW(commands.Cog, CogMixin): async def cog_check(self, ctx): """Only for NSFW channels""" - return isNsfw(ctx.channel) + if not isNsfw(ctx.channel): + raise NotNSFWChannel @commands.command() async def pussy(self, ctx): From e60398dd86777342ba220c937681958ceb7f7100 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 17:18:25 +0700 Subject: [PATCH 58/71] + CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efea15b2..6a770d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,9 @@ - [**Improved**] User now given choices between command and category when their names are conflicted - [**Improved**] Custom command list now paginated -- [**Improved**] Added "compact mode" to paginator +- [**New**] Added "compact mode" to paginator +- [**Improved**] Failed NSFW check will now properly "yell" at the executor, + instead of yelling "Check failed!" # v3.2 From 032f68f97615f78fa4fb8183cc46d7006cf79b7d Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 17:40:28 +0700 Subject: [PATCH 59/71] + [ 3 files changed ] - Fully implemented caseNum into modlog event --- CHANGELOG.md | 3 +-- exts/events/events.py | 20 ++++++++++++-------- exts/mod/mod.py | 24 +++++++++++++----------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a770d69..72334625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,7 @@ ## 3.3.0 - [**New**] Added realurl (get real url of a shorten url) -- [**Improved**] Added case number to modlog message (for now only work with - manual moderation action) +- [**Improved**] Added case number to modlog message - [**Changed**] Rename `Bot.master` -> `Bot.owner_ids` - [**Fixed**] Fix Admin commands' checks not working properly - [**Improved**] Manually set Intents, this should slightly improve the diff --git a/exts/events/events.py b/exts/events/events.py index f111514b..0e73bba4 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -30,7 +30,9 @@ from core.bot import ziBot -REASON_REGEX = re.compile(r"^\[\S+\#\d+ \(ID: (\d+)\)\]: (.*)") +REASON_REGEX = re.compile( + r"^\[\S+\#\d+ \(ID: (?P[0-9]+)\) #(?P[0-9]+)\]: (?P.*)" +) # TODO: Move this to exts.utils.other @@ -56,9 +58,10 @@ async def doModlog( # Get the real moderator match = REASON_REGEX.match(reason) if match: - modId = int(match.group(1)) + modId = int(match.group("userId")) moderator = bot.get_user(modId) or await bot.fetch_user(modId) - reason = match.group(2) + reason = match.group("reason") + caseNum = int(match.group("caseNum")) else: # Since moderation is done manually, caselog will be done here @@ -75,17 +78,18 @@ async def doModlog( # No channel found, don't do modlog return + if not caseNum: + # placeholder for failed case parsing attempt + caseNum = -1 + e = ZEmbed.minimal( - title="Modlog - {}".format(type.title()), + title="{} | #{}".format(type.title(), caseNum), description=( f"**User**: {member} ({member.mention})\n" + (f"**Reason**: {reason}\n" if reason else "") + f"**Moderator**: {moderator.mention}" ), ) - # TODO: Make caseNum appears when moderation cmd is used - if caseNum is not None: - e.description += f"\n**Case**: #{caseNum}" e.set_footer(text=f"ID: {member.id}") await channel.send(embed=e) # type: ignore @@ -533,7 +537,7 @@ async def onMemberMuted(self, member: discord.Member, mutedRole: discord.Object) return with suppress(discord.Forbidden): - await asyncio.sleep(5) + await asyncio.sleep(2) entry = ( await guild.audit_logs( limit=1, action=discord.AuditLogAction.member_role_update diff --git a/exts/mod/mod.py b/exts/mod/mod.py index 4632891e..c4f83213 100644 --- a/exts/mod/mod.py +++ b/exts/mod/mod.py @@ -81,17 +81,6 @@ async def doModeration( # Failed to send DM desc += "\n**DM**: Failed to notify user." - # Do the action - try: - await (actions[action])( - ctx, - user, - reason="[{} (ID: {})]: {}".format(ctx.author, ctx.author.id, reason), - **kwargs, - ) - except discord.Forbidden: - return await ctx.try_reply("I don't have permission to ban a user!") - caseNum = await doCaselog( self.bot, guildId=ctx.guild.id, @@ -103,6 +92,19 @@ async def doModeration( if caseNum: desc += "\n**Case**: #{}".format(caseNum) + # Do the action + try: + await (actions[action])( + ctx, + user, + reason="[{} (ID: {}) #{}]: {}".format( + ctx.author, ctx.author.id, caseNum, reason + ), + **kwargs, + ) + except discord.Forbidden: + return await ctx.try_reply("I don't have permission to ban a user!") + if time is not None: # Temporary ban await timer.createTimer( From d21365af10a0b809caf40375b141fa926503c067 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 17:42:04 +0700 Subject: [PATCH 60/71] + TODO --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e131fc13..b7d2a87e 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) - Channel manager commands - Reaction Role (With buttons... button role?) - Starboard +- Command to retrieve case log ### Pending Plan From f5fd3c8b23134e84fe01c39b4e4c871ff203030e Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 19:03:54 +0700 Subject: [PATCH 61/71] + No longer needed --- exts/events/events.py | 1 - 1 file changed, 1 deletion(-) diff --git a/exts/events/events.py b/exts/events/events.py index 0e73bba4..c441a541 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -35,7 +35,6 @@ ) -# TODO: Move this to exts.utils.other async def doModlog( bot: ziBot, guild: discord.Guild, From 6d5313aaa3913eb08f59250a1326b9f1e7355528 Mon Sep 17 00:00:00 2001 From: ziro Date: Sun, 5 Sep 2021 20:36:49 +0700 Subject: [PATCH 62/71] + [ 2 files changed ] - Updated discord.py, someone finally fixed it --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index c5d8e854..e97a9db6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -260,7 +260,7 @@ python-versions = ">=3.5.3" [[package]] name = "discord.py" -version = "2.0.0a3617+g33470ff1" +version = "2.0.0a3621+g65640ddf" description = "A Python wrapper for the Discord API" category = "main" optional = false @@ -278,8 +278,8 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "git" url = "https://github.com/iDevision/enhanced-discord.py" -reference = "33470ff1960285b5e5d5e0b277ee76a1e71dc1e2" -resolved_reference = "33470ff1960285b5e5d5e0b277ee76a1e71dc1e2" +reference = "65640ddfc78d2df0c1f901817538cb6de9cce025" +resolved_reference = "65640ddfc78d2df0c1f901817538cb6de9cce025" [[package]] name = "distlib" @@ -772,7 +772,7 @@ voice = ["PyNaCl"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "c5d20bc1b62e18c166dcf40e3cb9a44813e27cff2adfc20722378ed86df9a1f8" +content-hash = "3901d43437f45328397644da164dc539b644e7dff152fd6d058945d404dbedf6" [metadata.files] aiohttp = [ diff --git a/pyproject.toml b/pyproject.toml index 99c75c56..537252a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" aiohttp = "3.7.3" python = "^3.8" beautifulsoup4 = "^4.9.3" -"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", rev = "33470ff1960285b5e5d5e0b277ee76a1e71dc1e2"} +"discord.py" = {git = "https://github.com/iDevision/enhanced-discord.py", rev = "65640ddfc78d2df0c1f901817538cb6de9cce025"} discord-ext-menus = "^1.1" fuzzywuzzy = "0.18.0" humanize = "3.7.0" From ef8b6d9e1127f0b3d2c1e551ca509b55899b3b79 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 09:39:52 +0700 Subject: [PATCH 63/71] + Fix caselog type inconsistency --- exts/events/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exts/events/events.py b/exts/events/events.py index c441a541..147d582b 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -549,7 +549,7 @@ async def onMemberMuted(self, member: discord.Member, mutedRole: discord.Object) member.guild, entry.target, entry.user, - "muted", + "mute", entry.reason, ) From 44c18d28156440e12c98280b476c350f6abfb7a0 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 09:46:54 +0700 Subject: [PATCH 64/71] + CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72334625..46527743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ - [**New**] Added "compact mode" to paginator - [**Improved**] Failed NSFW check will now properly "yell" at the executor, instead of yelling "Check failed!" +- [**Fixed**] Fixed caselog type `mute` being inconsistent ( [**For + self-hoster**] sql query to fix your database: `UPDATE OR IGNORE caseLog SET + type='mute' WHERE type='muted'`) # v3.2 From a5f8ba2a7ac3acaa48015ba116ec6c686540d486 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 10:54:16 +0700 Subject: [PATCH 65/71] + [ 6 files changed ] - Added `caselogs`/`cases` command * Added createdAt column for cases command * Fix some issue with doCaselog --- CHANGELOG.md | 5 +++++ README.md | 1 - exts/mod/_pages.py | 33 +++++++++++++++++++++++++++++++++ exts/mod/mod.py | 24 ++++++++++++++++++++++++ utils/dbQuery.py | 1 + utils/other.py | 4 +++- 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 exts/mod/_pages.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 46527743..98c07143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,11 @@ - [**Fixed**] Fixed caselog type `mute` being inconsistent ( [**For self-hoster**] sql query to fix your database: `UPDATE OR IGNORE caseLog SET type='mute' WHERE type='muted'`) +- [**New**] Added createdAt column to caselog ( [**For self-hoster**]: sql + query to add this column without dropping the table `ALTER TABLE caseLog ADD + COLUMN createdAt INTEGER DEFAULT 0`) [**NOTE**]: Old cases' time will return + either "Unknown" or `1/1/1970` +- [**New**] Added `caselogs`/`cases` command to get moderator's cases # v3.2 diff --git a/README.md b/README.md index b7d2a87e..e131fc13 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,6 @@ Moved to [CHANGELOG.md](./CHANGELOG.md) - Channel manager commands - Reaction Role (With buttons... button role?) - Starboard -- Command to retrieve case log ### Pending Plan diff --git a/exts/mod/_pages.py b/exts/mod/_pages.py new file mode 100644 index 00000000..636a45f1 --- /dev/null +++ b/exts/mod/_pages.py @@ -0,0 +1,33 @@ +from discord.ext import menus + +from core.embed import ZEmbed +from core.menus import ZMenuView +from utils.format import formatDiscordDT + + +class CaseListSource(menus.ListPageSource): + def __init__(self, moderator, cases) -> None: + self.moderator = moderator + self.totalCases = len(cases) + super().__init__(cases, per_page=5) + + async def format_page(self, menu: ZMenuView, cases): + moderator = self.moderator + + e = ZEmbed(title=f"{moderator.display_name}'s cases") + e.set_author(name=moderator, icon_url=moderator.display_avatar.url) + + for case in cases: + timestamp = case[4] + formattedTime = "`Unknown`" + if timestamp: + formattedTime = formatDiscordDT(timestamp, "R") + + e.add_field( + name=f"#{case[0]}: **`{case[1]}`** [{formattedTime}]", + value=case[3], + inline=False, + ) + + e.set_footer(text=f"{self.totalCases} cases in total") + return e diff --git a/exts/mod/mod.py b/exts/mod/mod.py index c4f83213..5226165d 100644 --- a/exts/mod/mod.py +++ b/exts/mod/mod.py @@ -14,6 +14,7 @@ from core.converter import BannedMember, Hierarchy, MemberOrUser, TimeAndArgument from core.embed import ZEmbed from core.errors import MissingMuteRole +from core.menus import ZMenuPagesView from core.mixin import CogMixin from exts.admin.admin import Admin from exts.timer.timer import Timer, TimerData @@ -22,6 +23,7 @@ from utils.other import doCaselog, utcnow from ._flags import AnnouncementFlags +from ._pages import CaseListSource class Moderation(commands.Cog, CogMixin): @@ -693,3 +695,25 @@ async def clearchat(self, ctx, num): e = ZEmbed.default(ctx, title=resp) await msg.edit(embed=e) + + @commands.command(aliases=("cases",)) + @checks.mod_or_permissions(manage_messages=True) + async def caselogs(self, ctx, moderator: discord.Member = None): + moderator = moderator or ctx.author + modCases = await self.bot.db.fetch_all( + """ + SELECT caseId, type, targetId, reason, createdAt FROM caseLog + WHERE guildId=:guildId AND modId=:modId + """, + values={ + "guildId": ctx.guild.id, + "modId": moderator.id, + }, + ) + if not modCases: + return await ctx.error( + f"{moderator.display_name} doesn't have any cases", + title="No cases found", + ) + menu = ZMenuPagesView(ctx, source=CaseListSource(moderator, modCases)) + await menu.start() diff --git a/utils/dbQuery.py b/utils/dbQuery.py index b8eaf652..2e6dc9db 100644 --- a/utils/dbQuery.py +++ b/utils/dbQuery.py @@ -187,6 +187,7 @@ modId INTEGER, targetId INTEGER, reason STRING, + createdAt INTEGER DEFAULT 0, FOREIGN KEY ("guildId") REFERENCES guilds ("id") ON DELETE CASCADE ) """ diff --git a/utils/other.py b/utils/other.py index 4dd0562a..f2b38212 100644 --- a/utils/other.py +++ b/utils/other.py @@ -418,7 +418,8 @@ async def doCaselog( :type, :modId, :targetId, - :reason + :reason, + :createdAt ) """, values={ @@ -428,6 +429,7 @@ async def doCaselog( "modId": modId, "targetId": targetId, "reason": reason, + "createdAt": int(utcnow().timestamp()), }, ) return int(caseNum) From 4c2d2576367772f74a66354404af0d32f0d64f77 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 11:02:14 +0700 Subject: [PATCH 66/71] + CHANGELOG --- exts/meta/_help.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/exts/meta/_help.py b/exts/meta/_help.py index 88888790..dff4e931 100644 --- a/exts/meta/_help.py +++ b/exts/meta/_help.py @@ -69,10 +69,11 @@ async def send_bot_help(self, mapping) -> discord.Message: name="News | Updated at: {}".format(formatDiscordDT(1628576674, "F")), value=( "Changelogs:" - "\n- Updated `discord.py` to v2.0 (buttons!)" - "\n- Improved help command behaviour" - "\n- Added AniList category (Anime and Manga commands)" - "\n- Fixed some issues" + "\n- Fixed bugs and error" + "\n- Added choices for conflicted name (for `command disable/enable` and `help` command)" + "\n- `manga search` command now actually search for manga instead of anime" + "\n- Added `caselogs`/`cases` command to get moderator's cases (mods only)" + "\n- Added `realurl` command to get real url of a shorten url" "\n\n[Click here to see the full changelog!]" "(https://github.com/ZiRO-Bot/Z3R0/blob/overhaul/CHANGELOG.md)\n" ), From 2c67b59add36007c7e31aa65a5a5f0d3da2b90ef Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 11:27:07 +0700 Subject: [PATCH 67/71] + [ 2 files changed ] - Allow unmute to be tracked by modlog --- exts/events/events.py | 22 ++++++++++++++++++- exts/mod/mod.py | 51 +++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/exts/events/events.py b/exts/events/events.py index 147d582b..a86e215d 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -555,4 +555,24 @@ async def onMemberMuted(self, member: discord.Member, mutedRole: discord.Object) @commands.Cog.listener("on_member_unmuted") async def onMemberUnmuted(self, member: discord.Member, mutedRole: discord.Role): - return + if not (guild := member.guild): + # impossible to happened, but sure + return + + with suppress(discord.Forbidden): + await asyncio.sleep(2) + entry = ( + await guild.audit_logs( + limit=1, action=discord.AuditLogAction.member_role_update + ).flatten() + )[0] + + if entry.target == member and not entry.target._roles.has(mutedRole.id): + await doModlog( + self.bot, + member.guild, + entry.target, + entry.user, + "unmute", + entry.reason, + ) diff --git a/exts/mod/mod.py b/exts/mod/mod.py index 5226165d..72b277d1 100644 --- a/exts/mod/mod.py +++ b/exts/mod/mod.py @@ -41,12 +41,13 @@ async def doModeration( actions = { "ban": self.doBan, "mute": self.doMute, + "unmute": self.doUnmute, "kick": self.doKick, } defaultReason = "No reason." - timer: Timer = self.bot.get_cog("Timer") + timer: Optional[Timer] = self.bot.get_cog("Timer") # type: ignore if not timer: # Incase Timer cog not loaded yet. return await ctx.error( @@ -70,18 +71,24 @@ async def doModeration( desc += "\n**Duration**: {} ({})".format(delta, formatDateTime(time)) guildAndTime += " until " + formatDateTime(time) - DMMsg = { - "ban": "You have been banned from {}. Reason: {}", - "mute": "You have been muted from {}. Reason: {}", - "kick": "You have been kicked from {}. Reason: {}", - } + silent = kwargs.pop("silent", False) # Silent = don't DM - try: - await user.send(DMMsg[action].format(guildAndTime, reason)) - desc += "\n**DM**: User notified with a direct message." - except (AttributeError, discord.HTTPException): - # Failed to send DM - desc += "\n**DM**: Failed to notify user." + if not silent: + DMMsgs = { + "ban": "banned", + "mute": "muted", + "unmute": "unmuted", + } + DMMsg = DMMsgs.get(action, action + "ed") + + DMFmt = f"You have been {DMMsg}" + " from {}. reason: {}" + + try: + await user.send(DMFmt.format(guildAndTime, reason)) + desc += "\n**DM**: User notified with a direct message." + except (AttributeError, discord.HTTPException): + # Failed to send DM + desc += "\n**DM**: Failed to notify user." caseNum = await doCaselog( self.bot, @@ -120,13 +127,14 @@ async def doModeration( ) titles = { - "ban": "Banned {}", - "mute": "Muted {}", - "kick": "Kicked {}", + "ban": "Banned", + "mute": "Muted", + "unmute": "Unmuted", } + formattedTitle = f"{titles.get(action, action + 'ed')} {user}" e = ZEmbed.success( - title=titles[action].format(user), + title=formattedTitle, description=desc, ) await ctx.send(embed=e) @@ -340,17 +348,18 @@ async def unmute(self, ctx, member: MemberOrUser, *, reason: str = "No reason"): if not member._roles.has(mutedRoleId): return await ctx.error(f"{member.mention} is not muted!") - role = discord.Object(id=mutedRoleId) + await self.doModeration( + ctx, member, None, action="unmute", reason=reason, mutedRoleId=mutedRoleId + ) + async def doUnmute(self, _n, member: discord.Member, /, reason: str, **kwargs): + mutedRoleId = kwargs.get("mutedRoleId", 0) + role = discord.Object(id=mutedRoleId) try: await member.remove_roles(role, reason=reason) except (discord.HTTPException, AttributeError): # Failed to remove role, just remove it manually await self.manageMuted(member, False, role) - e = ZEmbed.success( - title="Unmuted {} for {}".format(member, reason), - ) - await ctx.try_reply(embed=e) @commands.Cog.listener("on_member_update") async def onMemberUpdate(self, before: discord.Member, after: discord.Member): From 5d2f99cac543915a6338e6d132328c3c78a01ae6 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 11:32:12 +0700 Subject: [PATCH 68/71] + Moved unban to doModeration --- exts/mod/mod.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/exts/mod/mod.py b/exts/mod/mod.py index 72b277d1..3ac973fa 100644 --- a/exts/mod/mod.py +++ b/exts/mod/mod.py @@ -40,6 +40,7 @@ async def doModeration( """Ban function, self-explanatory""" actions = { "ban": self.doBan, + "unban": self.doUnban, "mute": self.doMute, "unmute": self.doUnmute, "kick": self.doKick, @@ -76,6 +77,7 @@ async def doModeration( if not silent: DMMsgs = { "ban": "banned", + "unban": "unbanned", "mute": "muted", "unmute": "unmuted", } @@ -128,6 +130,7 @@ async def doModeration( titles = { "ban": "Banned", + "unban": "Unbanned", "mute": "Muted", "unmute": "Unmuted", } @@ -211,11 +214,7 @@ async def save( ) @checks.mod_or_permissions(ban_members=True) async def unban(self, ctx, member: BannedMember, *, reason: str = "No reason"): - await ctx.guild.unban(member.user, reason=reason) - e = ZEmbed.success( - title="Unbanned {} for {}".format(member.user, reason), - ) - await ctx.try_reply(embed=e) + await self.doModeration(ctx, member.user, None, "unban", reason=reason) async def doBan(self, ctx, user: discord.User, /, reason: str, **kwargs): saveMsg = kwargs.pop("saveMsg", False) @@ -226,6 +225,9 @@ async def doBan(self, ctx, user: discord.User, /, reason: str, **kwargs): delete_message_days=0 if saveMsg else 1, ) + async def doUnban(self, ctx, user: discord.User, /, reason: str, **kwargs): + await ctx.guild.unban(user, reason=reason) + @commands.Cog.listener("on_ban_timer_complete") async def onBanTimerComplete(self, timer: TimerData): """Automatically unban.""" From 91c05bfb8d4db91aecd53cb0abe2a8a808202d1a Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 11:50:22 +0700 Subject: [PATCH 69/71] + [ 3 files changed ] - Revert some changes to support unban modlog --- CHANGELOG.md | 4 --- core/bot.py | 12 +------ exts/events/events.py | 83 ++++++++++++++++++++++++++----------------- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98c07143..581bad86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,6 @@ - [**Improved**] Added case number to modlog message - [**Changed**] Rename `Bot.master` -> `Bot.owner_ids` - [**Fixed**] Fix Admin commands' checks not working properly -- [**Improved**] Manually set Intents, this should slightly improve the - performance -- [**Improved**] Merged `on_member_ban` with `on_member_remove`, so it doesn't - request audit logs twice - [**Improved**] Decrease modlog delay to 2 seconds delay - [**Improved**] Merged `>help filter: custom` with `>command list` - [**Changed**] `>command disable` and `>command enable` no longer uses flag, diff --git a/core/bot.py b/core/bot.py index 463190f5..8c2dcd52 100644 --- a/core/bot.py +++ b/core/bot.py @@ -76,17 +76,7 @@ class ziBot(commands.Bot): def __init__(self) -> None: # custom intents, required since dpy v1.5 - intents = discord.Intents( - # bans are handled with on_member_remove, - # so only members intent is needed - bans=False, - members=True, - guilds=True, - messages=True, - emojis=True, - presences=True, - reactions=True, - ) + intents = discord.Intents.all() super().__init__( command_prefix=_callablePrefix, diff --git a/exts/events/events.py b/exts/events/events.py index a86e215d..69d74ebd 100644 --- a/exts/events/events.py +++ b/exts/events/events.py @@ -168,18 +168,23 @@ async def onMemberJoin(self, member: discord.Member) -> None: # Something wrong happened return + async def getAuditLogs( + self, guild: discord.Guild, limit=1, delay=2, **kwargs + ) -> discord.AuditLogEntry: + # discord needs a few second to update Audit Logs + await asyncio.sleep(delay) + return (await guild.audit_logs(limit=limit, **kwargs).flatten())[0] + @commands.Cog.listener("on_member_remove") async def onMemberRemove(self, member: discord.Member) -> None: """Farewell message""" guild: discord.Guild = member.guild with suppress(discord.Forbidden): - # discord needs a few second to update Audit Logs - await asyncio.sleep(2) - - entry = (await guild.audit_logs(limit=1).flatten())[0] + entry = await self.getAuditLogs(guild) if entry.target == member: + # TODO: Filters bot's action if entry.action == discord.AuditLogAction.kick: self.bot.dispatch("member_kick", member, entry) @@ -190,6 +195,11 @@ async def onMemberRemove(self, member: discord.Member) -> None: self.bot.dispatch("member_ban", member, entry) return + if entry.action == discord.AuditLogAction.unban: + # Intents.bans are disabled to make this works + self.bot.dispatch("member_unban", member, entry) + return + # fallback to farewell message return await self.handleGreeting(member, "farewell") @@ -207,17 +217,30 @@ async def onMemberKick( ) @commands.Cog.listener("on_member_ban") - async def onMemberBan( - self, member: discord.Member, entry: discord.AuditLogEntry - ) -> None: - await doModlog( - self.bot, - member.guild, - entry.target, # type: ignore - entry.user, - "ban", - entry.reason, - ) + async def onMemberBan(self, guild: discord.Guild, user: discord.User) -> None: + entry = await self.getAuditLogs(guild) + if entry.target == user: + await doModlog( + self.bot, + guild, + entry.target, # type: ignore + entry.user, + "ban", + entry.reason, + ) + + @commands.Cog.listener("on_member_unban") + async def onMemberUnban(self, guild: discord.Guild, user: discord.User) -> None: + entry = await self.getAuditLogs(guild) + if entry.target == user: + await doModlog( + self.bot, + guild, + entry.target, # type: ignore + entry.user, + "unban", + entry.reason, + ) @commands.Cog.listener("on_command_error") async def onCommandError(self, ctx, error) -> Optional[discord.Message]: @@ -536,18 +559,15 @@ async def onMemberMuted(self, member: discord.Member, mutedRole: discord.Object) return with suppress(discord.Forbidden): - await asyncio.sleep(2) - entry = ( - await guild.audit_logs( - limit=1, action=discord.AuditLogAction.member_role_update - ).flatten() - )[0] - - if entry.target == member and entry.target._roles.has(mutedRole.id): + entry = await self.getAuditLogs( + guild, action=discord.AuditLogAction.member_role_update + ) + + if entry.target == member and entry.target._roles.has(mutedRole.id): # type: ignore await doModlog( self.bot, member.guild, - entry.target, + entry.target, # type: ignore entry.user, "mute", entry.reason, @@ -560,18 +580,15 @@ async def onMemberUnmuted(self, member: discord.Member, mutedRole: discord.Role) return with suppress(discord.Forbidden): - await asyncio.sleep(2) - entry = ( - await guild.audit_logs( - limit=1, action=discord.AuditLogAction.member_role_update - ).flatten() - )[0] - - if entry.target == member and not entry.target._roles.has(mutedRole.id): + entry = await self.getAuditLogs( + guild, action=discord.AuditLogAction.member_role_update + ) + + if entry.target == member and not entry.target._roles.has(mutedRole.id): # type: ignore await doModlog( self.bot, member.guild, - entry.target, + entry.target, # type: ignore entry.user, "unmute", entry.reason, From 8dbece8d836c7cc922e17b8163b112414400fc75 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 11:51:16 +0700 Subject: [PATCH 70/71] + CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 581bad86..0e25ae4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ COLUMN createdAt INTEGER DEFAULT 0`) [**NOTE**]: Old cases' time will return either "Unknown" or `1/1/1970` - [**New**] Added `caselogs`/`cases` command to get moderator's cases +- [**Improved**] Modlog now log unmute and unban # v3.2 From d3949ab9a2742eba9690e3d6e78804d8e5e35a19 Mon Sep 17 00:00:00 2001 From: ziro Date: Mon, 6 Sep 2021 11:54:25 +0700 Subject: [PATCH 71/71] + CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e25ae4a..35d19486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ either "Unknown" or `1/1/1970` - [**New**] Added `caselogs`/`cases` command to get moderator's cases - [**Improved**] Modlog now log unmute and unban +- [**Disabled**] Disable `google` command (blocking the whole bot) # v3.2