diff --git a/redbot/cogs/mod/settings.py b/redbot/cogs/mod/settings.py index 22864f6d1..add9d9e02 100644 --- a/redbot/cogs/mod/settings.py +++ b/redbot/cogs/mod/settings.py @@ -1,9 +1,11 @@ +import asyncio from collections import defaultdict, deque from typing import Optional from datetime import timedelta from redbot.core import commands, i18n, checks -from redbot.core.utils.chat_formatting import box, humanize_timedelta +from redbot.core.utils import AsyncIter +from redbot.core.utils.chat_formatting import box, humanize_timedelta, inline from .abc import MixinMeta @@ -398,3 +400,62 @@ class ModSettings(MixinMeta): duration=humanize_timedelta(timedelta=duration) ) ) + + @modset.command() + @commands.max_concurrency(1, commands.BucketType.default) + @commands.is_owner() + async def deletenames(self, ctx: commands.Context, confirmation: bool = False) -> None: + """Delete all stored usernames and nicknames. + + Examples: + - `[p]modset deletenames` - Did not confirm. Shows the help message. + - `[p]modset deletenames yes` - Deletes all stored usernames and nicknames. + + **Arguments** + + - `` This will default to false unless specified. + """ + if not confirmation: + await ctx.send( + _( + "This will delete all stored usernames and nicknames the bot has stored." + "\nIf you're sure, type {command}" + ).format(command=inline(f"{ctx.clean_prefix}modset deletenames yes")) + ) + return + + async with ctx.typing(): + # Nickname data + async with self.config._get_base_group(self.config.MEMBER).all() as mod_member_data: + guilds_to_remove = [] + for guild_id, guild_data in mod_member_data.items(): + await asyncio.sleep(0) + members_to_remove = [] + + async for member_id, member_data in AsyncIter(guild_data.items(), steps=100): + if "past_nicks" in member_data: + del member_data["past_nicks"] + if not member_data: + members_to_remove.append(member_id) + + async for member_id in AsyncIter(members_to_remove, steps=100): + del guild_data[member_id] + if not guild_data: + guilds_to_remove.append(guild_id) + + async for guild_id in AsyncIter(guilds_to_remove, steps=100): + del mod_member_data[guild_id] + + # Username data + async with self.config._get_base_group(self.config.USER).all() as mod_user_data: + users_to_remove = [] + async for user_id, user_data in AsyncIter(mod_user_data.items(), steps=100): + if "past_names" in user_data: + del user_data["past_names"] + if not user_data: + users_to_remove.append(user_id) + + async for user_id in AsyncIter(users_to_remove, steps=100): + del mod_user_data[user_id] + + await ctx.send(_("Usernames and nicknames have been deleted from Mod config."))