async def convert(self, ctx, argument): channels = Configuration.get_var(ctx.guild.id, "LOG_CHANNELS") match = CHANNEL_ID_MATCHER.match(argument) if match is not None: argument = match.group(1) if argument not in channels: raise TranslatedBadArgument('no_log_channel', ctx, arg=argument) return argument
async def raid_status(self, ctx): raid_settings = Configuration.get_var(ctx.guild.id, "RAID_HANDLING") if len(raid_settings.get('SHIELDS', [])) == 0: await MessageUtils.send_to(ctx, 'WRENCH', 'raid_shields_not_configured') elif raid_settings['ENABLED']: await MessageUtils.send_to(ctx, 'WRENCH', 'raid_shields_is_enabled') else: await MessageUtils.send_to(ctx, 'WRENCH', 'raid_shields_is_disabled')
async def remove_cog_override(self, ctx, cog: str): overrides = Configuration.get_var(ctx.guild.id, "PERM_OVERRIDES") if cog in overrides: overrides[cog]["required"] = -1 Configuration.save(ctx.guild.id) await ctx.send(f"{Emoji.get_chat_emoji('YES')} {Translator.translate('cog_override_removed', ctx, cog=cog)}") else: await ctx.send(f"{Emoji.get_chat_emoji('NO')} {Translator.translate('cog_override_not_found', ctx, cog=cog)}")
async def mute(self, member): role = member.guild.get_role( Configuration.get_var(member.guild.id, "MUTE_ROLE")) if role is not None: try: await member.add_roles(role, reason="Raid alarm triggered") except discord.HTTPException: Logging.warn(f"failed to mute {member} ({member.id}!")
def is_exempt(guild_id, member: Member): if not hasattr(member, "roles"): return False config = Configuration.get_var(guild_id, "ANTI_SPAM") for role in member.roles: if role.id in config["EXEMPT_ROLES"]: return True return member.id in config["EXEMPT_USERS"] or Permissioncheckers.is_mod(member)
async def ignored_channels_edits_remove(self, ctx, channel: TextChannel): """ignored_channels_remove_help""" channels = Configuration.get_var(ctx.guild.id, 'IGNORED_CHANNELS_OTHER') if not channel.id in channels: await MessageUtils.send_to(ctx, 'NO', 'ignored_channels_not_on_list') else: channels.append(channel.id) await MessageUtils.send_to(ctx, 'YES', 'ignored_channels_edits_removed', channel=channel.mention)
async def on_message(self, message: Message): if message.author.id == self.bot.user.id or message.guild is None: return # Don't track anti-spam for ourselves or DMs cfg = Configuration.get_var(message.guild.id, "ANTI_SPAM") if not cfg.get("ENABLED", False) or message.id in self.processed: return self.processed.append(message.id) await self.process_message(message)
def log_key(guild_id, key, embed=None, file=None, can_stamp=True, tag_on=None, timestamp=datetime.now(), **kwargs): # logging category, emoji and info = LOG_TYPES[key] # determine where it should be logged so we don't need to bother assembling everything when it's just gona be voided anyways targets = [] channels = Configuration.get_var(guild_id, "LOG_CHANNELS") for cid, settings in channels.items(): if info.category in settings[ "CATEGORIES"] and info.config_key not in settings[ "DISABLED_KEYS"]: targets.append(cid) # no targets? don't bother with assembly if len(targets) == 0: return message = MessageUtils.assemble(guild_id, info.emoji, key, **kwargs).replace('@', '@\u200b') if can_stamp and Configuration.get_var(guild_id, 'GENERAL', "TIMESTAMPS"): s = datetime.strftime( timestamp.now().astimezone( pytz.timezone( Configuration.get_var(guild_id, 'GENERAL', 'TIMEZONE'))), '%H:%M:%S') stamp = f"[`{s}`] " message = Utils.trim_message(f'{stamp} {message}', 2000) if tag_on is not None: tag_on = tag_on.replace('@', '@\u200b') if tag_on is not None and len(message) + len(tag_on) <= 1998: message = f"{message} {tag_on}" tag_on = None message = Utils.trim_message(message, 2000) # queuing up log_to(guild_id, targets, message, embed, file, tag_on)
async def mute(self, ctx:commands.Context): """Disable the mute feature""" role = ctx.guild.get_role(Configuration.get_var(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.set_var(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 blacklist_remove(self, ctx, *, word: str): blacklist = Configuration.get_var(ctx.guild.id, "WORD_BLACKLIST") if word not in blacklist: await MessageUtils.send_to(ctx, "NO", "not_blacklisted", word=word) else: blacklist.remove(word) await MessageUtils.send_to(ctx, "YES", "entry_removed", entry=word) Configuration.save(ctx.guild.id)
async def ignored_channels_changes_add(self, ctx, channel:TextChannel): """ignored_channels_add_help""" channels = Configuration.get_var(ctx.guild.id, 'IGNORED_CHANNELS_CHANGES') if channel.id in channels: await MessageUtils.send_to(ctx, 'NO', 'ignored_channels_already_on_list') else: channels.append(channel.id) await MessageUtils.send_to(ctx, 'YES', 'ignored_channels_changes_added', channel=channel.mention)
async def blacklist_add(self, ctx, *, word: str): blacklist = Configuration.get_var(ctx.guild.id, "CENSORING", "TOKEN_BLACKLIST") if word.lower() in blacklist: await MessageUtils.send_to(ctx, "NO", "already_blacklisted", word=word) else: blacklist.append(word.lower()) await MessageUtils.send_to(ctx, "YES", "entry_added", entry=word) Configuration.save(ctx.guild.id)
def get_features_status(ctx): enabled = f"{Emoji.get_chat_emoji('YES')} {Translator.translate('enabled', ctx)}" disabled = f"{Emoji.get_chat_emoji('NO')} {Translator.translate('disabled', ctx)}" embed = discord.Embed(color=6008770, title=Translator.translate('features', ctx)) for f, t in Features.requires_logging.items(): e = Configuration.get_var(ctx.guild.id, f) embed.add_field(name=f, value=enabled if e else disabled) return embed
async def list_list(ctx, item_type, list_name="roles", wrapper="<@&{item}>"): items = Configuration.get_var(ctx.guild.id, f"{item_type}_{list_name}".upper()) if len(items) == 0: desc = Translator.translate(f"no_{item_type}_{list_name}", ctx) else: desc = "\n".join(wrapper.format(item=item) for item in items) embed = discord.Embed(title=Translator.translate(f"current_{item_type}_{list_name}", ctx), description=desc) await ctx.send(embed=embed)
def is_dev(ctx: commands.Context): if ctx.guild is None: return False devrole = Configuration.get_var(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 log_raw(guild_id, location, message=None, embed=None, file=None): channels = Configuration.get_var(guild_id, "LOG_CHANNELS") if message is None and embed is None and file is None: raise ValueError("What the heck is trying to log nothing?") if message is not None: message = Utils.trim_message(message, 1998) for cid, info in channels.items(): if location in info: LOG_PUMP.receive(cid, (message, embed, file))
async def on_command_error(bot, ctx: commands.Context, error): if isinstance(error, NotCachedException): if bot.initial_fill_complete: await ctx.send( f"{Emoji.get_chat_emoji('CLOCK')} GearBot only just joined this guild and is still receiving the initial member info for this guild, please try again in a few seconds" ) else: await ctx.send( f"{Emoji.get_chat_emoji('CLOCK')} GearBot is in the process of starting up and has not received the member info for this guild. Please try again in a few minutes." ) if isinstance(error, commands.BotMissingPermissions): GearbotLogging.error( f"Encountered a permission error while executing {ctx.command}: {error}" ) await ctx.send(error) elif isinstance(error, commands.CheckFailure): if ctx.command.qualified_name is not "latest" and ctx.guild is not None and Configuration.get_var( ctx.guild.id, "GENERAL", "PERM_DENIED_MESSAGE"): await MessageUtils.send_to(ctx, 'LOCK', 'permission_denied') elif isinstance(error, commands.CommandOnCooldown): await ctx.send(error) elif isinstance(error, commands.MissingRequiredArgument): param = list(ctx.command.params.values())[min( len(ctx.args) + len(ctx.kwargs), len(ctx.command.params))] bot.help_command.context = ctx await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('missing_arg', ctx, arg=param._name, error=Utils.replace_lookalikes(str(error)))}\n{Emoji.get_chat_emoji('WRENCH')} {Translator.translate('command_usage', ctx, usage=bot.help_command.get_command_signature(ctx.command))}" ) elif isinstance(error, PostParseError): bot.help_command.context = ctx await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('bad_argument', ctx, type=error.type, error=Utils.replace_lookalikes(str(error.error)))}\n{Emoji.get_chat_emoji('WRENCH')} {Translator.translate('command_usage', ctx, usage=bot.help_command.get_command_signature(ctx.command))}" ) elif isinstance(error, commands.BadArgument): param = list(ctx.command.params.values())[min( len(ctx.args) + len(ctx.kwargs), len(ctx.command.params))] bot.help_command.context = ctx await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('bad_argument', ctx, type=param._name, error=Utils.replace_lookalikes(str(error)))}\n{Emoji.get_chat_emoji('WRENCH')} {Translator.translate('command_usage', ctx, usage=bot.help_command.get_command_signature(ctx.command))}" ) elif isinstance(error, commands.CommandNotFound): return elif isinstance(error, PeeweeException): await handle_database_error(bot) else: await handle_exception( "Command execution failed", bot, error.original if hasattr(error, "original") else error, ctx=ctx) # notify caller e = Emoji.get_chat_emoji('BUG') if ctx.channel.permissions_for(ctx.me).send_messages: await ctx.send( f"{e} Something went wrong while executing that command. If this keeps happening please report it on support server (DM me ``!about`` or check the website for an invite) {e}" )
def can_remove(self, guild, logging): counts = dict() for cid, info in Configuration.get_var(guild, "LOG_CHANNELS").items(): for i in info: if i not in counts: counts[i] = 1 else: counts[i] +=1 return logging not in Features.requires_logging.values() or (logging in counts and counts[logging] > 1) or Configuration.get_var("MESSAGE_LOGS" if logging == "EDIT_LOGS" else "CENSORING", "ENABLED", False)
async def on_message(self, message: discord.Message): if not hasattr(message.channel, "guild") or message.channel.guild is None: return if Configuration.get_var(message.guild.id, "EDIT_LOGS"): LoggedMessage.create(messageid=message.id, author=message.author.id, content=message.content, channel=message.channel.id, server=message.guild.id) for a in message.attachments: LoggedAttachment.create(id=a.id, url=a.url, isImage=(a.width is not None or a.width is 0), messageid=message.id)
def can_remove(self, guild, logging): counts = dict() for cid, info in Configuration.get_var(guild, "LOG_CHANNELS").items(): for i in info: if i not in counts: counts[i] = 1 else: counts[i] +=1 return logging not in Features.requires_logging.values() or (logging in counts and counts[logging] > 1)
async def logging(self, ctx): if ctx.invoked_subcommand is self.logging: embed = discord.Embed(color=6008770, title=Translator.translate('log_channels', ctx)) channels = Configuration.get_var(ctx.guild.id, "LOG_CHANNELS") if len(channels) > 0: for cid, info in channels.items(): embed.add_field(name=cid, value=self.get_channel_properties(ctx, cid, info)) await ctx.send(embed=embed)
async def list_channels(ctx, type): channel_list = Configuration.get_var(ctx.guild.id, f'IGNORED_CHANNELS_{type.upper()}') if len(channel_list) > 0: channels = "\n".join(ctx.guild.get_channel(c).mention for c in channel_list) else: channels = Translator.translate('no_ignored_channels', ctx) embed = discord.Embed(color=ctx.guild.roles[-1].color, description=channels) embed.set_author(name=Translator.translate(f'ignored_channels_list_{type}', ctx, guild=ctx.guild.name), icon_url=ctx.guild.icon_url) await ctx.send(embed=embed)
async def ignored_channels_changes_remove(self, ctx, channel: TextChannel): """ignored_channels_remove_help""" channels = Configuration.get_var(ctx.guild.id, "MESSAGE_LOGS", 'IGNORED_CHANNELS_CHANGES') if not channel.id in channels: await MessageUtils.send_to(ctx, 'NO', 'ignored_channels_not_on_list', channel=channel.mention) else: channels.remove(channel.id) await MessageUtils.send_to(ctx, 'YES', 'ignored_channels_changes_removed', channel=channel.mention) Configuration.save(ctx.guild.id)
async def on_guild_channel_delete(self, channel): changed = False for name in ["IGNORED_CHANNELS_CHANGES", "IGNORED_CHANNELS_OTHER"]: channels = Configuration.get_var(channel.guild.id, name) if channel.id in channels: channels.remove(channel.id) changed = True if changed: Configuration.save(channel.guild.id)
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: prefixes.append('!') #use default ! prefix in DMs elif bot.STARTUP_COMPLETE: prefixes.append(Configuration.get_var(message.guild.id, "PREFIX")) return prefixes
def is_user(perm_type, member): if not hasattr(member, "guild") or member.guild is None: return False if not hasattr(member, "roles"): return False roles = Configuration.get_var(member.guild.id, "PERMISSIONS", f"{perm_type}_ROLES") users = Configuration.get_var(member.guild.id, "PERMISSIONS", f"{perm_type}_USERS") if member.id in users: return True for role in member.roles: if role.id in roles: return True return False
async def process_message(self, message: Message): # print(f'{datetime.datetime.now().isoformat()} - Processing message') if message.webhook_id is not None or self.is_exempt( message.guild.id, message.author): return # Use the discord's message timestamp to hopefully not trigger false positives msg_time = int(message.created_at.timestamp()) * 1000 async def check_bucket(check, friendly_text, amount, b): # print(f"{check} - {amount}") if amount == 0: return bucket = self.get_bucket(message.guild.id, check, b, message.author.id) if bucket is not None and await bucket.check( message.author.id, msg_time, amount, f"{message.channel.id}-{message.id}"): count = await bucket.count(message.author.id, msg_time, expire=False) period = await bucket.size( message.author.id, msg_time, expire=False) / 1000 self.bot.loop.create_task( self.violate( Violation( check, message.guild, f"{friendly_text} ({count}/{period}s)", message.author, message.channel, await bucket.get(message.author.id, msg_time, expire=False), b, count))) counters = dict() buckets = Configuration.get_var(message.guild.id, "ANTI_SPAM", "BUCKETS", []) # so if someone does 20 levels of too many mentions for some stupid reason we don't end up running the same regex 20 times for nothing cache = dict() for bucket in buckets: t = bucket["TYPE"] counter = counters.get(t, 0) if t == "duplicates": await self.check_duplicates(message, counter, bucket) else: v = 0 if t in cache: v = cache[t] elif t in self.generators: v = self.generators[t](message) cache[t] = v if v is not 0: await check_bucket( f"{t}:{counter}", Translator.translate(f"spam_{t}", message), v, bucket)
def gen_role_pages(self, guild: discord.Guild): roles = Configuration.get_var(guild.id, "SELF_ROLES") current_roles = "" count = 1 for role in roles: current_roles += f"{count}) <@&{role}>\n\n" count += 1 if count > 10: count = 1 return Pages.paginate(current_roles, max_lines=20)
async def _warn(self, ctx, target, *, reason, message=True, dm_action=True): i = await InfractionUtils.add_infraction(ctx.guild.id, target.id, ctx.author.id, "Warn", reason) name = Utils.clean_user(target) if message: await MessageUtils.send_to(ctx, 'YES', 'warning_added', user=name, inf=i.id) aname = Utils.clean_user(ctx.author) GearbotLogging.log_key(ctx.guild.id, 'warning_added_modlog', user=name, moderator=aname, reason=reason, user_id=target.id, moderator_id=ctx.author.id, inf=i.id) if Configuration.get_var(ctx.guild.id, "INFRACTIONS", "DM_ON_WARN") and dm_action: await Utils.send_infraction(self.bot, target, ctx.guild, 'WARNING', 'warn', reason)
async def get_guild_settings(self, message): section = Configuration.get_var(int(message["guild_id"]), message["section"]) section = { k: [str(rid) if isinstance(rid, int) else rid for rid in v] if isinstance(v, list) else str(v) if isinstance(v, int) and not isinstance(v, bool) else v for k, v in section.items() } return section