async def logging_add(self, ctx, channel: Union[TextChannel], logging_types: commands.Greedy[ModLoggingType]): """CONFIG_LOGGING_ADD_HELP""" logging_types = list(set(logging_types)) # BIG BRAIN CODE for logging_type in logging_types: if channel.id in getattr( self.bot.cache.guilds.get(ctx.guild.id).logging, logging_type.value): logging_types.remove(logging_type) else: await self.bot.db.logging.add(logging_type, ctx.guild.id, channel.id) if len(logging_types) <= 0: return await ctx.send(Translator.translate('NOTHING_CHANGED', ctx)) await self.bot.cache.refresh(ctx.guild.id) await ctx.send( Translator.translate('MOD_LOGGING_ADDED', ctx, channel=channel.mention, logging_types=", ".join([ ltype.value for ltype in logging_types ])))
async def language(self, ctx, new_language=None): """CONFIG_LANGUAGE_HELP""" if new_language is None: settings = self.bot.cache.guilds.get(ctx.guild.id, None) current_language = (settings.language if settings is not None else 'en_US') or 'en_US' return await ctx.send( Translator.translate("CONFIG_LANGUAGE_CURRENT", ctx, language=current_language)) if new_language not in Translator.translations.keys(): return await ctx.send( Translator.translate( "CONFIG_LANGUAGE_BAD_LANGUAGE", ctx, languages=", ".join(list(Translator.translations.keys())))) await self.bot.db.languages.set(ctx.guild.id, new_language) await self.bot.cache.refresh(ctx.guild.id) await ctx.send( Translator.translate("CONFIG_LANGUAGE_UPDATED", ctx, language=new_language))
async def on_mod_log_join_leave(self, is_join: bool, member: Member): destinations = await self.get_destinations(member.guild.id, ModLoggingType.join_leave) guild_tz = self.bot.cache.guilds.get(member.guild.id).timezone if is_join: time_fmt = datetime.now().astimezone( timezone(guild_tz)).strftime("%H:%M:%S") for channel in destinations: await channel.send( Translator.translate('MOD_LOGS_JOIN', member.guild.id, time=time_fmt, target=str(member), target_id=str(member.id))) else: time_fmt = datetime.now().astimezone( timezone(guild_tz)).strftime("%H:%M:%S") for channel in destinations: await channel.send( Translator.translate('MOD_LOGS_LEAVE', member.guild.id, time=time_fmt, target=str(member), target_id=str(member.id)))
async def export(self, ctx): """TODO_EXPORT_HELP""" await ctx.trigger_typing() async with (await self.bot.db.get_pool()).acquire() as db: current_todos = await db.fetch( "SELECT * FROM bot.todos WHERE user_id = $1 ORDER BY timestamp DESC LIMIT 200;", ctx.author.id) if len(current_todos) <= 0: await ctx.send(Translator.translate("TODOS_EMPTY", ctx)) else: output = "Todo:\n" for index, todo in enumerate(current_todos): output += f"{index + 1}) {todo['content']}\n" bdata = BytesIO() bdata.write(output.encode(encoding='utf-8')) bdata.seek(0) try: await ctx.author.send( file=File(bdata, filename="Todo List.txt")) await ctx.send(Translator.translate('TODO_EXPORTED', ctx)) except Forbidden: await ctx.send( Translator.translate('TODO_EXPORT_CLOSED_DM', ctx, author=ctx.author.mention))
async def serverinfo(self, ctx, server_id: Union[discord.Guild, int] = None): """SERVERINFO_HELP""" if server_id is None: guild = ctx.guild else: guild = self.bot.get_guild(server_id) if guild is None: return await ctx.send(Translator.translate('SERVERINFO_NOT_FOUND', ctx, id=str(server_id))) guild_features = "\n".join(guild.features) if len(guild.features) > 0 else None guild_emojis = " ".join(walk_emojis(guild.emojis)) embed = DefraEmbed(title=f"{guild.name}") embed.set_thumbnail(url=guild.icon_url) embed.add_field(name="**ID**", value=str(guild.id), inline=False) embed.add_field(name=Translator.translate("SERVERINFO_OWNER", ctx), value=str(guild.owner), inline=False) embed.add_field(name=Translator.translate("SERVERINFO_MEMBERS", ctx), value=str(guild.member_count), inline=False) if guild_features is not None: embed.add_field(name=Translator.translate("SERVERINFO_FEATURES", ctx), value=guild_features, inline=False) embed.add_field(name=Translator.translate("SERVERINFO_EMOJILIST", ctx), value=guild_emojis[0:1000], inline=False) await ctx.send(embed=embed)
async def mod_roles_remove(self, ctx, roles: commands.Greedy[int] = None): """MOD_ROLES_REMOVE_HELP""" if roles is None: return await ctx.send(embed=error_embed( text=None, title=Translator.translate('CONFIG_MOD_ROLES_EMPTY_ARGUMENT', ctx.guild.id))) # Iterate through provided list of roles for role_id in roles: # Check if role_id is already a mod role if role_id not in self.bot.cache.guilds.get( ctx.guild.id).mod_roles: return await ctx.send( embed=error_embed(text=None, title=Translator.translate( 'CONFIG_MOD_ROLES_REMOVE_BAD_ROLE', ctx, role_id=role_id))) # Delete the role await self.bot.db.roles.remove(TableRolesTypes.mod_roles, ctx.guild.id, role_id) await self.bot.cache.refresh(ctx.guild.id) await ctx.send(embed=DefraEmbed( title=Translator.translate('CONFIG_MOD_ROLES_REMOVED', ctx.guild.id), description='\n'.join([ str( ctx.guild.get_role(role_id).mention if ctx.guild. get_role(role_id) is not None else role_id) for role_id in roles ])))
async def send_archive(bot, ctx: Context, messages: List[Message], archived_channel: TextChannel): file_bytes = await Messages.archive_messages(bot, messages) filename = f"Archive for {archived_channel.name}.txt" try: file_bytes.seek(0) await ctx.author.send(file=File(file_bytes, filename=filename)) await ctx.send(Translator.translate('ARCHIVE_SENT', ctx)) except Forbidden: file_bytes.seek(0) await ctx.send( Translator.translate('ARCHIVE_WARNING_CLOSED_DMS', ctx, author=ctx.author.mention)) try: def check(m): return m.author == ctx.author and any( ext.lower() in m.content.lower() for ext in ['yes', 'no']) msg = await bot.wait_for('message', check=check, timeout=60.0) except asyncio.TimeoutError: await ctx.send(Translator.translate('ARCHIVE_TOO_SLOW', ctx)) else: if 'yes' in msg.content.lower(): await ctx.send(file=File(file_bytes, filename=filename)) else: await ctx.send( Translator.translate('ARCHIVE_CANCELLED', ctx))
async def todo(self, ctx): """TODO_HELP""" if ctx.invoked_subcommand is None: await ctx.send(embed=warn_embed( title=Translator.translate("EMBED_NO_SUBCOMMAND_TITLE", ctx), text=Translator.translate( "EMBED_NO_SUBCOMMAND_DESCRIPTION", ctx, help=f"{ctx.prefix}help {ctx.command.qualified_name}")))
async def about(self, ctx): """ABOUT_TITLE""" e = DefraEmbed( title=Translator.translate("ABOUT_TITLE", ctx), footer_text=Translator.translate("ABOUT_FOOTER", ctx, user=ctx.author), footer_icon_url=ctx.author.avatar_url, description=Translator.translate('ABOUT_DESCRIPTION', ctx, owner=self.bot.owner, lib_version=f"discord.py {discord.__version__}") ) e.set_thumbnail(url=self.bot.user.avatar_url_as(format="png")) await ctx.send(embed=e)
async def what_prefix(self, ctx): """WHATPREFIX_HELP""" if ctx.guild is None: return await ctx.send( Translator.translate('WHATPREFIX', ctx, prefix=self.bot.cfg['DEFAULT_PREFIX'])) prefix = self.bot.cache.guilds.get( ctx.guild.id).prefix or self.bot.cfg['DEFAULT_PREFIX'] await ctx.send(Translator.translate('WHATPREFIX', ctx, prefix=prefix))
async def mod_roles_reset(self, ctx): """MOD_ROLES_RESET_HELP""" if len(self.bot.cache.guilds.get(ctx.guild.id).mod_roles) <= 0: return await ctx.send(Translator.translate('MOD_ROLES_RESET_FAIL'), ctx) await self.bot.db.roles.set(TableRolesTypes.mod_roles, ctx.guild.id, []) await self.bot.cache.refresh(ctx.guild.id) await ctx.send(Translator.translate('MOD_ROLES_RESET_SUCCESS', ctx))
async def translate(self, ctx, translate_from, translate_to, *, text: str): """TRANSLATE_HELP""" await ctx.trigger_typing() data = await self.bot.apis.yandex_translate(text=text, tr_to=translate_to, tr_from=translate_from) if data['code'] != 200: await ctx.send(embed=error_embed(title=Translator.translate('YANDEX_TRANSLATE_FAILED', ctx), text=data['message'])) elif data['code'] == 200: e = DefraEmbed() e.description = data['text'][0] e.set_footer(text=Translator.translate('YANDEX_TRANSLATE_NOTICE', ctx), icon_url="https://translate.yandex.ru/icons/favicon.png") await ctx.send(embed=e)
async def avatar(self, ctx, user: Union[discord.Member, SmartUser] = None): """AVATAR_HELP""" user = user or ctx.author avatar_url = user.avatar_url_as(static_format="png") embed = DefraEmbed( title=Translator.translate("AVATAR_TITLE", ctx, user=user), description=Translator.translate("AVATAR_DESCRIPTION", ctx, url=avatar_url) ) embed.set_image(url=avatar_url) await ctx.send(embed=embed)
async def purge(self, ctx): """TODO_PURGE_HELP""" await ctx.trigger_typing() async with (await self.bot.db.get_pool()).acquire() as conn: async with conn.transaction(): resp = await conn.fetchval( "DELETE FROM bot.todos WHERE user_id = $1 RETURNING True", ctx.author.id) if resp is True: await ctx.send(Translator.translate("TODO_PURGE_DONE", ctx)) else: await ctx.send(Translator.translate("TODO_PURGE_EMPTY_LIST", ctx))
async def on_mod_logging_messages(self, payload: Union[RawMessageUpdateEvent, RawMessageDeleteEvent], message_log_type: MessageLogType): if message_log_type is MessageLogType.deleted_message: destinations = await self.get_destinations(payload.guild_id, ModLoggingType.messages) guild_tz = self.bot.cache.guilds.get(payload.guild_id).timezone time_fmt = datetime.now().astimezone( timezone(guild_tz)).strftime("%H:%M:%S") if (cached_message := payload.cached_message) is None: message = await self.bot.db.fetchrow( "SELECT * FROM bot.messages WHERE guild_id = $1 AND message_id = $2", payload.guild_id, payload.message_id) if message is not None: content = self.bot.cryptor.decrypt(message['content']) content_fmt = utils.escape_mentions( utils.escape_markdown( content.decode(encoding='utf-8'))) author = self.bot.get_user(message['author_id']) c = self.bot.get_channel(message['channel_id']) for channel in destinations: await channel.send( Translator.translate('MOD_LOGS_MESSAGE_DELETED', payload.guild_id, user=str(author), time=time_fmt, user_id=str( message['author_id']), content=content_fmt, channel=c.mention)) elif cached_message is not None: content_fmt = utils.escape_mentions( utils.escape_markdown(cached_message.content)) for channel in destinations: await channel.send( Translator.translate( 'MOD_LOGS_MESSAGE_DELETED', cached_message.guild.id, user=str(cached_message.author), time=time_fmt, user_id=str(cached_message.author.id), content=content_fmt, channel=cached_message.channel.mention))
async def prefix(self, ctx: commands.Context, new_prefix=None): """CONFIG_PREFIX_HELP""" if new_prefix is None: return await ctx.send(Translator.translate("CONFIG_PREFIX_NO_NEW")) await self.bot.db.prefixes.set(ctx.guild.id, new_prefix) await self.bot.cache.refresh(ctx.guild.id) if self.bot.cache.guilds.get(ctx.guild.id).prefix == new_prefix: await ctx.send( Translator.translate("CONFIG_PREFIX_UPDATED", ctx, prefix=new_prefix)) else: await ctx.send(Translator.translate("CONFIG_UPDATE_ERROR", ctx))
async def add(self, ctx, *, task: str = None): """TODO_ADD_HELP""" await ctx.trigger_typing() if task is None: return await ctx.send(embed=warn_embed( title=Translator.translate("TODO_MISSING_ARG", ctx), text="")) async with (await self.bot.db.get_pool()).acquire() as conn: async with conn.transaction(): resp = await conn.fetchval( "INSERT INTO bot.todos (user_id, content) VALUES($1, $2) RETURNING True", ctx.author.id, task) if resp is True: await ctx.send(Translator.translate("TODO_ADDED", ctx))
async def hug(self, ctx, target: Member): """HUG_HELP""" await ctx.send( Translator.translate("HUG_MESSAGE_1", ctx, target=target.mention, author=str(ctx.author)))
async def config(self, ctx: commands.Context): """CONFIG_HELP""" if ctx.invoked_subcommand is None: await ctx.send( Translator.translate( "NO_SUBCOMMAND", ctx, help= f"{ctx.prefix}help {ctx.command} {ctx.command.signature}"))
async def fox(self, ctx): """FOX_HELP""" await ctx.trigger_typing() some_cat = await self.bot.apis.get_fox() embed = DefraEmbed( title=":fox: {0}".format(Translator.translate("THIS_FOX", ctx))) embed.set_image(url=some_cat) await ctx.send(embed=embed)
async def log_messages(self, ctx, mode: bool = None): """CONFIG_LOG_MESSAGES_HELP""" if mode is None: return await ctx.send( Translator.translate('CONFIG_LOG_MESSAGES_CURRENT_MOD', ctx, mode=self.bot.cache.guilds.get( ctx.guild.id).log_messages)) await self.bot.db.execute( "UPDATE bot.guilds SET log_messages = $2 WHERE guild_id = $1;", ctx.guild.id, mode) await self.bot.cache.refresh(ctx.guild.id) await ctx.send( Translator.translate('CONFIG_LOG_MESSAGES_UPDATED', ctx, mode=self.bot.cache.guilds.get( ctx.guild.id).log_messages))
async def cat(self, ctx): """CAT_HELP""" await ctx.trigger_typing() some_cat = await self.bot.apis.get_cat(self.bot.cfg['API_KEYS']['CATS'] ) embed = DefraEmbed( title=":cat: {0}".format(Translator.translate("THIS_CAT", ctx))) embed.set_image(url=some_cat) await ctx.send(embed=embed)
async def mod_roles(self, ctx): """MOD_ROLES_HELP""" if ctx.invoked_subcommand is None: e = DefraEmbed(title=Translator.translate( 'CONFIG_MOD_ROLES_CURRENT', ctx.guild.id), description='\n'.join([ f'{role.mention} (`{role.id}`)' if (role := ctx.guild.get_role(role_id)) is not None else f"`{role_id}`" for role_id in self.bot.cache.guilds.get( ctx.guild.id).mod_roles ]))
async def mod_roles_add(self, ctx, roles: commands.Greedy[int] = None): """MOD_ROLES_ADD_HELP""" if roles is None: return await ctx.send(embed=error_embed( text=None, title=Translator.translate('CONFIG_MOD_ROLES_EMPTY_ARGUMENT', ctx.guild.id))) # Filtering out non-existing roles and deleting duplicates roles = [ ctx.guild.get_role(role) for role in set( filter( lambda _id: True if ctx.guild.get_role(_id) is not None else False, roles)) ] if len(roles) <= 0: return await ctx.send(embed=error_embed( text=None, title=Translator.translate('CONFIG_MOD_ROLES_NONE_ADDED', ctx.guild.id))) # Adding each role id into the database for role in roles: if role.id not in self.bot.cache.guilds.get( ctx.guild.id).mod_roles: await self.bot.db.roles.add(TableRolesTypes.mod_roles, ctx.guild.id, role.id) else: return await ctx.send( embed=error_embed(title=Translator.translate( 'NOTHING_CHANGED', ctx.guild.id), text=None)) await self.bot.cache.refresh(ctx.guild.id) await ctx.send(embed=DefraEmbed( title=Translator.translate('CONFIG_MOD_ROLES_ADDED', ctx.guild.id), description='\n'.join( [f"{role.mention} (`{role.id}`)" for role in roles])))
async def shpaklevka(self, ctx, *, body: str): msg = await ctx.send("Your meme is being generated") if len(body) > 90: return await msg.edit( content=Translator.translate("CONTENT_LENGTH_90_MAX", ctx)) fn = partial(self.generate_meme, "shpaklevka", body) meme = await self.bot.loop.run_in_executor(None, fn) file = discord.File(fp=meme, filename="shpaklevka.jpg") await ctx.send(file=file, content=f"{ctx.author.mention}") return await msg.delete()
async def list(self, ctx): """TODO_LIST_HELP""" await ctx.trigger_typing() async with (await self.bot.db.get_pool()).acquire() as db: current_todos = await db.fetch( "SELECT * FROM bot.todos WHERE user_id = $1 ORDER BY timestamp DESC LIMIT 200;", ctx.author.id) if len(current_todos) <= 0: await ctx.send(Translator.translate("TODOS_EMPTY", ctx)) else: entries = [] for index, todo in enumerate(current_todos): entries.append(f"`{index + 1}` {todo['content']}") source = TodosSource(entries, title=Translator.translate("TODOS_LIST_TITLE", ctx, user=ctx.author)) menu = MyPagesMenu(source, delete_message_after=True) await menu.start(ctx)
async def timezone(self, ctx, new_timezone=None): """CONFIG_TIMEZONE_HELP""" if new_timezone is None: current_tz = self.bot.cache.guilds.get(ctx.guild.id).timezone return await ctx.send( Translator.translate("CONFIG_TIMEZONE_CURRENT", ctx, current=current_tz)) if is_timezone(new_timezone) is False: return await ctx.send( Translator.translate("CONFIG_TIMEZONE_BAD_TIMEZONE", ctx)) await self.bot.db.timezones.set(ctx.guild.id, new_timezone) await self.bot.cache.refresh(ctx.guild.id) if self.bot.cache.guilds.get(ctx.guild.id).timezone == new_timezone: await ctx.send( Translator.translate("CONFIG_TIMEZONE_UPDATED", ctx, timezone=new_timezone)) else: await ctx.send(Translator.translate("CONFIG_UPDATE_ERROR", ctx))
async def logging_reset(self, ctx, channel: Union[TextChannel, int] = None): """CONFIG_LOGGING_RESET_HELP""" if channel is None: return await ctx.send( Translator.translate('CONFIG_LOGGING_RESET_CHANNEL_IS_NONE', ctx)) for logging_type in ModLoggingType: if isinstance(channel, TextChannel): await self.bot.db.logging.remove(logging_type, ctx.guild.id, channel.id) elif isinstance(channel, int): await self.bot.db.logging.remove(logging_type, ctx.guild.id, channel) await self.bot.cache.refresh(ctx.guild.id) await ctx.send( Translator.translate('CONFIG_LOGGING_RESET', ctx, channel=f"{channel.mention}" if isinstance( channel, TextChannel) else f"{channel}"))
async def remove(self, ctx, todo_id): """TODO_REMOVE_HELP""" await ctx.trigger_typing() if not todo_id.isdigit(): return await ctx.send(Translator.translate("TODO_MUST_BE_INT", ctx)) todo_id = int(todo_id) target_todo = None async with (await self.bot.db.get_pool()).acquire() as conn: todos = await conn.fetch( "SELECT * FROM bot.todos WHERE user_id = $1 ORDER BY timestamp DESC LIMIT 200;", ctx.author.id) for index, todo in enumerate(todos): if index + 1 == todo_id: target_todo = todo if target_todo is None: await ctx.send(embed=warn_embed( title=Translator.translate('TODO_NOT_EXISTING', ctx))) else: async with (await self.bot.db.get_pool()).acquire() as conn: async with conn.transaction(): params = (target_todo.get('timestamp'), target_todo.get('user_id')) is_deleted = await conn.fetchval( "DELETE FROM bot.todos WHERE timestamp = $1 AND user_id = $2 RETURNING True", *params) if is_deleted: await ctx.send(embed=DefraEmbed( description=Translator.translate( 'TODO_REMOVED', ctx, todo=target_todo.get('content'))))
async def logging(self, ctx): """CONFIG_LOGGING_HELP""" if ctx.invoked_subcommand is None: logging_settings = self.bot.cache.guilds.get(ctx.guild.id).logging embed = DefraEmbed(title=Translator.translate( 'LOGGING_CURRENT_TITLE', ctx, servername=ctx.guild.name)) for modlog_type in ModLoggingType: channel_ids = [ channel_id for channel_id in getattr( logging_settings, modlog_type.value) ] channels_fmt = "\n".join([ f"{channel.mention}" if (channel := self.bot.get_channel(channel_id)) else f"~~`{channel_id}`~~" for channel_id in channel_ids ])