diff --git a/redbot/cogs/filter/filter.py b/redbot/cogs/filter/filter.py index b8eb4e6e4..b5fe1e3cb 100644 --- a/redbot/cogs/filter/filter.py +++ b/redbot/cogs/filter/filter.py @@ -240,8 +240,8 @@ class Filter: pass else: await modlog.create_case( - server, message.created_at, "filterban", - author, server.me, reason + self.bot, server, message.created_at, + "filterban", author, server.me, reason ) async def on_message(self, message: discord.Message): diff --git a/redbot/cogs/mod/mod.py b/redbot/cogs/mod/mod.py index 06597108e..1bb0faaa8 100644 --- a/redbot/cogs/mod/mod.py +++ b/redbot/cogs/mod/mod.py @@ -328,8 +328,8 @@ class Mod: try: await modlog.create_case( - guild, ctx.message.created_at, "kick", user, author, - reason, until=None, channel=None + self.bot, guild, ctx.message.created_at, "kick", + user, author, reason, until=None, channel=None ) except RuntimeError as e: await ctx.send(e) @@ -389,8 +389,8 @@ class Mod: try: await modlog.create_case( - guild, ctx.message.created_at, "ban", user, author, - reason, until=None, channel=None + self.bot, guild, ctx.message.created_at, "ban", + user, author, reason, until=None, channel=None ) except RuntimeError as e: await ctx.send(e) @@ -442,8 +442,8 @@ class Mod: user_info = await self.bot.get_user_info(user_id) try: await modlog.create_case( - guild, ctx.message.created_at, "hackban", user_info, author, - reason, until=None, channel=None + self.bot, guild, ctx.message.created_at, "hackban", + user_info, author, reason, until=None, channel=None ) except RuntimeError as e: await ctx.send(e) @@ -490,7 +490,7 @@ class Mod: try: await modlog.create_case( - guild, ctx.message.created_at, "tempban", + self.bot, guild, ctx.message.created_at, "tempban", user, author, reason, unban_time ) except RuntimeError as e: @@ -560,6 +560,7 @@ class Mod: user.name, user.id)) try: await modlog.create_case( + self.bot, guild, ctx.message.created_at, "softban", @@ -609,8 +610,8 @@ class Mod: try: await modlog.create_case( - guild, ctx.message.created_at, "unban", user, author, - reason, until=None, channel=None + self.bot, guild, ctx.message.created_at, "unban", + user, author, reason, until=None, channel=None ) except RuntimeError as e: await ctx.send(e) @@ -697,8 +698,8 @@ class Mod: try: await modlog.create_case( - guild, ctx.message.created_at, "voiceban", user, author, - reason, until=None, channel=None + self.bot, guild, ctx.message.created_at, "voiceban", + user, author, reason, until=None, channel=None ) except RuntimeError as e: await ctx.send(e) @@ -732,8 +733,8 @@ class Mod: author = ctx.author try: await modlog.create_case( - guild, ctx.message.created_at, "voiceunban", user, author, - reason, until=None, channel=None + self.bot, guild, ctx.message.created_at, "voiceunban", + user, author, reason, until=None, channel=None ) except RuntimeError as e: await ctx.send(e) @@ -791,8 +792,8 @@ class Mod: ) try: await modlog.create_case( - guild, ctx.message.created_at, "boicemute", user, author, - reason, until=None, channel=channel + self.bot, guild, ctx.message.created_at, "boicemute", + user, author, reason, until=None, channel=channel ) except RuntimeError as e: await ctx.send(e) @@ -826,8 +827,8 @@ class Mod: await channel.send(_("User has been muted in this channel.")) try: await modlog.create_case( - guild, ctx.message.created_at, "cmute", user, author, - reason, until=None, channel=channel + self.bot, guild, ctx.message.created_at, "cmute", + user, author, reason, until=None, channel=channel ) except RuntimeError as e: await ctx.send(e) @@ -862,8 +863,8 @@ class Mod: await ctx.send(_("User has been muted in this guild.")) try: await modlog.create_case( - guild, ctx.message.created_at, "smute", user, author, - reason, until=None, channel=None + self.bot, guild, ctx.message.created_at, "smute", + user, author, reason, until=None, channel=None ) except RuntimeError as e: await ctx.send(e) @@ -924,8 +925,8 @@ class Mod: user.name, user.discriminator, channel.name)) try: await modlog.create_case( - guild, ctx.message.created_at, "voiceunmute", user, author, - reason, until=None, channel=channel + self.bot, guild, ctx.message.created_at, "voiceunmute", + user, author, reason, until=None, channel=channel ) except RuntimeError as e: await ctx.send(e) @@ -953,8 +954,8 @@ class Mod: await ctx.send(_("User unmuted in this channel.")) try: await modlog.create_case( - guild, ctx.message.created_at, "cunmute", user, author, - reason, until=None, channel=channel + self.bot, guild, ctx.message.created_at, "cunmute", + user, author, reason, until=None, channel=channel ) except RuntimeError as e: await ctx.send(e) @@ -985,8 +986,8 @@ class Mod: await ctx.send(_("User has been unmuted in this guild.")) try: await modlog.create_case( - guild, ctx.message.created_at, "sunmute", user, author, - reason, until=None, channel=channel + self.bot, guild, ctx.message.created_at, "sunmute", + user, author, reason, until=None, channel=channel ) except RuntimeError as e: await ctx.send(e) @@ -1209,8 +1210,8 @@ class Mod: else: try: case = await modlog.create_case( - guild, message.created_at, "ban", author, guild.me, - "Mention spam (Autoban)", until=None, channel=None + self.bot, guild, message.created_at, "ban", author, + guild.me, "Mention spam (Autoban)", until=None, channel=None ) except RuntimeError as e: print(e) @@ -1269,7 +1270,7 @@ class Mod: if date is None: date = datetime.now() try: - await modlog.create_case(guild, date, + await modlog.create_case(self.bot, guild, date, "ban", member, mod, reason if reason else None) except RuntimeError as e: @@ -1288,7 +1289,7 @@ class Mod: if date is None: date = datetime.now() try: - await modlog.create_case(guild, date, "unban", + await modlog.create_case(self.bot, guild, date, "unban", user, mod, reason) except RuntimeError as e: print(e) diff --git a/redbot/cogs/modlog/modlog.py b/redbot/cogs/modlog/modlog.py index 5423ac423..acab67922 100644 --- a/redbot/cogs/modlog/modlog.py +++ b/redbot/cogs/modlog/modlog.py @@ -151,5 +151,5 @@ class ModLog: if case_before.moderator != author: to_modify["amended_by"] = author to_modify["modified_at"] = ctx.message.created_at.timestamp() - await case_before.edit(to_modify) + await case_before.edit(self.bot, to_modify) await ctx.send(_("Reason has been updated.")) diff --git a/redbot/core/cog_manager.py b/redbot/core/cog_manager.py index 72e6a892e..fe660b010 100644 --- a/redbot/core/cog_manager.py +++ b/redbot/core/cog_manager.py @@ -418,15 +418,40 @@ class CogManagerUI: loaded = sorted(list(loaded), key=str.lower) unloaded = sorted(list(unloaded), key=str.lower) - loaded = ('**{} loaded:**\n').format(len(loaded)) + ", ".join(loaded) - unloaded = ('**{} unloaded:**\n').format(len(unloaded)) + ", ".join(unloaded) + if await ctx.embed_requested(): + loaded = ('**{} loaded:**\n').format(len(loaded)) + ", ".join(loaded) + unloaded = ('**{} unloaded:**\n').format(len(unloaded)) + ", ".join(unloaded) - for page in pagify(loaded, delims=[', ', '\n'], page_length=1000): - e = discord.Embed(description=page, - colour=discord.Colour.dark_green()) - await ctx.send(embed=e) + for page in pagify(loaded, delims=[', ', '\n'], page_length=1800): + e = discord.Embed(description=page, + colour=discord.Colour.dark_green()) + await ctx.send(embed=e) - for page in pagify(unloaded, delims=[', ', '\n'], page_length=1000): - e = discord.Embed(description=page, - colour=discord.Colour.dark_red()) - await ctx.send(embed=e) + for page in pagify(unloaded, delims=[', ', '\n'], page_length=1800): + e = discord.Embed(description=page, + colour=discord.Colour.dark_red()) + await ctx.send(embed=e) + else: + loaded_count = '**{} loaded:**\n'.format(len(loaded)) + loaded = ", ".join(loaded) + unloaded_count = '**{} unloaded:**\n'.format(len(unloaded)) + unloaded = ", ".join(unloaded) + loaded_count_sent = False + unloaded_count_sent = False + for page in pagify(loaded, delims=[", ", "\n"], page_length=1800): + if page.startswith(", "): + page = page[2:] + if not loaded_count_sent: + await ctx.send(loaded_count + box(page, lang="css")) + loaded_count_sent = True + else: + await ctx.send(box(page, lang="css")) + + for page in pagify(unloaded, delims=[", ", "\n"], page_length=1800): + if page.startswith(", "): + page = page[2:] + if not unloaded_count_sent: + await ctx.send(unloaded_count + box(page, lang="ldif")) + unloaded_count_sent = True + else: + await ctx.send(box(page, lang="ldif")) diff --git a/redbot/core/core_commands.py b/redbot/core/core_commands.py index 4b2ef9a83..43e434fae 100644 --- a/redbot/core/core_commands.py +++ b/redbot/core/core_commands.py @@ -626,7 +626,7 @@ class Core: await ctx.send_help() else: await ctx.bot.change_presence(status=status, activity=game) - await ctx.send(_("Status changed to %s.") % status) + await ctx.send(_("Status changed to {}.").format(status)) @_set.command() @checks.bot_in_a_guild() @@ -863,13 +863,13 @@ class Core: owner = discord.utils.get(ctx.bot.get_all_members(), id=ctx.bot.owner_id) author = ctx.message.author - footer = _("User ID: %s") % author.id + footer = _("User ID: {}").format(author.id) if ctx.guild is None: source = _("through DM") else: source = _("from {}").format(guild) - footer += _(" | Server ID: %s") % guild.id + footer += _(" | Server ID: {}").format(guild.id) # We need to grab the DM command prefix (global) # Since it can also be set through cli flags, bot.db is not a reliable @@ -881,29 +881,43 @@ class Core: content = _("Use `{}dm {} ` to reply to this user" "").format(prefix, author.id) + description = _("Sent by {} {}").format(author, source) + if isinstance(author, discord.Member): colour = author.colour else: colour = discord.Colour.red() - description = _("Sent by {} {}").format(author, source) + if await ctx.embed_requested(): + e = discord.Embed(colour=colour, description=message) + if author.avatar_url: + e.set_author(name=description, icon_url=author.avatar_url) + else: + e.set_author(name=description) + e.set_footer(text=footer) - e = discord.Embed(colour=colour, description=message) - if author.avatar_url: - e.set_author(name=description, icon_url=author.avatar_url) + try: + await owner.send(content, embed=e) + except discord.InvalidArgument: + await ctx.send(_("I cannot send your message, I'm unable to find " + "my owner... *sigh*")) + except: + await ctx.send(_("I'm unable to deliver your message. Sorry.")) + else: + await ctx.send(_("Your message has been sent.")) else: - e.set_author(name=description) - e.set_footer(text=footer) - - try: - await owner.send(content, embed=e) - except discord.InvalidArgument: - await ctx.send(_("I cannot send your message, I'm unable to find " - "my owner... *sigh*")) - except: - await ctx.send(_("I'm unable to deliver your message. Sorry.")) - else: - await ctx.send(_("Your message has been sent.")) + msg_text = ( + "{}\nMessage:\n\n{}\n{}".format(description, message, footer) + ) + try: + await owner.send("{}\n{}".format(content, box(msg_text))) + except discord.InvalidArgument: + await ctx.send(_("I cannot send your message, I'm unable to find " + "my owner... *sigh*")) + except: + await ctx.send(_("I'm unable to deliver your message. Sorry.")) + else: + await ctx.send(_("Your message has been sent.")) @commands.command() @checks.is_owner() @@ -922,25 +936,36 @@ class Core: "with.")) return - e = discord.Embed(colour=discord.Colour.red(), description=message) - description = _("Owner of %s") % ctx.bot.user fake_message = namedtuple('Message', 'guild') prefixes = await ctx.bot.command_prefix(ctx.bot, fake_message(guild=None)) prefix = prefixes[0] - e.set_footer(text=_("You can reply to this message with %scontact" - "") % prefix) - if ctx.bot.user.avatar_url: - e.set_author(name=description, icon_url=ctx.bot.user.avatar_url) - else: - e.set_author(name=description) + description = _("Owner of {}").format(ctx.bot.user) + content = _("You can reply to this message with {}contact").format(prefix) + if await ctx.embed_requested(): + e = discord.Embed(colour=discord.Colour.red(), description=message) - try: - await destination.send(embed=e) - except: - await ctx.send(_("Sorry, I couldn't deliver your message " - "to %s") % destination) + e.set_footer(text=content) + if ctx.bot.user.avatar_url: + e.set_author(name=description, icon_url=ctx.bot.user.avatar_url) + else: + e.set_author(name=description) + + try: + await destination.send(embed=e) + except: + await ctx.send(_("Sorry, I couldn't deliver your message " + "to {}").format(destination)) + else: + await ctx.send(_("Message delivered to {}").format(destination)) else: - await ctx.send(_("Message delivered to %s") % destination) + response = "{}\nMessage:\n\n{}".format(description, message) + try: + await destination.send("{}\n{}".format(box(response), content)) + except: + await ctx.send(_("Sorry, I couldn't deliver your message " + "to {}").format(destination)) + else: + await ctx.send(_("Message delivered to {}").format(destination)) @commands.group() @checks.is_owner() diff --git a/redbot/core/help_formatter.py b/redbot/core/help_formatter.py index 3d6be7e7e..ae9aa12ab 100644 --- a/redbot/core/help_formatter.py +++ b/redbot/core/help_formatter.py @@ -280,10 +280,14 @@ async def help(ctx, *cmds: str): def repl(obj): return _mentions_transforms.get(obj.group(0), '') - + use_embeds = await ctx.embed_requested() + f = formatter.HelpFormatter() # help by itself just lists our own commands. if len(cmds) == 0: - embeds = await ctx.bot.formatter.format_help_for(ctx, ctx.bot) + if use_embeds: + embeds = await ctx.bot.formatter.format_help_for(ctx, ctx.bot) + else: + embeds = await f.format_help_for(ctx, ctx.bot) elif len(cmds) == 1: # try to see if it is a cog name name = _mention_pattern.sub(repl, cmds[0]) @@ -293,17 +297,29 @@ async def help(ctx, *cmds: str): else: command = ctx.bot.all_commands.get(name) if command is None: - await destination.send( - embed=ctx.bot.formatter.cmd_not_found(ctx, name)) + if use_embeds: + await destination.send( + embed=ctx.bot.formatter.cmd_not_found(ctx, name)) + else: + await destination.send( + ctx.bot.command_not_found.format(name) + ) return - - embeds = await ctx.bot.formatter.format_help_for(ctx, command) + if use_embeds: + embeds = await ctx.bot.formatter.format_help_for(ctx, command) + else: + embeds = await f.format_help_for(ctx, command) else: name = _mention_pattern.sub(repl, cmds[0]) command = ctx.bot.all_commands.get(name) if command is None: - await destination.send( - embed=ctx.bot.formatter.cmd_not_found(ctx, name)) + if use_embeds: + await destination.send( + embed=ctx.bot.formatter.cmd_not_found(ctx, name)) + else: + await destination.send( + ctx.bot.command_not_found.format(name) + ) return for key in cmds[1:]: @@ -311,29 +327,48 @@ async def help(ctx, *cmds: str): key = _mention_pattern.sub(repl, key) command = command.all_commands.get(key) if command is None: - await destination.send( - embed=ctx.bot.formatter.cmd_not_found(ctx, key)) + if use_embeds: + await destination.send( + embed=ctx.bot.formatter.cmd_not_found(ctx, key)) + else: + await destination.send( + ctx.bot.command_not_found.format(key) + ) return except AttributeError: - await destination.send( - embed=ctx.bot.formatter.simple_embed( - ctx, - title='Command "{0.name}" has no subcommands.'.format(command), - color=ctx.bot.formatter.color, - author=ctx.author.display_name)) + if use_embeds: + await destination.send( + embed=ctx.bot.formatter.simple_embed( + ctx, + title='Command "{0.name}" has no subcommands.'.format(command), + color=ctx.bot.formatter.color, + author=ctx.author.display_name)) + else: + await destination.send( + ctx.bot.command_has_no_subcommands.format(command) + ) return - - embeds = await ctx.bot.formatter.format_help_for(ctx, command) + if use_embeds: + embeds = await ctx.bot.formatter.format_help_for(ctx, command) + else: + embeds = await f.format_help_for(ctx, command) if len(embeds) > 2: destination = ctx.author for embed in embeds: - try: - await destination.send(embed=embed) - except discord.HTTPException: - destination = ctx.author - await destination.send(embed=embed) + if use_embeds: + try: + await destination.send(embed=embed) + except discord.HTTPException: + destination = ctx.author + await destination.send(embed=embed) + else: + try: + await destination.send(embed) + except discord.HTTPException: + destination = ctx.author + await destination.send(embed) @help.error diff --git a/redbot/core/modlog.py b/redbot/core/modlog.py index 3d4faa06e..a429684d3 100644 --- a/redbot/core/modlog.py +++ b/redbot/core/modlog.py @@ -59,12 +59,14 @@ class Case: self.case_number = case_number self.message = message - async def edit(self, data: dict): + async def edit(self, bot, data: dict): """ Edits a case Parameters ---------- + bot: Red + The bot instance data: dict The attributes to change @@ -74,21 +76,31 @@ class Case: """ for item in list(data.keys()): setattr(self, item, data[item]) - case_emb = await self.message_content() - await self.message.edit(embed=case_emb) + + use_embed = await bot.embed_requested(self.message.channel, self.guild.me) + case_content = await self.message_content(use_embed) + if use_embed: + await self.message.edit(embed=case_content) + else: + await self.message.edit(case_content) await _conf.guild(self.guild).cases.set_raw( str(self.case_number), value=self.to_json() ) - async def message_content(self): + async def message_content(self, embed: bool=True): """ Format a case message + Parameters + ---------- + embed: bool + Whether or not to get an embed + Returns ------- - discord.Embed - A rich embed representing a case message + discord.Embed or `str` + A rich embed or string representing a case message """ casetype = await get_casetype(self.action_type) @@ -103,17 +115,16 @@ class Case: self.case_number ) - emb = discord.Embed(title=title, description=reason) - user = "{}#{} ({})\n".format( - self.user.name, self.user.discriminator, self.user.id) - emb.set_author(name=user, icon_url=self.user.avatar_url) if self.moderator is not None: moderator = "{}#{} ({})\n".format( self.moderator.name, self.moderator.discriminator, self.moderator.id ) - emb.add_field(name="Moderator", value=moderator, inline=False) + else: + moderator = "Unknown" + until = None + duration = None if self.until: start = datetime.fromtimestamp(self.created_at) end = datetime.fromtimestamp(self.until) @@ -122,27 +133,57 @@ class Case: dur_fmt = _strfdelta(duration) until = end_fmt duration = dur_fmt - emb.add_field(name="Until", value=until) - emb.add_field(name="Duration", value=duration) - if self.channel: - emb.add_field(name="Channel", value=self.channel.name, inline=False) + amended_by = None if self.amended_by: amended_by = "{}#{} ({})".format( self.amended_by.name, self.amended_by.discriminator, self.amended_by.id ) - emb.add_field(name="Amended by", value=amended_by) + + last_modified = None if self.modified_at: last_modified = "{}".format( datetime.fromtimestamp( self.modified_at ).strftime('%Y-%m-%d %H:%M:%S') ) - emb.add_field(name="Last modified at", value=last_modified) - emb.timestamp = datetime.fromtimestamp(self.created_at) - return emb + + user = "{}#{} ({})\n".format( + self.user.name, self.user.discriminator, self.user.id) + if embed: + emb = discord.Embed(title=title, description=reason) + + emb.set_author(name=user, icon_url=self.user.avatar_url) + emb.add_field(name="Moderator", value=moderator, inline=False) + if until and duration: + emb.add_field(name="Until", value=until) + emb.add_field(name="Duration", value=duration) + + if self.channel: + emb.add_field(name="Channel", value=self.channel.name, inline=False) + if amended_by: + emb.add_field(name="Amended by", value=amended_by) + if last_modified: + emb.add_field(name="Last modified at", value=last_modified) + emb.timestamp = datetime.fromtimestamp(self.created_at) + return emb + else: + case_text = "" + case_text += "{}\n".format(title) + case_text += "**User:** {}\n".format(user) + case_text += "**Moderator:** {}\n".format(moderator) + case_text += "{}\n".format(reason) + if until and duration: + case_text += "**Until:** {}\n**Duration:** {}\n".format(until, duration) + if self.channel: + case_text += "**Channel**: {}\n".format(self.channel.name) + if amended_by: + case_text += "**Amended by:** {}\n".format(amended_by) + if last_modified: + case_text += "**Last modified at:** {}\n".format(last_modified) + return case_text.strip() def to_json(self) -> dict: """Transform the object to a dict @@ -377,7 +418,7 @@ async def get_all_cases(guild: discord.Guild, bot: Red) -> List[Case]: return case_list -async def create_case(guild: discord.Guild, created_at: datetime, action_type: str, +async def create_case(bot: Red, guild: discord.Guild, created_at: datetime, action_type: str, user: Union[discord.User, discord.Member], moderator: discord.Member=None, reason: str=None, until: datetime=None, channel: discord.TextChannel=None @@ -387,6 +428,8 @@ async def create_case(guild: discord.Guild, created_at: datetime, action_type: s Parameters ---------- + bot: `Red` + The bot object guild: `discord.Guild` The guild the action was taken in created_at: datetime @@ -438,8 +481,12 @@ async def create_case(guild: discord.Guild, created_at: datetime, action_type: s next_case_number, reason, until, channel, amended_by=None, modified_at=None, message=None) if hasattr(mod_channel, "send"): # Not going to be the case for tests - case_emb = await case.message_content() - msg = await mod_channel.send(embed=case_emb) + use_embeds = await bot.embed_requested(mod_channel, guild.me) + case_content = await case.message_content(use_embeds) + if use_embeds: + msg = await mod_channel.send(embed=case_content) + else: + msg = await mod_channel.send(case_content) case.message = msg await _conf.guild(guild).cases.set_raw(str(next_case_number), value=case.to_json()) return case diff --git a/tests/cogs/test_mod.py b/tests/cogs/test_mod.py index d256d914a..b0eeb31f4 100644 --- a/tests/cogs/test_mod.py +++ b/tests/cogs/test_mod.py @@ -31,12 +31,13 @@ async def test_modlog_case_create(mod, ctx, member_factory): from datetime import datetime as dt usr = member_factory.get() guild = ctx.guild + bot = ctx.bot case_type = "ban" moderator = ctx.author reason = "Test 12345" created_at = dt.utcnow() case = await mod.create_case( - guild, created_at, case_type, usr, moderator, reason + bot, guild, created_at, case_type, usr, moderator, reason ) assert case is not None assert case.user == usr