async def _command(self, ctx: commands.Context, *, item): new_item = ... for converter in converters: with contextlib.suppress(commands.BadArgument): new_item = await converter().convert(ctx, item) break if new_item is ...: raise commands.BadArgument item = getattr(item, "id", item) # noinspection PyTypeChecker async with DummyModule().config.guild( ctx.guild).ignore.get_attr(conf_opt)() as ignored: if remove is False: if item in ignored: await ctx.send( warning( i18n("That item is already currently being ignored" ))) return ignored.append(item) else: if item not in ignored: await ctx.send( warning( i18n("That item is not currently being ignored"))) return ignored.remove(item) log.debug("{} {!r} to/from {!r} {} ignore list".format( name, new_item, ctx.guild, conf_opt)) await ctx.tick()
async def _add_remove(self, ctx: commands.Context, role: discord.Role, *, rm: bool = False): if role.is_default(): raise commands.BadArgument( "cannot make a server's default role mentionable") async with self.config.guild(ctx.guild).roles() as roles: if rm is False: if role.id in roles: await ctx.send( warning(_("That role is already mentionable"))) return roles.append(role.id) else: if role.id not in roles: await ctx.send( warning(_("That role is not currently mentionable"))) return roles.remove(role.id) await ctx.send( escape( tick( _("`{}` is now allowed to be mentioned").format(role. name)), mass_mentions=True, ) if rm is False else escape( tick( _("`{}` is no longer allowed to be mentioned"). format(role.name)), mass_mentions=True, ))
async def create(self, ctx): """Create personal role if you don't have one already""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) if not role: pos = await self.config.guild(ctx.guild).position_role() pos = ctx.guild.get_role(pos) pos = pos.position if pos else 1 try: role = await ctx.guild.create_role(name=str(ctx.author), colour=ctx.author.colour, reason=_("Personal role")) await asyncio.sleep(0.3) await role.edit(position=pos) await asyncio.sleep(0.3) await ctx.author.add_roles(role, reason=_("Personal Roles")) await self.config.member(ctx.author).role.set(role.id) await self.config.member(ctx.author).auto_role.set(True) except: await ctx.send( chat.warning( "Could not create your personal role, please contact an admin." )) return await ctx.send( f"Role created! You can edit it using `{ctx.prefix}myrole name` and `{ctx.prefix}myrole colour` commands." ) else: await ctx.send(chat.warning("You already have a personal role!"))
async def cogwhitelist_remove(self, ctx: commands.Context, cog: str, guild_id: int = None): """Removes a cog or guild from the list of whitelisted cogs/guilds If a guild ID is specified, it's removed from the specified cogs' list of allowed guilds """ cog = cog.lower() proper_name = cog_name(self.bot, cog) or cog async with self.config.cogs() as cogs: if cog not in cogs: return await fmt( ctx, warning(_("**{cog}** doesn't currently require a whitelist to use")), cog=proper_name, ) if guild_id: if guild_id not in cogs[cog]: return await fmt( ctx, warning(_("That guild isn't allowed to use **{cog}**")), cog=proper_name, ) cogs[cog].remove(guild_id) await fmt( ctx, tick(_("That guild is no longer allowed to use **{cog}**.")), cog=proper_name, ) else: cogs.pop(cog) await fmt( ctx, tick(_("**{cog}** no longer requires a whitelist to use")), cog=proper_name )
async def stars_unignore(self, ctx: Context, name: str, *, reason: str = None): """Remove a channel or member from the server's ignore list `reason` is only used if unignoring a member """ item = await resolve_any(ctx, name, commands.TextChannelConverter, commands.MemberConverter) if isinstance(item, discord.Member) and not await hierarchy_allows( self.bot, ctx.author, item): await ctx.send( error( i18n( "You aren't allowed to remove that member from the ignore list" ))) return elif (isinstance(item, discord.TextChannel) and item == await ctx.starboard.resolve_starboard()): await ctx.send( warning( i18n( "The starboard channel is always ignored and cannot be manually " "ignored nor unignored."))) return if not await ctx.starboard.is_ignored(item): await ctx.send( warning( i18n( "That user is not already ignored from using this server's starboard" ) if isinstance(item, discord.Member) else i18n( "That channel is not already being ignored"))) return await ctx.starboard.unignore(item) await ctx.send( tick( i18n("**{}** is no longer ignored from this server's starboard" )).format(item)) if isinstance(item, discord.Member): try: await modlog.create_case( bot=self.bot, guild=ctx.guild, created_at=ctx.message.created_at, action_type="starboardunblock", user=item, moderator=ctx.author, reason=reason, until=None, channel=None, ) except RuntimeError: pass
async def quote_message(self, ctx: commands.Context, message: int, channel: discord.TextChannel = None): channel = channel or ctx.channel try: message = await channel.get_message(message) except discord.NotFound: await ctx.send(warning(translate("message_not_found"))) except discord.Forbidden: await ctx.send(warning(translate("message_forbidden"))) else: quote = await Quote.create(message.content, ctx.author, message.author) await ctx.send(tick(translate("quote_added")), embed=quote.embed)
async def getuserinfo(self, ctx, user_id: int): """Get info about any discord's user by ID""" try: user = await self.bot.get_user_info(user_id) except discord.errors.NotFound: await ctx.send( chat.error("Discord user with ID `{}` not found").format( user_id)) return except discord.errors.HTTPException: await ctx.send( chat.warning( "Bot was unable to get data about user with ID `{}`. " "Try again later".format(user_id))) return embed = discord.Embed(title=str(user), timestamp=user.created_at, color=await ctx.embed_color()) embed.add_field(name="ID", value=user.id) embed.add_field(name="Bot?", value=bool_emojify(user.bot)) embed.add_field(name="Mention", value=user.mention) embed.add_field(name="Default avatar", value="[{}]({})".format(user.default_avatar, user.default_avatar_url)) if user.avatar: embed.add_field(name="Avatar", value="[`{}`]({})".format( user.avatar, user.avatar_url_as(static_format="png", size=2048))) embed.set_image(url=user.avatar_url_as(static_format="png", size=2048)) embed.set_thumbnail(url=user.default_avatar_url) embed.set_footer(text="Created at") await ctx.send(embed=embed)
async def icon_reset(self, ctx): """Remove icon of personal role""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) if not role: await ctx.send( chat.warning( f"Please create your role using `{ctx.prefix}myrole create`!" )) return try: await edit_role_icon( self.bot, role, icon=None, unicode_emoji=None, reason=get_audit_reason(ctx.author, _("Personal Role")), ) await ctx.send( _("Removed icon of {user}'s personal role").format( user=ctx.message.author.name)) except discord.Forbidden: ctx.command.reset_cooldown(ctx) await ctx.send( chat.error( _("Unable to edit role.\nRole must be lower than my top role" ))) except discord.HTTPException as e: ctx.command.reset_cooldown(ctx) await ctx.send(chat.error(_("Unable to edit role: {}").format(e)))
async def name(self, ctx, *, name: str): """Change name of personal role You can't use blacklisted names Names must be 30 characters or less""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) if not role: await ctx.send( chat.warning( f"Please create your role using `{ctx.prefix}myrole create`!" )) return name = name[:30] if name.casefold() in await self.config.guild(ctx.guild).blacklist(): await ctx.send(chat.error(_("This rolename is blacklisted."))) return try: await role.edit(name=name, reason=get_audit_reason(ctx.author, _("Personal Role"))) except discord.Forbidden: ctx.command.reset_cooldown(ctx) await ctx.send( chat.error( _("Unable to edit role.\n" 'Role must be lower than my top role and i must have permission "Manage Roles"' ))) except discord.HTTPException as e: ctx.command.reset_cooldown(ctx) await ctx.send(chat.error(_("Unable to edit role: {}").format(e))) else: await ctx.send( _("Changed name of {user}'s personal role to {name}").format( user=ctx.message.author.name, name=name))
async def requirerole(self, ctx: commands.Context, *roles: RoleTuple): """Require one of any specific roles to use the bot in the current guild To require a member to __not__ have one or more roles, you can use `~` before the role name to treat it as a blacklisted role. If a role name has `~` at the start of it's name, you can escape it with a backslash (`\`) character. Blacklisted roles override any possible whitelisted roles a member may have. Role names are case sensitive. If a role has spaces in it's name, wrap it in quotes. Passing no roles removes any currently set role requirements. The guild owner and members with the Administrator permission always bypass these requirements, regardless of roles.""" seen = SeenSet() roles = tuple( (k, v) for k, v in roles if seen.mark_seen(k)) # type: Tuple[Tuple[discord.Role, bool]] whitelist = tuple(r for r, v in roles if v) # type: Tuple[discord.Role] blacklist = tuple(r for r, v in roles if not v) # type: Tuple[discord.Role] if ctx.guild.default_role in roles: await ctx.send( warning( _("I can't set a role requirement with the guild's default role - " "if you'd like to clear your current role requirements, " "you can execute this command with no arguments to do so." ))) return await self.config.guild(ctx.guild).roles.set({ "whitelist": [x.id for x in whitelist], "blacklist": [x.id for x in blacklist] }) if not roles: await ctx.send(tick(_("Cleared currently set role requirements."))) return whitelist = ", ".join( escape(str(x), mass_mentions=True, formatting=True) for x in whitelist) blacklist = ", ".join( escape(str(x), mass_mentions=True, formatting=True) for x in blacklist) msg = _( "A member will now need to pass the following checks to use my commands:\n\n" ) if whitelist: msg += _("**Any of the following roles:**\n{roles}").format( roles=whitelist) if whitelist and blacklist: msg += "\n\n" if blacklist: msg += _("**None of the following roles:**\n{roles}").format( roles=blacklist) await ctx.send(tick(msg))
async def logset_channel(self, ctx: commands.Context, module: str, channel: discord.TextChannel = None): """Set the log channel for a module Passing no log channel effectively acts as disabling the module """ module = await retrieve_module(ctx, module) if channel and not channel.permissions_for(ctx.guild.me).send_messages: await ctx.send( warning(i18n("I'm not able to send messages in that channel"))) return await module.module_config.set_raw("_log_channel", value=getattr(channel, "id", None)) if channel: await ctx.send( tick( i18n("Module **{module}** will now log to {channel}"). format(module=module.friendly_name, channel=channel.mention))) else: await ctx.send( tick( i18n( "The log channel for module **{module}** has been cleared" ).format(module=module.friendly_name)))
async def starboard_minstars(self, ctx: Context, stars: int): """Set the amount of stars required for a message to be sent to this server's starboard""" if stars < 1: await ctx.send( warning(i18n("The amount of stars must be a non-zero number"))) return if stars > len([x for x in ctx.guild.members if not x.bot]): await ctx.send( warning( i18n( "There aren't enough members in this server to reach" " the given amount of stars. Maybe try a lower number?" ))) return await ctx.starboard.min_stars.set(stars) await ctx.tick()
async def process_rule_agreement_reaction(self, member: discord.Member, emoji: str, add: bool): """ Handles the rule agreement reaction """ if emoji.startswith("\N{THUMBS UP SIGN}"): if add: msg = ( f"Thank you for agreeing to the rules of {member.guild.name}.\n" "You have now been granted full access to the server." ) action = "added" await member.add_roles(self.roles["reader"]["obj"]) else: msg = ( f"It is unfortunate that you can no longer agree to the rules of {member.guild.name}.\n" "Your access to the server has been restricted.\n" "If you decide to agree to the rules in the future, your access will be restored." ) action = "removed" await member.remove_roles(self.roles["reader"]["obj"]) await self.log.send(f"`{member.name}` {action} `reader` role.") with contextlib.suppress(discord.HTTPException): # we don't want blocked DMs preventing the function working await member.send(msg) else: await self.log.send(warning(f"`{member.name}` tried to add a role but used the wrong emoji."))
async def greetRemove(self, ctx: Context, name: str): """ Remove a greeting Parameters: ----------- name: name of the greeting to remove """ def check(message: discord.Message): return message.author == ctx.message.author and message.channel == ctx.message.channel greetings = await self.config.guild(ctx.guild).greetings() if name in greetings: await ctx.send( warning("Are you sure you wish to delete this greeting? Respond with 'yes' if yes") ) try: response = await self.bot.wait_for("message", timeout=30.0, check=check) except asyncio.TimeoutError: await ctx.send("You took too long, not deleting") return if response.content.lower() != "yes": await ctx.send("Not deleting") return # delete the greeting del greetings[name] await ctx.send(f"{name} removed from list") await self.config.guild(ctx.guild).greetings.set(greetings) else: ctx.send(f"{name} not in list of greetings") return
async def cleanup_users(self, ctx, days: int = 1): """Cleanup inactive server members""" if days > 30: await ctx.send( chat.info( _("Due to Discord Restrictions, you cannot use more than 30 days for that cmd." ))) days = 30 elif days <= 0: await ctx.send(chat.info(_('"days" arg cannot be less than 1...'))) days = 1 to_kick = await ctx.guild.estimate_pruned_members(days=days) await ctx.send( chat.warning( _("You about to kick **{to_kick}** inactive for **{days}** days members from this server. " 'Are you sure?\nTo agree, type "yes"').format( to_kick=to_kick, days=days))) pred = MessagePredicate.yes_or_no(ctx) try: await self.bot.wait_for("message", check=pred, timeout=30) except AsyncTimeoutError: pass if pred.result: cleanup = await ctx.guild.prune_members(days=days, reason=get_audit_reason( ctx.author)) await ctx.send( chat.info( _("**{removed}**/**{all}** inactive members removed.\n" "(They was inactive for **{days}** days)").format( removed=cleanup, all=to_kick, days=days))) else: await ctx.send(chat.error(_("Inactive members cleanup canceled.")))
async def rndactivity_list(self, ctx: commands.Context): statuses = list(await self.config.statuses()) if not statuses: return await ctx.send( warning(translate("no_setup_statuses", prefix=ctx.prefix))) pages = [] for status in statuses: index = statuses.index(status) + 1 game_type = 0 stream_url = None if isinstance(status, dict): game_type = status.get("type", 0) stream_url = status.get("url") status = status.get("game") status = escape(status, formatting=True, mass_mentions=True) if stream_url: status = f"[{status}]({stream_url})" pages.append( f"**#{index}** \N{EM DASH} **{translate('game_type')[game_type]}** {status}" ) colour = await ctx.embed_colour() pages = [ discord.Embed(colour=colour, description=x) for x in pagify("\n".join(pages)) ] await PaginatedMenu(pages=pages, bot=ctx.bot, channel=ctx.channel, member=ctx.author).prompt()
async def channel_delete(self, ctx: commands.Context, *, channel: Union[discord.TextChannel, discord.VoiceChannel]): """Remove a channel from server Example: `[p]channel delete channel` """ self.check_channel_permission(ctx, channel) pred = MessagePredicate.yes_or_no(ctx) if not ctx.assume_yes: await ctx.send( chat.warning( _("You are about to delete channel {channel}. This cannot be undone. Are you sure?\n" 'To agree, type "yes"').format(channel=channel.mention))) try: await self.bot.wait_for("message", check=pred, timeout=30) except AsyncTimeoutError: pass if ctx.assume_yes or pred.result: try: await channel.delete(reason=get_audit_reason(ctx.author)) except discord.Forbidden: await ctx.send(chat.error(_("I can't delete this channel"))) except discord.HTTPException as e: await ctx.send( chat.error( _("I am unable to delete a channel: {}").format(e))) else: await ctx.tick()
async def allsfx(self, ctx): """Sends a list of every sound in a PM.""" # await self.bot.type() server = ctx.message.guild serverid = str(server.id) if serverid not in os.listdir(self.sound_base): os.makedirs(os.path.join(self.sound_base, serverid)) if serverid not in self.settings: self.settings[serverid] = {} self.save_json(self.settings_path, self.settings) strbuffer = self._list_sounds(serverid) if len(strbuffer) == 0: await ctx.send(cf.warning( "No sounds found. Use `{}addsfx` to add one.".format( ctx.prefix))) return mess = "```" for line in strbuffer: if len(mess) + len(line) + 4 < 2000: mess += "\n" + line else: mess += "```" await ctx.send(mess) mess = "```" + line if mess != "": mess += "```" await ctx.send(mess)
async def rndactivity_add(self, ctx: commands.Context, game_type: Optional[ActivityTypeConverter], *, game: str): stream = None if game_type is None: game_type = discord.ActivityType.playing elif game_type == discord.ActivityType.streaming: game = game.split(" ") stream, game = game.pop(), " ".join(game) if not TWITCH_REGEX.match(stream): raise commands.BadArgument(translate("no_stream_provided")) activity = { "type": game_type.value, "game": game, "url": stream.strip("<>") if stream else None, } try: self.format_status(activity, error_deprecated=True) except KeyError as e: await ctx.send( warning( translate("parse_fail_invalid_placeholder", placeholder=str(e)))) else: async with self.config.statuses() as statuses: statuses.append(activity) await ctx.send( tick(translate("added_status", id=len(statuses))))
async def logging_level_setter(self, ctx: commands.Context, logging_level: int): """ Set the logging level of the cog. The logging level must be an integrer between 1 and 5. The lowest the logging level is, the more alert you will receive in your bot's log. 1 - DEBUG 2 - INFO 3 - WARNING 4 - ERROR 5 - CRITICAL **Level 1 is meant for developers, tester and monitoring purpose.** """ if logging_level > 5: await ctx.send("The logging level cannot be more than 5.") return if logging_level < 0: await ctx.send("The logging level cannot be less than 0.") value = getattr(LoggingLevels, "Lvl" + str(logging_level)).value await self.data.log_level.set(logging_level * 10) await ctx.send( warning( "The logging level has been set to: {val}, {lev}".format( val=value, lev=logging_level ) ) ) await self._initialize(False)
async def rule_channel_list(self, ctx, channel: Union[discord.TextChannel, discord.VoiceChannel] = None): """ List all rules for a channel Defaults to current channel. For voice channels, use the voice channel ID """ if channel: rules = await self.config.channel(channel).rules() else: channel = ctx.channel rules = await self.config.channel(channel).rules() embeds = [] rules_keys = sorted([int(r) for r in rules.keys()]) num_rules = len(rules_keys) for i, rule_num in enumerate(rules_keys): embed = discord.Embed(title=f"{channel.name} rules", colour=ctx.guild.me.colour) embed.add_field(name=f"Rule {rule_num}", value=rules[str(rule_num)]) embed.set_footer(text=f"Page {i+1} of {num_rules}") embeds.append(embed) if not embeds: await ctx.send(chat.warning("No rules defined.")) return await menu(ctx, embeds, DEFAULT_CONTROLS)
async def wikipedia(self, ctx: commands.Context, *, query: str): """Get information from Wikipedia.""" can_not_embed_links = not ctx.channel.permissions_for( ctx.me).embed_links can_not_add_reactions = not ctx.channel.permissions_for( ctx.me).add_reactions only_first_result = can_not_embed_links or can_not_add_reactions async with ctx.typing(): embeds, url = await self.perform_search( query, only_first_result=only_first_result) if not embeds: await ctx.send( error(f"I'm sorry, I couldn't find \"{query}\" on Wikipedia")) elif can_not_embed_links: await ctx.send( warning( f"I'm not allowed to do embeds here, so here's the first result:\n{url}" )) elif can_not_add_reactions: embeds[0].set_author( name=f"Result 1 (I need add reactions permission to show more)" ) await ctx.send(embed=embeds[0]) elif len(embeds) == 1: embeds[0].set_author(name="Result 1 of 1") await ctx.send(embed=embeds[0]) else: count = 0 for embed in embeds: count += 1 embed.set_author(name=f"Result {count} of {len(embeds)}") await menu(ctx, embeds, DEFAULT_CONTROLS, timeout=60.0)
async def _list_guilds(self, ctx: commands.Context, cog: str): cogs = await self.config.cogs() if cog.lower() not in cogs: await ctx.send(warning(_("That cog doesn't require a whitelist to use"))) return proper_name = cog_name(self.bot, cog) or cog def converter(page, page_id, total_pages): embed = discord.Embed( colour=ctx.me.colour, title=_("Whitelisted Guilds"), description=_("The following guilds are allowed to use {}").format(proper_name), ) for guild_id in page: guild = self.bot.get_guild(guild_id) try: name = escape(guild.name, formatting=True) except AttributeError: name = inline(_("Unknown guild")) embed.add_field( name=_("Guild #{}").format(((page_id * 10) + page.index(guild_id)) + 1), value=_("**Name:** {name}\n**ID:** `{id}`").format(name=name, id=guild_id), inline=False, ) embed.set_footer(text=_("Page {}/{}").format(page_id + 1, total_pages)) return embed await PaginateMenu(ctx, pages=chunks(cogs[cog.lower()], 6), converter=converter, actions={})
async def cogwhitelist_reset(self, ctx: commands.Context): """Reset whitelisted cog settings""" cogs = len(await self.config.cogs()) if not cogs: return await fmt( ctx, info( _( "No cogs are currently setup to require a whitelist to use, and as such " "you cannot reset any cog whitelist settings." ) ), ) warn_str = warning( _( "Are you sure you want to reset your cog whitelist settings?\n" "This action will make {cogs} cog(s) usable by any server.\n\n" "Unless you have a time machine, **this action cannot be undone.**" ) ) if await ConfirmMenu(ctx=ctx, content=warn_str.format(cogs=cogs)).prompt(): await self.config.cogs.set({}) await ctx.tick() else: await ctx.send(_("Ok then."))
async def dice(self, ctx: commands.Context, *, roll: str): """Perform die roll.""" try: # Pass 1: Tokenize and convert #d# into die objects roll_pass1 = self.get_equation_tokens( roll, await self.config.max_dice_rolls(), await self.config.max_die_sides(), ) # Pass 2: Roll dice and build math string to evaluate roll_log = "" roll_pass2 = "" roll_friendly = "" for token in roll_pass1: if isinstance(token, Die): token.roll() roll_pass2 += str(token.total) roll_log += "\nRolling {}: {} = {}".format( str(token), str(token.rolls), str(token.total)) else: roll_pass2 += str(token) roll_friendly += str(token) # Pass 3: Evaluate results if roll_log: result = str(eval_expr(roll_pass2)) roll_pass2 = roll_pass2.replace("*", "×") roll_friendly = roll_friendly.replace("*", "×") roll_log = "\n*Roll Log:" + roll_log if len(roll_pass1) > 1: roll_log += "\nResulting equation: {} = {}".format( roll_pass2, result) roll_log += "*" if len(roll_log) > 1500: roll_log = "\n*(Log too long to display)*" await ctx.send( "\N{GAME DIE} {} rolled {} and got **{}**{}".format( ctx.message.author.mention, roll_friendly, result, roll_log)) else: await ctx.send( warning( "{}, that notation doesn't have any dice for me to roll." .format(ctx.message.author.mention))) except TooManySides as exception: await ctx.send( error("{}, I don't own a {} sided die to perform that roll.". format(ctx.message.author.mention, exception.value))) except TooManyDice: await ctx.send( error("{}, I don't have that many dice to roll...".format( ctx.message.author.mention))) except KeyError: await ctx.send( error("{}, that is too complex for me to roll.".format( ctx.message.author.mention))) except (ValueError, SyntaxError, TypeError): await ctx.send( error("{}, that doesn't seem like a proper dice equation.". format(ctx.message.author.mention)))
async def staff(self, ctx: commands.Context, *, reason: str = None): """ Alert for the staff. """ channel = await self.config.guild(ctx.guild).channel() role = await self.config.guild(ctx.guild).role() if not channel: return await ctx.send( error("The staff have not yet setup a staff channel.")) channel = self.bot.get_channel(channel) role = ctx.guild.get_role(role) message_list = [] backslash = "\n" async for message in ctx.channel.history(limit=6): author, msg = message.author, message.content.replace("`", "") if len(msg) > 90: msg = msg[:90].strip(" ") + "..." elif not len(msg): msg = "[Embed, Attachment or File]" message_list.append( f"{str(author.display_name)}: {msg.replace(backslash, ' ')}") context = box("\n".join(message_list), lang="yaml") reason = reason or "No reason was provided." embed = discord.Embed( title=warning("Staff Attention Pending | Conspicuous Activity"), description="[Click here for context]({})".format( ctx.message.jump_url), color=await ctx.embed_colour(), ) embed.add_field(name="Member", value=ctx.author.mention, inline=True) embed.add_field(name="Channel", value=ctx.channel.mention, inline=True) embed.add_field(name="Time", value=self.timestamp, inline=True) embed.add_field(name="Reason", value=reason, inline=False) embed.add_field(name="Context", value=context, inline=False) if await ctx.embed_requested(): try: await channel.send( allowed_mentions=discord.AllowedMentions(roles=True), content=role.mention if role else None, embed=embed, ) await ctx.send( "I have alerted the authorities, please remain calm.") except discord.Forbidden: return await ctx.send( "I do not have permissions to alert the staff.") else: return await ctx.send( "I do not have permissions to send embeds in the staff's channel." )
async def maintenance_disable(self, ctx: commands.Context): if os.environ.get("RED_MAINTENANCE"): await ctx.send(warning(translate("set_by_env"))) return manager.bot = False await self.config.maintenance.set_raw("global", value=False) await ctx.send(tick(translate("disabled")))
async def identicon( self, ctx: commands.Context, user: Union[discord.Member, discord.User, int] = None, ): """ Generate an unique pydenticon with an user's Discord ID Parameters ---------- `[user]` - any valid user that shares a server with this bot (ID|tag#1234|tag) """ msg = "" DEFAULT_SCALE = 9 DEFAULT_SIZE = 120 scale = DEFAULT_SCALE size = DEFAULT_SIZE - DEFAULT_SIZE % scale if isinstance(user, int): try: user = await ctx.bot.fetch_user(user) except discord.NotFound: await ctx.send( chat.error("Discord user with ID `{}` not found").format( user)) return except discord.HTTPException: await ctx.send( chat.warning( "I was unable to get data about user with ID `{}`. Try again later" ).format(user)) return if user is None: user = ctx.author random.seed(user.id) color_white = "#000000" color_black = "#ffffff" fg: [str] bg: str fg = ["#{:06x}".format(random.randint(0x0, 0xFFFFFF))] bg = "#{:06x}".format(random.randint(0x0, 0xFFFFFF)) if fg[0] == bg: # squashing an edge case for some users... bg = color_black if fg != color_black else color_white f = BytesIO() generator = pydenticon.Generator(scale, scale, foreground=fg, background=bg) icon = generator.generate(str(user.id), size, size) f.write(icon) f.seek(0) f.name = "identicon.png" await ctx.send(msg + f"{user.name}'s identicon:", file=discord.File(f))
async def timedmute( self, ctx: commands.Context, member: discord.Member, duration: TimeConverter, *, reason: str = None, ): from timedrole.api import TempRole if not await hierarchy_allows(self.bot, mod=ctx.author, member=member): await ctx.send(warning(translate("hierarchy_disallows"))) return role = await self.get_punished_role(ctx.guild) if role is None: tmp_msg = await ctx.send(translate("setting_up")) async with ctx.typing(): role = await self.setup_role(ctx.guild) await tmp_msg.delete() if role in member.roles: await ctx.send(warning(translate("already_muted"))) return role = await TempRole.create( member, role, duration=duration, added_by=ctx.author, reason=reason ) await role.apply_role(reason=reason) try: await modlog.create_case( bot=self.bot, guild=ctx.guild, user=member, moderator=ctx.author, reason=reason, until=role.expires_at, action_type="timedmute", created_at=role.added_at, ) except RuntimeError: pass await ctx.send(tick(translate("member_muted", member=member, duration=Humanize(duration))))
async def star_remove(self, ctx: Context, message: StarboardMessage): """Remove a previously added star""" if not message.has_starred(ctx.author): await fmt( ctx, warning( i18n("You haven't starred that message\n\n" "(you can use `{prefix}star` to star it)")), delete_after=15, ) return try: await message.remove_star(ctx.author) except StarboardException: await ctx.send(warning(i18n("Failed to remove star"))) else: await ctx.tick()