async def unmuteTask(modcog: Moderation): GearbotLogging.info("Started unmute background task") skips = [] updated = False while modcog.running: userid = 0 guildid = 0 try: guildstoremove = [] for guildid, list in modcog.mutes.items(): guild: discord.Guild = modcog.bot.get_guild(int(guildid)) toremove = [] if Configuration.getConfigVar(int(guildid), "MUTE_ROLE") is 0: guildstoremove.append(guildid) for userid, until in list.items(): if time.time() > until and userid not in skips: member = guild.get_member(int(userid)) role = discord.utils.get(guild.roles, id=Configuration.getConfigVar(int(guildid), "MUTE_ROLE")) if guild.me.guild_permissions.manage_roles: await member.remove_roles(role, reason="Mute expired") await GearbotLogging.logToModLog(guild, f"<:gearInnocent:465177981287923712> {member.name}#{member.discriminator} (`{member.id}`) has automaticaly been unmuted") else: await GearbotLogging.logToModLog(guild, f":no_entry: ERROR: {member.name}#{member.discriminator} (`{member.id}`) was muted earlier but I no longer have the permissions needed to unmute this person, please remove the role manually!") updated = True toremove.append(userid) for todo in toremove: del list[todo] await asyncio.sleep(0) if updated: Utils.saveToDisk("mutes", modcog.mutes) updated = False for id in guildstoremove: del modcog.mutes[id] await asyncio.sleep(10) except CancelledError: pass # bot shutdown except Exception as ex: GearbotLogging.error("Something went wrong in the unmute task") GearbotLogging.error(traceback.format_exc()) skips.append(userid) embed = discord.Embed(colour=discord.Colour(0xff0000), timestamp=datetime.datetime.utcfromtimestamp(time.time())) embed.set_author(name="Something went wrong in the unmute task:") embed.add_field(name="Current guildid", value=guildid) embed.add_field(name="Current userid", value=userid) embed.add_field(name="Exception", value=ex) v = "" for line in traceback.format_exc().splitlines(): if len(v) + len(line) > 1024: embed.add_field(name="Stacktrace", value=v) v = "" v = f"{v}\n{line}" if len(v) > 0: embed.add_field(name="Stacktrace", value=v) await GearbotLogging.logToBotlog(embed=embed) await asyncio.sleep(10) GearbotLogging.info("Unmute background task terminated")
async def on_message(self, message: discord.Message): if not hasattr(message.channel, "guild") or message.channel.guild is None: return ctx: commands.Context = await self.bot.get_context(message) guild = message.guild is_mod = Permissioncheckers.is_mod(ctx) if message.author == guild.me or is_mod or message.author.id in Configuration.getConfigVar(guild.id, "IGNORED_USERS"): return guilds = Configuration.getConfigVar(message.guild.id, "INVITE_WHITELIST") if len(guilds) is not 0: codes = INVITE_MATCHER.findall(message.content) for code in codes: try: invite:discord.Invite = await self.bot.get_invite(code) except discord.NotFound: pass except KeyError: await message.delete() clean_message = await clean_content().convert(ctx, message.content) clean_name = Utils.clean_user(message.author) await GearbotLogging.log_to_minor_log(message.guild, f":no_entry_sign: {Translator.translate('censored_invite', ctx.guild.id, user=clean_name, code=code, message=clean_message, server_name='DM group')}") else: if invite.guild is None or (not invite.guild.id in guilds and invite.guild.id != guild.id): await message.delete() clean_message = await clean_content().convert(ctx ,message.content) clean_name = Utils.clean_user(message.author) await GearbotLogging.log_to_minor_log(message.guild, f":no_entry_sign: {Translator.translate('censored_invite', ctx.guild.id, user=clean_name, code=code, message=clean_message, server_name=invite.guild.name)}")
async def on_raw_message_delete(self, data: RawMessageDeleteEvent): message = LoggedMessage.get_or_none(messageid=data.message_id) if message is not None: channel: discord.TextChannel = self.bot.get_channel( data.channel_id) user: discord.User = self.bot.get_user(message.author) hasUser = user is not None if hasUser and user.id in Configuration.getConfigVar( channel.guild.id, "IGNORED_USERS"): return channelid = Configuration.getConfigVar(channel.guild.id, "MINOR_LOGS") if channelid is not 0: logChannel: discord.TextChannel = self.bot.get_channel( channelid) if logChannel is not None and message.content != None and message.content != "": embed = discord.Embed( timestamp=datetime.datetime.utcfromtimestamp( time.time()), description=message.content) embed.set_author( name=user.name if hasUser else message.author, icon_url=user.avatar_url if hasUser else EmptyEmbed) embed.set_footer(text=f"Sent in #{channel.name}") name = Utils.clean_user(user) if hasUser else str( message.author) await logChannel.send( f":wastebasket: {Translator.translate('message_removed', channel.guild.id, name=name, user_id=user.id if hasUser else 'WEBHOOK', channel=channel.mention)}", embed=embed)
def check_permission(ctx: commands.Context, default): name = ctx.command.qualified_name.split(" ")[0] if ctx.guild is None: return default command_overrides = Configuration.getConfigVar(ctx.guild.id, "COMMAND_OVERRIDES") cog_overrides = Configuration.getConfigVar(ctx.guild.id, "COG_OVERRIDES") cog_name = type(ctx.cog).__name__ if name in command_overrides: return check_perm_lvl(ctx, command_overrides[name]) elif cog_name in cog_overrides: return check_perm_lvl(ctx, cog_overrides[cog_name]) else: return default
async def role(self, ctx: commands.Context, *, role: str = None): """role_help""" if role is None: await Pages.create_new("role", ctx) else: try: role = await commands.RoleConverter().convert(ctx, role) except Exception as ex: await ctx.send(Translator.translate("role_not_found", ctx)) else: roles = Configuration.getConfigVar(ctx.guild.id, "SELF_ROLES") if role.id in roles: if role in ctx.author.roles: await ctx.author.remove_roles(role) await ctx.send( Translator.translate("role_left", ctx, role_name=role.name)) else: await ctx.author.add_roles(role) await ctx.send( Translator.translate("role_joined", ctx, role_name=role.name)) else: await ctx.send( Translator.translate("role_not_allowed", ctx))
async def mute(self, ctx: commands.Context, target: discord.Member, durationNumber: int, durationIdentifier: str, *, reason=""): """mute_help""" if reason == "": reason = Translator.translate("no_reason", ctx.guild.id) roleid = Configuration.getConfigVar(ctx.guild.id, "MUTE_ROLE") if roleid is 0: await ctx.send(f"{Emoji.get_chat_emoji('WARNING')} {Translator.translate('mute_not_configured', ctx.guild.id, user=target.mention)}") else: role = discord.utils.get(ctx.guild.roles, id=roleid) if role is None: await ctx.send(f"{Emoji.get_chat_emoji('WARNING')} {Translator.translate('mute_role_missing', ctx.guild.id, user=target.mention)}") else: if (ctx.author != target and target != ctx.bot.user and ctx.author.top_role > target.top_role) or ctx.guild.owner == ctx.author: duration = Utils.convertToSeconds(durationNumber, durationIdentifier) if duration > 0: until = time.time() + duration await target.add_roles(role, reason=f"{reason}, as requested by {ctx.author.name}") if not str(ctx.guild.id) in self.mutes: self.mutes[str(ctx.guild.id)] = dict() self.mutes[str(ctx.guild.id)][str(target.id)] = until await ctx.send(f"{Emoji.get_chat_emoji('MUTE')} {Translator.translate('mute_confirmation', ctx.guild.id, user=Utils.clean_user(target), duration=f'{durationNumber} {durationIdentifier}')}") Utils.saveToDisk("mutes", self.mutes) await GearbotLogging.logToModLog(ctx.guild, f"{Emoji.get_chat_emoji('MUTE')} {Translator.translate('mute_log', ctx.guild.id, user=Utils.clean_user(target), user_id=target.id, moderator=Utils.clean_user(ctx.author), moderator_id=ctx.author.id, duration=f'{durationNumber} {durationIdentifier}', reason=reason)}") InfractionUtils.add_infraction(ctx.guild.id, target.id, ctx.author.id, "Mute", reason) else: await ctx.send(f"{Emoji.get_chat_emoji('WHAT')} {Translator.translate('mute_negative_denied', ctx.guild.id, duration=f'{durationNumber} {durationIdentifier}')} {Emoji.get_chat_emoji('WHAT')}") else: await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('mute_not_allowed', ctx.guild.id, user=target)}")
async def unmute(self, ctx: commands.Context, target: discord.Member, *, reason=""): """unmute_help""" if reason == "": reason = Translator.translate("no_reason", ctx.guild.id) roleid = Configuration.getConfigVar(ctx.guild.id, "MUTE_ROLE") if roleid is 0: await ctx.send( f"{Emoji.get_chat_emoji('NO')} The mute feature has been disabled on this server, as such i cannot unmute that person" ) else: role = discord.utils.get(ctx.guild.roles, id=roleid) if role is None: await ctx.send( f"{Emoji.get_chat_emoji('NO')} Unable to comply, the role i've been told to use for muting no longer exists" ) else: await target.remove_roles( role, reason=f"Unmuted by {ctx.author.name}, {reason}") await ctx.send( f"{Emoji.get_chat_emoji('INNOCENT')} {target.display_name} has been unmuted" ) await GearbotLogging.logToModLog( ctx.guild, f"{Emoji.get_chat_emoji('INNOCENT')} {target.name}#{target.discriminator} (`{target.id}`) has been unmuted by {ctx.author.name}" ) InfractionUtils.add_infraction(ctx.guild.id, target.id, ctx.author.id, "Unmute", reason)
async def logToModLog(guild, message=None, embed=None): modlog: discord.TextChannel = guild.get_channel( Configuration.getConfigVar(guild.id, "MOD_LOGS")) if modlog is not None: perms = modlog.permissions_for(guild.me) if perms.send_messages: await modlog.send(message, embed=embed)
def translate(key, location, **kwargs): if location is not None: if hasattr(location, "guild"): location = location.guild if location is not None and hasattr(location, "id"): lang_key = Configuration.getConfigVar(location.id, "LANG") else: lang_key = Configuration.getConfigVar(location, "LANG") else: lang_key = "en_US" if key in LANGS[lang_key].keys(): return LANGS[lang_key][key].format(**kwargs) else: if key in LANGS["en_US"].keys(): return LANGS["en_US"][key].format(**kwargs) return key
async def log_to_minor_log(guild, message=None, embed=None, file=None): minor_log: discord.TextChannel = guild.get_channel( Configuration.getConfigVar(guild.id, "MINOR_LOGS")) if minor_log is not None: perms = minor_log.permissions_for(guild.me) if perms.send_messages: await minor_log.send(message, embed=embed, file=file)
async def remove_admin_role(self, ctx, *, role: discord.Role): roles = Configuration.getConfigVar(ctx.guild.id, "ADMIN_ROLES") if role.id not in roles: await ctx.send(f"{Emoji.get_chat_emoji('NO')} `{role.name}` was not an admin role so i cannot remove it") else: roles.remove(role.id) Configuration.saveConfig(ctx.guild.id) await ctx.send(f"{Emoji.get_chat_emoji('YES')} `{role.name}` is no longer an admin role")
async def add_to_whitelist(self, ctx: commands.Context, server:int): current = Configuration.getConfigVar(ctx.guild.id, "INVITE_WHITELIST") if server in current: await ctx.send("This server is already whitelisted.") else: current.append(server) Configuration.setConfigVar(ctx.guild.id, "INVITE_WHITELIST", current) await ctx.send(f"Server {server} is now whitelisted.")
async def remove(self, ctx:commands.Context, role:discord.Role): current = Configuration.getConfigVar(ctx.guild.id, "SELF_ROLES") if role.id not in current: await ctx.send("This wasn't assignable.") else: current.remove(role.id) Configuration.setConfigVar(ctx.guild.id, "SELF_ROLES", current) await ctx.send(f"The {role.name} role is now no longer assignable.")
async def remove_from_whitelist(self, ctx: commands.Context, server:int): current = Configuration.getConfigVar(ctx.guild.id, "INVITE_WHITELIST") if server not in current: await ctx.send("This server was not whitelisted.") else: current.remove(server) Configuration.setConfigVar(ctx.guild.id, "INVITE_WHITELIST", current) await ctx.send(f"Server {server} is no longer whitelisted.")
async def addIgnoredUser(self, ctx:commands.Context, user:discord.Member): current = Configuration.getConfigVar(ctx.guild.id, "IGNORED_USERS") if user.id in current: await ctx.send("This user is already ignored.") else: current.append(user.id) Configuration.setConfigVar(ctx.guild.id, "IGNORED_USERS", current) await ctx.send("I will now no longer log this user's edited/deleted messages.")
async def add_mod_role(self, ctx, role: discord.Role): roles = Configuration.getConfigVar(ctx.guild.id, "MOD_ROLES") if role.id in roles: await ctx.send(f"{Emoji.get_chat_emoji('NO')} `{role.name}` is already a mod role") else: roles.append(role.id) Configuration.saveConfig(ctx.guild.id) await ctx.send(f"{Emoji.get_chat_emoji('YES')} `{role.name}` is now a mod role")
async def removeIgnoredUser(self, ctx:commands.Context, user:discord.User): current = Configuration.getConfigVar(ctx.guild.id, "IGNORED_USERS") if user.id not in current: await ctx.send("This user was not on my ignore list.") else: current.remove(user.id) Configuration.setConfigVar(ctx.guild.id, "IGNORED_USERS", current) await ctx.send("I will now no longer ignore this user's edited/deleted messages.")
async def mute(self, ctx:commands.Context): """Disable the mute feature""" role = discord.utils.get(ctx.guild.roles, id=Configuration.getConfigVar(ctx.guild.id, "MUTE_ROLE")) if role is not None: for member in role.members: await member.remove_roles(role, reason=f"Mute feature has been disabled") Configuration.setConfigVar(ctx.guild.id, "MUTE_ROLE", 0) await ctx.send("Mute feature has been disabled, all people muted have been unmuted and the role can now be removed.")
async def remove_command_override(self, ctx, command:str): overrides = Configuration.getConfigVar(ctx.guild.id, "COMMAND_OVERRIDES") if command in overrides: del overrides[command] Configuration.saveConfig(ctx.guild.id) await ctx.send(f"{Emoji.get_chat_emoji('YES')} Command override for {command} has been removed.") else: await ctx.send(f"{Emoji.get_chat_emoji('NO')} I don't have a command override for {command} to remove.")
async def add(self, ctx:commands.Context, role:discord.Role): current = Configuration.getConfigVar(ctx.guild.id, "SELF_ROLES") if role.id in current: await ctx.send("This role is already assignable.") else: current.append(role.id) Configuration.setConfigVar(ctx.guild.id, "SELF_ROLES", current) await ctx.send(f"The {role.name} role is now assignable.")
async def on_raw_message_edit(self, event: RawMessageUpdateEvent): if event.data["channel_id"] == Configuration.getMasterConfigVar( "BOT_LOG_CHANNEL"): return message = LoggedMessage.get_or_none(messageid=event.message_id) if message is not None and "content" in event.data: channel: discord.TextChannel = self.bot.get_channel( int(event.data["channel_id"])) user: discord.User = self.bot.get_user(message.author) hasUser = user is not None channelid = Configuration.getConfigVar(channel.guild.id, "MINOR_LOGS") if channelid is not 0: logChannel: discord.TextChannel = self.bot.get_channel( channelid) if logChannel is not None: if message.content == event.data["content"]: #prob just pinned return if message.content is None or message.content == "": message.content = f"<{Translator.translate('no_content', channel.guild.id)}>" embed = discord.Embed(timestamp=datetime.datetime. utcfromtimestamp(time.time())) embed.set_author( name=user.name if hasUser else message.author, icon_url=user.avatar_url if hasUser else EmptyEmbed) embed.set_footer( text=Translator.translate('sent_in', channel.guild.id, channel=f"#{channel.name}")) embed.add_field( name=Translator.translate('before', channel.guild.id), value=Utils.trim_message(message.content, 1024), inline=False) embed.add_field( name=Translator.translate('after', channel.guild.id), value=Utils.trim_message(event.data["content"], 1024), inline=False) if not (hasUser and user.id in Configuration.getConfigVar( channel.guild.id, "IGNORED_USERS")): await logChannel.send( f":pencil: {Translator.translate('edit_logging', channel.guild.id, user=Utils.clean_user(user), user_id=user.id, channel=channel.mention)}", embed=embed) message.content = event.data["content"] message.save()
async def minorLogChannel(self, ctx: commands.Context, channel: discord.TextChannel): """Sets the logging channel for minor logs (edit/delete)""" old = Configuration.getConfigVar(ctx.guild.id, "MINOR_LOGS") new = await set_log_channel(ctx, channel, "minor") if old == 0 and new: await ctx.send(Translator.translate('minor_log_caching_start', ctx)) self.bot.to_cache.append(ctx)
async def command_overrides(self, ctx): if ctx.invoked_subcommand is self.command_overrides: overrides = Configuration.getConfigVar(ctx.guild.id, "COMMAND_OVERRIDES") if len(overrides) == 0: desc = "No overrides" else: desc = "\n".join(f"{k}: {v} ({self.perm_lvls[v]})" for k, v in overrides.items()) embed = discord.Embed(color=6008770, title="Command overrides", description=desc) await ctx.send(embed=embed)
def is_dev(ctx: commands.Context): if ctx.guild is None: return False devrole = Configuration.getConfigVar(ctx.guild.id, "DEV_ROLE") if devrole != 0: for role in ctx.author.roles: if role.id == devrole: return True return is_admin(ctx)
def prefix_callable(bot, message): user_id = bot.user.id prefixes = [f'<@!{user_id}> ', f'<@{user_id}> '] #execute commands by mentioning if message.guild is None or not bot.STARTUP_COMPLETE: prefixes.append('!') #use default ! prefix in DMs else: prefixes.append(Configuration.getConfigVar(message.guild.id, "PREFIX")) return prefixes
async def add_command_override(self, ctx, command: str, perm_lvl: int): command_object = self.bot.get_command(command) if command_object is not None: cog = command_object.instance cog_name = command_object.cog_name if not hasattr(cog, "permissions"): await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('command_core_cog_no_override', ctx, command=command, cog_name=cog_name)}" ) elif perm_lvl in range(7): perm_dict = Permissioncheckers.get_perm_dict( command.split(" "), cog.permissions) if perm_lvl < perm_dict["min"]: lvl = cog.permissions['min'] await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('command_min_perm_violation', ctx, command=command, min_lvl=lvl, min_lvl_name=Translator.translate(f'perm_lvl_{lvl}', ctx))}" ) elif perm_lvl > perm_dict["max"]: lvl = cog.permissions['max'] await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('command_max_perm_violation', ctx, command=command, max_lvl=lvl, max_lvl_name=Translator.translate(f'perm_lvl_{lvl}', ctx))}" ) else: overrides = Configuration.getConfigVar( ctx.guild.id, "PERM_OVERRIDES") if cog_name not in overrides: overrides[cog_name] = { "required": perm_lvl, "commands": {}, "people": [] } override = overrides[cog_name] parts = command.split(" ") while len(parts) > 0: part = parts.pop(0) if not part in override["commands"]: override["commands"][part] = override = { "required": -1, "commands": {}, "people": [] } else: override = override["commands"][part] override["required"] = perm_lvl Configuration.saveConfig(ctx.guild.id) await ctx.send( f"{Emoji.get_chat_emoji('YES')} {Translator.translate('command_override_confirmation', ctx, command=command, perm_lvl=perm_lvl, perm_lvl_name=Translator.translate(f'perm_lvl_{perm_lvl}', ctx))}" ) else: await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('invalid_override_lvl', ctx)}" ) else: await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('command_not_found', ctx)}" )
async def modroles(self, ctx: commands.Context): """Show or configure server mod roles""" if ctx.invoked_subcommand is self.modroles: roles = Configuration.getConfigVar(ctx.guild.id, "MOD_ROLES") if len(roles) == 0: desc = "No mod roles configured" else: desc = "\n".join(f"<@&{role}>" for role in roles) embed = discord.Embed(title="Current admin roles", description=desc) await ctx.send(embed=embed)
def check_permission(ctx: commands.Context): overrides = Configuration.getConfigVar(ctx.guild.id, "PERM_OVERRIDES") cog_name = type(ctx.cog).__name__ required = -1 if cog_name in overrides: required = get_required(ctx, overrides[cog_name]) if required == -1: required = get_required(ctx, ctx.cog.permissions) return get_user_lvl(ctx) >= (ctx.cog.permissions["required"] if required == -1 else required)
def is_user(perm_type, ctx): if ctx.guild is None: return False if not hasattr(ctx.author, "roles"): return False roles = Configuration.getConfigVar(ctx.guild.id, f"{perm_type}_ROLES") for role in ctx.author.roles: if role.id in roles: return True return False
async def on_member_unban(self, guild, user): if user.id in self.bot.data["unbans"]: return channelid = Configuration.getConfigVar(guild.id, "MOD_LOGS") if channelid is not 0: logChannel: discord.TextChannel = self.bot.get_channel(channelid) if logChannel is not None: await logChannel.send( f":rotating_light: {user.name}#{user.discriminator} (`{user.id}`) has been unbanned from the server." )