diff --git a/moderation/config.py b/moderation/config.py index 7571fa8..d2cf7d6 100644 --- a/moderation/config.py +++ b/moderation/config.py @@ -1,3 +1,3 @@ -from Redbot.core import Config +from redbot.core import Config config = Config.get_conf(None, identifier=481923957134912, cog_name="Moderation") diff --git a/moderation/database.py b/moderation/database.py index 68ef0b3..af18374 100644 --- a/moderation/database.py +++ b/moderation/database.py @@ -1,7 +1,7 @@ import json import time -import mysql.connector from datetime import datetime +import mysql.connector from discord import Guild from .utils import generate_dict, get_next_case_number, check_conf from .config import config @@ -94,8 +94,8 @@ async def create_guild_table(guild: Guild): "NULL", "NULL", 0, - json.dumps([]), - json.dumps({}), + json.dumps([]), # pylint: disable=dangerous-default-value + json.dumps({}), # pylint: disable=dangerous-default-value ) cursor.execute(insert_query, insert_values) @@ -125,9 +125,9 @@ async def mysql_log( resolved_by: str = None, resolved_reason: str = None, expired: bool = None, - changes: list = [], - metadata: dict = {}, -): # pylint: disable=dangerous-default-argument + changes: list = [], # pylint: disable=dangerous-default-value + metadata: dict = {}, # pylint: disable=dangerous-default-value +): if not timestamp: timestamp = int(time.time()) diff --git a/moderation/embed_factory.py b/moderation/embed_factory.py index 69fac49..6d2160b 100644 --- a/moderation/embed_factory.py +++ b/moderation/embed_factory.py @@ -1,5 +1,5 @@ -import humanize from datetime import datetime, timedelta +import humanize from discord import Color, Embed, Guild, Interaction, InteractionMessage from .utils import get_next_case_number, fetch_user_dict diff --git a/moderation/moderation.py b/moderation/moderation.py index f5c1614..12c9af1 100644 --- a/moderation/moderation.py +++ b/moderation/moderation.py @@ -101,7 +101,7 @@ class Moderation(commands.Cog): try: for guild in guilds: if not await self.bot.cog_disabled_in_guild(self, guild): - await self.create_guild_table(guild) + await create_guild_table(guild) except ConnectionRefusedError: return @@ -204,7 +204,7 @@ class Moderation(commands.Cog): moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'NOTE', target.id, 0, 'NULL', reason) await interaction.edit_original_response(content=f"{target.mention} has received a note! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) @app_commands.command(name="warn") async def warn(self, interaction: discord.Interaction, target: discord.Member, reason: str, silent: bool = None): @@ -234,16 +234,15 @@ class Moderation(commands.Cog): moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'WARN', target.id, 0, 'NULL', reason) await interaction.edit_original_response(content=f"{target.mention} has been warned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) - async def blacklist_autocomplete(self, interaction: discord.Interaction, current: str,) -> list[app_commands.Choice[str]]: + async def blacklist_autocomplete(self, interaction: discord.Interaction, current: str,) -> list[app_commands.Choice[str]]: # pylint: disable=unused-argument """Autocompletes a blacklist role.""" blacklist_roles = await self.config.guild(interaction.guild).blacklist_roles() if blacklist_roles: return [app_commands.Choice(name=role.name, value=role.id) for role in interaction.guild.roles if role.id in blacklist_roles] - else: - return [] + return [] @app_commands.command(name="blacklist") @app_commands.autocomplete(role=blacklist_autocomplete) @@ -263,7 +262,7 @@ class Moderation(commands.Cog): blacklist_roles = await self.config.guild(interaction.guild).blacklist_roles() if not blacklist_roles: - await interaction.response.send_message(content=f"There are no blacklist types set for this server!", ephemeral=True) + await interaction.response.send_message(content="There are no blacklist types set for this server!", ephemeral=True) return matching_role = None @@ -274,7 +273,7 @@ class Moderation(commands.Cog): break if not matching_role: - await interaction.response.send_message(content=f"Please provide a valid blacklist type!", ephemeral=True) + await interaction.response.send_message(content="Please provide a valid blacklist type!", ephemeral=True) return if not await check_moddable(target, interaction, ['moderate_members', 'manage_roles']): @@ -284,13 +283,22 @@ class Moderation(commands.Cog): await interaction.response.send_message(content=f"{target.mention} already has the blacklist role!", ephemeral=True) return + if silent is None: + silent = not await self.config.guild(interaction.guild).dm_users() + if silent is False: + try: + embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, reason=reason, moderation_type='blacklisted', response=await interaction.original_response(), duration=matching_role['duration']) + await target.send(embed=embed) + except discord.errors.HTTPException: + pass + role_obj = interaction.guild.get_role(role) await target.add_roles(role, reason=f"Blacklisted by {interaction.user.id} for {humanize.precisedelta(matching_role['duration'])} for: {reason}") await interaction.response.send_message(content=f"{target.mention} has been blacklisted with the {role_obj.name} role for {humanize.precisedelta(matching_role['duration'])}!\n**Reason** - `{reason}`") moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'BLACKLIST', target.id, role, matching_role['duration'], reason) await interaction.edit_original_response(content=f"{target.mention} has been blacklisted with the {role_obj.name} role for {humanize.precisedelta(matching_role['duration'])}! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) @app_commands.command(name="mute") async def mute(self, interaction: discord.Interaction, target: discord.Member, duration: str, reason: str, silent: bool = None): @@ -338,7 +346,7 @@ class Moderation(commands.Cog): moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'MUTE', target.id, 0, parsed_time, reason) await interaction.edit_original_response(content=f"{target.mention} has been muted for {humanize.precisedelta(parsed_time)}! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) @app_commands.command(name="unmute") async def unmute(self, interaction: discord.Interaction, target: discord.Member, reason: str = None, silent: bool = None): @@ -378,7 +386,7 @@ class Moderation(commands.Cog): moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'UNMUTE', target.id, 0, 'NULL', reason) await interaction.edit_original_response(content=f"{target.mention} has been unmuted! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) @app_commands.command(name="kick") async def kick(self, interaction: discord.Interaction, target: discord.Member, reason: str, silent: bool = None): @@ -410,7 +418,7 @@ class Moderation(commands.Cog): moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'KICK', target.id, 0, 'NULL', reason) await interaction.edit_original_response(content=f"{target.mention} has been kicked! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) @app_commands.command(name="ban") @app_commands.choices(delete_messages=[ @@ -465,7 +473,7 @@ class Moderation(commands.Cog): moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'TEMPBAN', target.id, 0, parsed_time, reason) await interaction.edit_original_response(content=f"{target.mention} has been banned for {humanize.precisedelta(parsed_time)}! (Case `#{moderation_id}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) else: await interaction.response.send_message(content=f"{target.mention} has been banned!\n**Reason** - `{reason}`") @@ -473,14 +481,14 @@ class Moderation(commands.Cog): silent = not await self.config.guild(interaction.guild).dm_users() if silent is False: try: - embed = embed = await embed_factory('message', guild=interaction.guild, reason=reason, moderation_type='banned', response=await interaction.original_response()) + embed = embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, reason=reason, moderation_type='banned', response=await interaction.original_response()) await target.send(embed=embed) except discord.errors.HTTPException: pass await interaction.guild.ban(target, reason=f"Banned by {interaction.user.id} for: {reason}", delete_message_seconds=delete_messages) - moderation_id = await self.mysql_log(interaction.guild.id, interaction.user.id, 'BAN', target.id, 0, 'NULL', reason) + moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'BAN', target.id, 0, 'NULL', reason) await interaction.edit_original_response(content=f"{target.mention} has been banned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") await log(interaction, moderation_id) @@ -524,7 +532,7 @@ class Moderation(commands.Cog): moderation_id = await mysql_log(interaction.guild.id, interaction.user.id, 'UNBAN', target.id, 0, 'NULL', reason) await interaction.edit_original_response(content=f"{target.mention} has been unbanned! (Case `#{moderation_id:,}`)\n**Reason** - `{reason}`") - await log(interaction, moderation_id) + await log(interaction, moderation_id, await self.bot.get_embed_color(None)) @app_commands.command(name="history") async def history(self, interaction: discord.Interaction, target: discord.User = None, moderator: discord.User = None, pagesize: app_commands.Range[int, 1, 20] = None, page: int = 1, ephemeral: bool = None, inline: bool = None, export: bool = False): @@ -756,7 +764,7 @@ class Moderation(commands.Cog): embed = await embed_factory('case', await self.bot.get_embed_color(None), interaction=interaction, case_dict=await self.fetch_case(case, interaction.guild.id)) await interaction.response.send_message(content=f"✅ Moderation #{case:,} resolved!", embed=embed) - await log(interaction, case, True) + await log(interaction, case, await self.bot.get_embed_color(None), True) cursor.close() database.close() @@ -918,7 +926,7 @@ class Moderation(commands.Cog): embed = await embed_factory('case', await self.bot.get_embed_color(None), interaction=interaction, case_dict=new_case) await interaction.response.send_message(content=f"✅ Moderation #{case:,} edited!", embed=embed, ephemeral=True) - await log(interaction, case) + await log(interaction, case, await self.bot.get_embed_color(None)) cursor.close() database.close() @@ -1411,8 +1419,8 @@ class Moderation(commands.Cog): else: duration = 'NULL' except OverflowError: - failed_cases.append(case['case']) - continue + failed_cases.append(case['case']) + continue if case['resolved']: resolved = 1 diff --git a/moderation/utils.py b/moderation/utils.py index a7e0528..af273fc 100644 --- a/moderation/utils.py +++ b/moderation/utils.py @@ -1,11 +1,10 @@ import json from typing import Union -from discord import User, Member, Interaction, Guild +from discord import Color, User, Member, Interaction, Guild from discord.errors import NotFound, Forbidden from redbot.core import commands -import database as db -from .embed_factory import embed_factory from .config import config +from .database import connect, fetch_case async def check_conf(config_list: list): @@ -112,7 +111,7 @@ async def check_moddable( async def get_next_case_number(guild_id: str, cursor=None): """This method returns the next case number from the MySQL table for a specific guild.""" if not cursor: - database = await db.connect() + database = await connect() cursor = database.cursor() cursor.execute( f"SELECT moderation_id FROM `moderation_{guild_id}` ORDER BY moderation_id DESC LIMIT 1" @@ -181,16 +180,18 @@ async def fetch_role_dict(interaction: Interaction, role_id: str): return role_dict -async def log(interaction: Interaction, moderation_id: int, resolved: bool = False): +async def log(interaction: Interaction, moderation_id: int, color: Color, resolved: bool = False): """This method sends a message to the guild's configured logging channel when an infraction takes place.""" + from .embed_factory import embed_factory + logging_channel_id = await config.guild(interaction.guild).log_channel() if logging_channel_id != " ": logging_channel = interaction.guild.get_channel(logging_channel_id) - case = await db.fetch_case(moderation_id, interaction.guild.id) + case = await fetch_case(moderation_id, interaction.guild.id) if case: embed = await embed_factory( - "log", interaction=interaction, case_dict=case, resolved=resolved + "log", color, interaction=interaction, case_dict=case, resolved=resolved ) try: await logging_channel.send(embed=embed)