diff --git a/jarvis/__init__.py b/jarvis/__init__.py index 1c07887..5172272 100644 --- a/jarvis/__init__.py +++ b/jarvis/__init__.py @@ -81,8 +81,10 @@ async def run() -> None: ) # External modules - if jconfig.log_level == "DEBUG": + if jconfig.jurigged: logging.addLevelName(11, "\033[35mJURIG\033[0m ") + if jconfig.log_level == "INFO": + logger.setLevel(11) jurigged.watch(pattern="jarvis/*.py", logger=partial(jlogger, logger)) # Initialize bot diff --git a/jarvis/client/events/components.py b/jarvis/client/events/components.py index 707bc04..8b7fbb1 100644 --- a/jarvis/client/events/components.py +++ b/jarvis/client/events/components.py @@ -10,17 +10,17 @@ from jarvis.utils import build_embed class ComponentEventMixin: - async def _handle_modcase_button(self, event: ButtonPressed) -> None: - context = event.context + async def _handle_modcase_button(self, event: ButtonPressed) -> bool: + context = event.ctx if not context.custom_id.startswith("modcase|"): - return # Failsafe + return False # Failsafe if not context.deferred and not context.responded: await context.defer(ephemeral=True) if not context.author.has_permission(Permissions.MODERATE_MEMBERS): - return + return False user_key = f"msg|{context.message.id}" action_key = "" @@ -79,11 +79,13 @@ class ComponentEventMixin: await self.redis.delete(user_key) await self.redis.delete(action_key) - async def _handle_delete_button(self, event: ButtonPressed) -> None: - context = event.context + return True + + async def _handle_delete_button(self, event: ButtonPressed) -> bool: + context = event.ctx if not context.custom_id.startswith("delete|"): - return # Failsafe + return False # Failsafe if not context.deferred and not context.responded: await context.defer(ephemeral=True) @@ -96,19 +98,20 @@ class ComponentEventMixin: and not str(context.author.id) == uid ): await context.send("I'm afraid I can't let you do that", ephemeral=True) - return # User does not have perms to delete + return True # User does not have perms to delete if star := await Star.find_one(q(star=context.message.id, guild=context.guild.id)): await star.delete() await context.message.delete() await context.send("Message deleted", ephemeral=True) + return True - async def _handle_copy_button(self, event: ButtonPressed) -> None: - context = event.context + async def _handle_copy_button(self, event: ButtonPressed) -> bool: + context = event.ctx if not context.custom_id.startswith("copy|"): - return + return False if not context.deferred and not context.responded: await context.defer(ephemeral=True) @@ -130,10 +133,12 @@ class ComponentEventMixin: await context.send("Reminder copied!", ephemeral=True) - async def _handle_phishlist_button(self, event: ButtonPressed) -> None: - context = event.context + return True + + async def _handle_phishlist_button(self, event: ButtonPressed) -> bool: + context = event.ctx if not context.custom_id.startswith("pl|"): - return + return False if not context.deferred and not context.responded: await context.defer(ephemeral=True) @@ -143,7 +148,7 @@ class ComponentEventMixin: pl = await Phishlist.find_one(q(_id=id_)) if not pl: self.logger.warn(f"Phishlist {id_} does not exist!") - return + return False pl.valid = valid pl.confirmed = True @@ -159,11 +164,16 @@ class ComponentEventMixin: await context.message.edit(components=context.message.components, embeds=embed) await context.send("Confirmed! Thank you for confirming this URL.") + return True @listen() async def on_button(self, event: ButtonPressed) -> None: """Process button events.""" - await self._handle_modcase_button(event) - await self._handle_delete_button(event) - await self._handle_copy_button(event) - await self._handle_phishlist_button(event) + modcase = await self._handle_modcase_button(event) + delete = await self._handle_delete_button(event) + copy = await self._handle_copy_button(event) + phishlist = await self._handle_phishlist_button(event) + + if not any([modcase, delete, copy, phishlist]): + # self.logger.warn(f"Unhandled ButtonPressed event: {event.ctx.custom_id}") + pass diff --git a/jarvis/client/tasks.py b/jarvis/client/tasks.py index ff28c44..15cb5b7 100644 --- a/jarvis/client/tasks.py +++ b/jarvis/client/tasks.py @@ -30,4 +30,4 @@ class TaskMixin: if domain in self.phishing_domains: sub -= 1 self.phishing_domains.remove(domain) - self.logger.debug(f"{add} additions, {sub} removals") + self.logger.info(f"{add} additions, {sub} removals") diff --git a/jarvis/cogs/calc.py b/jarvis/cogs/calc.py index e853211..c47e504 100644 --- a/jarvis/cogs/calc.py +++ b/jarvis/cogs/calc.py @@ -33,6 +33,7 @@ CURRENCIES = ( "CNY", "CZK", "DKK", + "EUR", "GBP", "HKD", "HRK", @@ -167,6 +168,7 @@ class CalcCog(Extension): conv = value * rate fields = ( + EmbedField(name="Conversion Rate", value=f"1 {from_currency} ~= {rate:0.4f} {to_currency}"), EmbedField(name=from_currency, value=f"{value:0.2f}"), EmbedField(name=to_currency, value=f"{conv:0.2f}"), ) diff --git a/jarvis/cogs/reddit.py b/jarvis/cogs/reddit.py index 197426b..9439dc4 100644 --- a/jarvis/cogs/reddit.py +++ b/jarvis/cogs/reddit.py @@ -223,11 +223,11 @@ class RedditCog(Extension): try: context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.context.author.id, + check=lambda x: ctx.author.id == x.ctx.author.id, messages=message, timeout=60 * 5, ) - for to_delete in context.context.values: + for to_delete in context.ctx.values: follow = get(redditors, guild=ctx.guild.id, name=names[int(to_delete)]) try: await follow.delete() @@ -237,8 +237,8 @@ class RedditCog(Extension): for component in row.components: component.disabled = True - block = "\n".join(names[int(x)] for x in context.context.values) - await context.context.edit_origin( + block = "\n".join(names[int(x)] for x in context.ctx.values) + await context.ctx.edit_origin( content=f"Unfollowed the following:\n```\n{block}\n```", components=components ) except asyncio.TimeoutError: @@ -342,11 +342,11 @@ class RedditCog(Extension): try: context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.context.author.id, + check=lambda x: ctx.author.id == x.ctx.author.id, messages=message, timeout=60 * 5, ) - for to_delete in context.context.values: + for to_delete in context.ctx.values: follow = get(subreddits, guild=ctx.guild.id, display_name=names[int(to_delete)]) try: await follow.delete() @@ -356,8 +356,8 @@ class RedditCog(Extension): for component in row.components: component.disabled = True - block = "\n".join(names[int(x)] for x in context.context.values) - await context.context.edit_origin( + block = "\n".join(names[int(x)] for x in context.ctx.values) + await context.ctx.edit_origin( content=f"Unfollowed the following:\n```\n{block}\n```", components=components ) except asyncio.TimeoutError: diff --git a/jarvis/cogs/rolegiver.py b/jarvis/cogs/rolegiver.py index bb521cc..6df4fe0 100644 --- a/jarvis/cogs/rolegiver.py +++ b/jarvis/cogs/rolegiver.py @@ -241,13 +241,13 @@ class RolegiverCog(Extension): try: context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.context.author.id, + check=lambda x: ctx.author.id == x.ctx.author.id, messages=message, timeout=60 * 5, ) added_roles = [] - for role in context.context.values: + for role in context.ctx.values: role = await ctx.guild.fetch_role(int(role)) added_roles.append(role) await ctx.author.add_role(role, reason="Rolegiver") @@ -282,7 +282,7 @@ class RolegiverCog(Extension): for component in row.components: component.disabled = True - await context.context.edit_origin(embeds=embed, content="\u200b", components=components) + await context.ctx.edit_origin(embeds=embed, content="\u200b", components=components) except asyncio.TimeoutError: for row in components: for component in row.components: @@ -321,13 +321,13 @@ class RolegiverCog(Extension): try: context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.context.author.id, + check=lambda x: ctx.author.id == x.ctx.author.id, messages=message, timeout=60 * 5, ) removed_roles = [] - for to_remove in context.context.values: + for to_remove in context.ctx.values: role = get(user_roles, id=int(to_remove)) await ctx.author.remove_role(role, reason="Rolegiver") user_roles.remove(role) @@ -358,7 +358,7 @@ class RolegiverCog(Extension): for component in row.components: component.disabled = True - await context.context.edit_origin(embeds=embed, components=components, content="\u200b") + await context.ctx.edit_origin(embeds=embed, components=components, content="\u200b") except asyncio.TimeoutError: for row in components: diff --git a/jarvis/cogs/settings.py b/jarvis/cogs/settings.py index de12ff3..a4b3593 100644 --- a/jarvis/cogs/settings.py +++ b/jarvis/cogs/settings.py @@ -55,9 +55,7 @@ class SettingsCog(Extension): sub_cmd_name="modlog", sub_cmd_description="Set Moglod channel", ) - @slash_option( - name="channel", description="ModLog Channel", opt_type=OptionTypes.CHANNEL, required=True - ) + @slash_option(name="channel", description="ModLog Channel", opt_type=OptionTypes.CHANNEL, required=True) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _set_modlog(self, ctx: InteractionContext, channel: GuildText) -> None: if not isinstance(channel, GuildText): @@ -98,9 +96,7 @@ class SettingsCog(Extension): await ctx.send(f"Settings applied. New massmention limit is {amount}") @set_.subcommand(sub_cmd_name="verified", sub_cmd_description="Set verified role") - @slash_option( - name="role", description="Verified role", opt_type=OptionTypes.ROLE, required=True - ) + @slash_option(name="role", description="Verified role", opt_type=OptionTypes.ROLE, required=True) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _set_verified(self, ctx: InteractionContext, role: Role) -> None: if role.id == ctx.guild.id: @@ -117,9 +113,7 @@ class SettingsCog(Extension): await ctx.send(f"Settings applied. New verified role is `{role.name}`") @set_.subcommand(sub_cmd_name="unverified", sub_cmd_description="Set unverified role") - @slash_option( - name="role", description="Unverified role", opt_type=OptionTypes.ROLE, required=True - ) + @slash_option(name="role", description="Unverified role", opt_type=OptionTypes.ROLE, required=True) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _set_unverified(self, ctx: InteractionContext, role: Role) -> None: if role.id == ctx.guild.id: @@ -135,9 +129,7 @@ class SettingsCog(Extension): await self.update_settings("unverified", role.id, ctx.guild.id) await ctx.send(f"Settings applied. New unverified role is `{role.name}`") - @set_.subcommand( - sub_cmd_name="noinvite", sub_cmd_description="Set if invite deletion should happen" - ) + @set_.subcommand(sub_cmd_name="noinvite", sub_cmd_description="Set if invite deletion should happen") @slash_option(name="active", description="Active?", opt_type=OptionTypes.BOOLEAN, required=True) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _set_invitedel(self, ctx: InteractionContext, active: bool) -> None: @@ -153,12 +145,8 @@ class SettingsCog(Extension): await self.update_settings("notify", active, ctx.guild.id) await ctx.send(f"Settings applied. Notifications active: {active}") - @set_.subcommand( - sub_cmd_name="log_ignore", sub_cmd_description="Ignore a channel for ActivityLog" - ) - @slash_option( - name="channel", description="Channel to ignore", opt_type=OptionTypes.CHANNEL, required=True - ) + @set_.subcommand(sub_cmd_name="log_ignore", sub_cmd_description="Ignore a channel for ActivityLog") + @slash_option(name="channel", description="Channel to ignore", opt_type=OptionTypes.CHANNEL, required=True) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _add_log_ignore(self, ctx: InteractionContext, channel: GuildText) -> None: if not isinstance(channel, GuildText): @@ -218,9 +206,7 @@ class SettingsCog(Extension): await self.delete_settings("unverified", ctx.guild.id) await ctx.send("Setting `unverified` unset") - @unset.subcommand( - sub_cmd_name="noinvite", sub_cmd_description="Unset if invite deletion should happen" - ) + @unset.subcommand(sub_cmd_name="noinvite", sub_cmd_description="Unset if invite deletion should happen") @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _unset_invitedel(self, ctx: InteractionContext, active: bool) -> None: await ctx.defer() @@ -234,9 +220,7 @@ class SettingsCog(Extension): await self.delete_settings("notify", ctx.guild.id) await ctx.send("Setting `notify` unset") - @unset.subcommand( - sub_cmd_name="log_ignore", sub_cmd_description="Add a channel for ActivityLog" - ) + @unset.subcommand(sub_cmd_name="log_ignore", sub_cmd_description="Add a channel for ActivityLog") @slash_option( name="channel", description="Channel to stop ignoring", @@ -282,21 +266,15 @@ class SettingsCog(Extension): if value: value = value.mention else: - value = "||`[redacted]`||" + await setting.delete() + continue elif setting.setting in ["activitylog", "modlog"]: value = await ctx.guild.fetch_channel(value) if value: value = value.mention else: - value = "||`[redacted]`||" - elif setting.setting == "rolegiver": - value = "" - for _role in setting.value: - nvalue = await ctx.guild.fetch_role(_role) - if nvalue: - value += "\n" + nvalue.mention - else: - value += "\n||`[redacted]`||" + await setting.delete() + continue elif setting.setting == "log_ignore": names = [] for v in setting.value: @@ -315,19 +293,18 @@ class SettingsCog(Extension): async def _clear(self, ctx: InteractionContext) -> None: components = [ ActionRow( - Button(style=ButtonStyles.RED, emoji="✖️", custom_id="no"), - Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id="yes"), + Button(style=ButtonStyles.RED, emoji="✖️", custom_id=f"{ctx.guild.id}|set_clear|no"), + Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"{ctx.guild.id}|set_clear|yes"), ) ] message = await ctx.send("***Are you sure?***", components=components) try: context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.context.author.id, + check=lambda x: ctx.author.id == x.ctx.author.id, messages=message, timeout=60 * 5, ) - content = "***Are you sure?***" - if context.context.custom_id == "yes": + if context.ctx.custom_id == f"{ctx.guild.id}|set_clear|yes": async for setting in Setting.find(q(guild=ctx.guild.id)): await setting.delete() content = "Guild settings cleared" @@ -336,7 +313,7 @@ class SettingsCog(Extension): for row in components: for component in row.components: component.disabled = True - await context.context.edit_origin(content=content, components=components) + await context.ctx.edit_origin(content=content, components=components) except asyncio.TimeoutError: for row in components: for component in row.components: diff --git a/jarvis/cogs/twitter.py b/jarvis/cogs/twitter.py index cd819ae..1c3e7df 100644 --- a/jarvis/cogs/twitter.py +++ b/jarvis/cogs/twitter.py @@ -136,11 +136,11 @@ class TwitterCog(Extension): try: context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.context.author.id, + check=lambda x: ctx.author.id == x.ctx.author.id, messages=message, timeout=60 * 5, ) - for to_delete in context.context.values: + for to_delete in context.ctx.values: follow = get(twitters, guild=ctx.guild.id, twitter_id=int(to_delete)) try: await follow.delete() @@ -150,8 +150,8 @@ class TwitterCog(Extension): for component in row.components: component.disabled = True - block = "\n".join(handlemap[x] for x in context.context.values) - await context.context.edit_origin( + block = "\n".join(handlemap[x] for x in context.ctx.values) + await context.ctx.edit_origin( content=f"Unfollowed the following:\n```\n{block}\n```", components=components ) except asyncio.TimeoutError: @@ -200,13 +200,13 @@ class TwitterCog(Extension): try: context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.author.id, + check=lambda x: ctx.author.id == x.ctx.author.id, messages=message, timeout=60 * 5, ) handlemap = {} - for to_update in context.context.values: + for to_update in context.ctx.values: account = await TwitterAccount.find_one(q(twitter_id=int(to_update))) handlemap[str(twitter.twitter_id)] = account.handle t = get(twitters, guild=ctx.guild.id, twitter_id=int(to_update)) @@ -217,8 +217,8 @@ class TwitterCog(Extension): for component in row.components: component.disabled = True - block = "\n".join(handlemap[x] for x in context.context.values) - await context.context.edit_origin( + block = "\n".join(handlemap[x] for x in context.ctx.values) + await context.ctx.edit_origin( content=( f"{'Unfollowed' if not retweets else 'Followed'} " "retweets from the following:" diff --git a/jarvis/config.py b/jarvis/config.py index 2e2ecd6..a4feeb2 100644 --- a/jarvis/config.py +++ b/jarvis/config.py @@ -17,6 +17,7 @@ class JarvisConfig(Config): "twitter": None, "reddit": None, "rook_token": None, + "jurigged": False, } ENV_REQUIRED = [ "TOKEN", @@ -42,6 +43,7 @@ class JarvisConfig(Config): "TWITTER_ACCESS_TOKEN": None, "TWITTER_ACCESS_SECRET": None, "URLS_DBRAND_SHIPPING": None, + "JURIGGED": False, } @classmethod diff --git a/poetry.lock b/poetry.lock index df35dec..b91b63c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1475,19 +1475,19 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "2.6.0" +version = "2.6.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-2.6.0-py3-none-any.whl", hash = "sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca"}, - {file = "platformdirs-2.6.0.tar.gz", hash = "sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e"}, + {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, + {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, ] [package.extras] -docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"] -test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pre-commit" @@ -2225,10 +2225,8 @@ description = "Fuzzy string matching in python" category = "main" optional = false python-versions = "*" -files = [ - {file = "thefuzz-0.19.0-py2.py3-none-any.whl", hash = "sha256:4fcdde8e40f5ca5e8106bc7665181f9598a9c8b18b0a4d38c41a095ba6788972"}, - {file = "thefuzz-0.19.0.tar.gz", hash = "sha256:6f7126db2f2c8a54212b05e3a740e45f4291c497d75d20751728f635bb74aa3d"}, -] +files = [] +develop = false [package.dependencies] python-levenshtein = {version = ">=0.12", optional = true, markers = "extra == \"speedup\""} @@ -2236,6 +2234,12 @@ python-levenshtein = {version = ">=0.12", optional = true, markers = "extra == \ [package.extras] speedup = ["python-levenshtein (>=0.12)"] +[package.source] +type = "git" +url = "https://github.com/zevaryx/thefuzz.git" +reference = "master" +resolved_reference = "e4ab69d3d44cc3dd67221cba53e6a614786b0d7c" + [[package]] name = "tomli" version = "2.0.1" @@ -2686,4 +2690,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "2.0" python-versions = ">=3.10,<4" -content-hash = "9b727b6dcd39bfdbe5adbf2c1ab9a2846142f93c4214d72a30c81780c8e9c2b8" +content-hash = "89f766c3bacf47f7b955a812a695020dbae9c4f301816e94c943151af2696a19" diff --git a/pyproject.toml b/pyproject.toml index 253a67c..430753f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,21 +14,21 @@ psutil = "^5.9.0" python-gitlab = "^3.1.1" ulid-py = "^1.1.0" tweepy = "^4.5.0" -jarvis-core = {git = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git", rev = "main"} +jarvis-core = {git = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git", rev = "main"} # Mine aiohttp = "^3.8.3" -pastypy = "^1.0.3.post1" +pastypy = "^1.0.3.post1" # Mine dateparser = "^1.1.1" aiofile = "^3.8.1" asyncpraw = "^7.5.0" rich = "^12.3.0" -jurigged = "^0.5.3" -naff = { version = "^2.0.0", extras = ["orjson"] } +jurigged = "^0.5.3" # Contributed +naff = { version = "^2.0.0", extras = ["orjson"] } # Contributed ansitoimg = "^2022.1" nest-asyncio = "^1.5.5" -thefuzz = {extras = ["speedup"], git = "https://github.com/zevaryx/thefuzz.git", rev = "master"} +thefuzz = {extras = ["speedup"], git = "https://github.com/zevaryx/thefuzz.git", rev = "master"} # Forked beautifulsoup4 = "^4.11.1" -calculator = {git = "https://git.zevaryx.com/zevaryx/calculator.git"} -nafftrack = {git = "https://github.com/zevaryx/nafftrack.git"} +calculator = {git = "https://git.zevaryx.com/zevaryx/calculator.git"} # Mine +nafftrack = {git = "https://github.com/zevaryx/nafftrack.git"} # Contributed redis = "^4.4.0" [tool.poetry.dev-dependencies]