async def removal(self, ctx: commands.Context, action: str): message = "Would you like to reset the {}?".format(action) can_react = ctx.channel.permissions_for(ctx.me).add_reactions if not can_react: message += " (y/n)" question: discord.Message = await ctx.send(message) if can_react: start_adding_reactions( question, ReactionPredicate.YES_OR_NO_EMOJIS ) pred = ReactionPredicate.yes_or_no(question, ctx.author) event = "reaction_add" else: pred = MessagePredicate.yes_or_no(ctx) event = "message" try: await ctx.bot.wait_for(event, check=pred, timeout=20) except asyncio.TimeoutError: await question.delete() await ctx.send("Okay then :D") if not pred.result: await question.delete() return await ctx.send("Canceled!") else: if can_react: with suppress(discord.Forbidden): await question.clear_reactions() await self.config.guild(ctx.guild).set_raw(action, value=None) await ctx.send("Removed the {}!".format(action)) pred = ReactionPredicate.yes_or_no(question, ctx.author) event = "reaction_add"
async def confirm(self, ctx, type: str, cost: int): msg = await ctx.send( f"Please confirm that you would like to purchase a {type} for {cost}." ) pred = ReactionPredicate.yes_or_no(msg, ctx.author) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: await self.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: await msg.delete() await ctx.send(f":x: You took too long to respond.") if not pred.result: await ctx.send("Okay. No changes have been made.") else: try: await msg.delete() await bank.withdraw_credits(ctx.author, cost) crooks = await self.config.user(ctx.author).crooks() crooks += 1 await self.config.user(ctx.author).crooks.set(crooks) await ctx.send(f"Done. A {type} was successfully purchased for {cost}.") except ValueError: await ctx.send( f"You do not have enough cash! A crook costs {cost}, you have {await bank.get_balance(ctx.author)}." )
async def _send_check_out_message(self, ctx, user, match_day, tier): embed = discord.Embed( title="Check Out", description= "You are currently checked in as available for the following match day and tier. " "Do you wish to take yourself off the availability list? To confirm you want to check out, react with {}" .format(ReactionPredicate.YES_OR_NO_EMOJIS[0]), colour=discord.Colour.blue()) embed.add_field(name="Match Day", value=match_day, inline=True) embed.add_field(name="Tier", value=tier, inline=True) react_msg = await user.send(embed=embed) start_adding_reactions(react_msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: pred = ReactionPredicate.yes_or_no(react_msg, user) await ctx.bot.wait_for("reaction_add", check=pred, timeout=verify_timeout) if pred.result is True: await self._unregister_user(ctx, user, match_day, tier) await user.send( "You have been removed from the list. Thank you for updating your availability!" ) else: await user.send( "Still checked in. If you wish to check out use the command again." ) except asyncio.TimeoutError: await user.send( "Sorry, you didn't react quick enough. Please try again.")
async def _send_check_in_message(self, ctx, user, match_day, tier): embed = discord.Embed( title="Check In", description= "By checking in you are letting GMs know that you are available to play " "on the following match day in the following tier. To confirm react with {}" .format(ReactionPredicate.YES_OR_NO_EMOJIS[0]), colour=discord.Colour.blue()) embed.add_field(name="Match Day", value=match_day, inline=True) embed.add_field(name="Tier", value=tier, inline=True) react_msg = await user.send(embed=embed) start_adding_reactions(react_msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: pred = ReactionPredicate.yes_or_no(react_msg, user) await ctx.bot.wait_for("reaction_add", check=pred, timeout=verify_timeout) if pred.result is True: await self._register_user(ctx, user, match_day, tier) await user.send( "Thank you for checking in! GMs will now be able to see that you're available." ) else: await user.send( "Not checked in. If you wish to check in use the command again." ) except asyncio.TimeoutError: await user.send( "Sorry, you didn't react quick enough. Please try again.")
async def delete_letter(self, ctx: commands.Context, letter_id: str): """ Delete a specific letter. """ letters = await self.config.custom("LetterBox", ctx.author.id).letterbox() if letter_id not in letters: await ctx.send("This letter is not in your letterbox.") return msg = await ctx.send( bold( "Are you sure you want to delete this letter? This action " + underline("cannot be") + " recovered.", escape_formatting=False, )) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await self.bot.wait_for("reaction_add", check=pred, timeout=60) except AsyncTimeoutError: return None if pred.result: await self.config.custom( "LetterBox", ctx.author.id).letterbox.clear_raw(letter_id) await msg.edit(content="Deleted your letter.") else: await msg.edit(content="I won't touch it then!")
async def find_wiki_name(self, ctx, wiki_name): wikis = await self.get_wikis(ctx) match = get_close_matches(wiki_name, wikis.keys(), 1, 0.3) if not match: # No match found, list of wikis returned instead return msg = await ctx.send( f'I can\'t find a wiki called {wiki_name}. Did you mean`{match[0]}`?' ) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: #waiting for reaction pred = ReactionPredicate.yes_or_no(msg, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred, timeout=15) except asyncio.TimeoutError: await ctx.send("You didn\'t react in time, cancelled.") try: # Delete reactions from question message if ctx.channel.permissions_for(ctx.me).manage_messages: await msg.clear_reactions() except: pass if pred.result is not True: return # User didn't responded with tick wiki_name = match[0] return wiki_name
async def _react_prompt(self, ctx, prompt, if_not_msg=None, embed: discord.Embed = None): user = ctx.message.author if embed: embed.description = prompt react_msg = await ctx.send(embed=embed) else: react_msg = await ctx.send(prompt) start_adding_reactions(react_msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: pred = ReactionPredicate.yes_or_no(react_msg, user) await ctx.bot.wait_for("reaction_add", check=pred, timeout=verify_timeout) if pred.result: return True if if_not_msg: await ctx.send(if_not_msg) return False except asyncio.TimeoutError: await ctx.send( "Sorry {}, you didn't react quick enough. Please try again.". format(user.mention)) return False
async def _confirm(ctx: commands.Context) -> bool: """Ask "Are you sure?" and get the response as a bool.""" if ctx.guild is None or ctx.guild.me.permissions_in( ctx.channel).add_reactions: msg = await ctx.send(_("Are you sure?")) # noinspection PyAsyncCall task = start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: await ctx.send(_("Response timed out.")) return False else: task.cancel() agreed = pred.result finally: await msg.delete() else: await ctx.send(_("Are you sure? (y/n)")) pred = MessagePredicate.yes_or_no(ctx) try: await ctx.bot.wait_for("message", check=pred, timeout=30) except asyncio.TimeoutError: await ctx.send(_("Response timed out.")) return False else: agreed = pred.result if agreed is False: await ctx.send(_("Action cancelled.")) return agreed
async def setup_delete_definition(self, ctx: commands.Context, definition_name:str) -> None: """Delete a defined game Note that this does delete any files or folders. Parameters ---------- definition_name: str Name of the game to delete. """ game_defs = await self._conf.game_defs() if definition_name not in game_defs.keys(): return await self._embed_msg( ctx, title=_("No Such Definition"), description=_(f"{name} does not exist."), error=True ) # Ask the user if they are really sure about this info_msg = _( "Are you sure you want to delete?:\n" "```\n" f"{definition_name}\n" "```\n" ) info = await ctx.maybe_send_embed(info_msg) start_adding_reactions(info, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(info, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred) # If user said no if not pred.result: with contextlib.suppress(discord.HTTPException): await info.delete() return else: # If an instance is running, shut it down if self._locks.get(definition_name, None) is not None: async with self._locks[definition_name]: if self._instances.get(definition_name, None) is not None: if self._instances[definition_name].isRunning(): self._instances[definition_name].stop() # Delete it from the list del game_defs[definition_name] await self._conf.game_defs.set(game_defs) # Delete the channel registrations defs_to_channels = await self._conf.defs_to_channels() channels_to_defs = await self._conf.channels_to_defs() for channel_id in channels_to_defs.keys(): del channels_to_defs[channel_id] await self._conf.channels_to_defs.set(channels_to_defs) del defs_to_channels[definition_name] await self._conf.defs_to_channels.set(defs_to_channels) # Report success return await self._embed_msg( ctx, title=_("Deletion Successful"), description=_(f"{definition_name} has been deleted."), success=True )
async def reactrole_delete( self, ctx: commands.Context, message: Union[discord.Message, ObjectConverter], ): """Delete an entire reaction role for a message.""" message_data = await self.config.custom("GuildMessage", ctx.guild.id, message.id).all() if not message_data["reactroles"]["react_to_roleid"]: return await ctx.send("There are no reaction roles set up for that message.") msg = await ctx.send( "Are you sure you want to remove all reaction roles for that message?" ) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await self.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await ctx.send("Action cancelled.") if pred.result: await self.config.custom("GuildMessage", ctx.guild.id, message.id).clear() await ctx.send("Reaction roles cleared for that message.") self._edit_cache(message.id, True) else: await ctx.send("Action cancelled.")
async def tag_global_add(self, ctx: commands.Context, tag_name: TagName, *, tagscript: TagScriptConverter): """ Add a global tag with TagScript. [Tag usage guide](https://phen-cogs.readthedocs.io/en/latest/blocks.html#usage) """ tag = self.get_tag(None, tag_name, check_global=True) if tag: msg = await ctx.send( f"`{tag_name}` is already registered global tag. Would you like to overwrite it?" ) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: return await ctx.send("Global tag edit cancelled.") if pred.result is False: return await ctx.send("Global tag edit cancelled.") tag.tagscript = tagscript await tag.update_config() await ctx.send(f"Global tag `{tag}` edited.") return tag = Tag(self, tag_name, tagscript, author_id=ctx.author.id) self.global_tag_cache[tag_name] = tag await tag.update_config() await ctx.send(f"Global tag `{tag}` added.")
async def _profile_delete(self, ctx: commands.Context): """Deletes your profile permanently""" try: exists_msg = await ctx.author.send( "This cannot be undone and you will have to create a new profile, " "do you want to continue? (y/n)" ) start_adding_reactions(exists_msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(exists_msg, ctx.author) await self.bot.wait_for("reaction_add", check=pred) except discord.Forbidden: return await ctx.send(f"I can't DM you, {ctx.author.mention}") if pred.result: user_group = self.profileConfig.user(ctx.author) async with user_group() as user_data: user_data.clear() account_group = self.config.user(ctx.author) async with account_group() as account_data: account_data.clear() await ctx.author.send( f"To created a new one please run `{self._profile_create.qualified_name}`" ) else: await ctx.author.send("Your profile hasn't been touched")
async def _confirm(ctx: commands.Context) -> bool: """Ask "Are you sure?" and get the response as a bool.""" if ctx.guild is None or ctx.guild.me.permissions_in(ctx.channel).add_reactions: msg = await ctx.send(_("Are you sure?")) # noinspection PyAsyncCall task = start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS, ctx.bot.loop) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: await ctx.send(_("Response timed out.")) return False else: task.cancel() agreed = pred.result finally: await msg.delete() else: await ctx.send(_("Are you sure? (y/n)")) pred = MessagePredicate.yes_or_no(ctx) try: await ctx.bot.wait_for("message", check=pred, timeout=30) except asyncio.TimeoutError: await ctx.send(_("Response timed out.")) return False else: agreed = pred.result if agreed is False: await ctx.send(_("Action cancelled.")) return agreed
async def manifest(self, ctx: commands.Context) -> None: """ See the current manifest version and optionally re-download it """ version = await self.config.manifest_version() if not version: version = "Not Downloaded" await ctx.send( _("Current manifest version is {version}").format(version=version)) await ctx.trigger_typing() msg = await ctx.send(_("Would you like to re-download the manifest?")) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: react, user = await self.bot.wait_for("reaction_add", check=pred, timeout=15) except asyncio.TimeoutError: await msg.delete() if pred.result: try: version = await self.get_manifest() except Exception: return await ctx.send( _("There was an issue downloading the manifest.")) await msg.delete() await ctx.send(f"Manifest {version} was downloaded.") else: await msg.delete()
async def leave_guilds(self, ctx: commands.Context, guilds: list, message: str): data = await self.config.all() unwl_guilds = [guild for guild in guilds if guild.id not in data["whitelist"]] if not unwl_guilds: await ctx.send("There are no servers to leave that aren't whitelisted.") return name_ids = "\n".join([f"{guild.name} - ({guild.id})" for guild in unwl_guilds][:5]) guild_preview = name_ids + ( f"\nand {len(unwl_guilds) - 5} other guilds.." if len(unwl_guilds) > 5 else "" ) msg = await ctx.send( f"Are you sure you want me to leave the following {len(unwl_guilds)} guilds?\n" + box(guild_preview, "py") ) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await self.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await ctx.send("Action cancelled.") if pred.result is True: async with ctx.typing(): for guild in unwl_guilds: await self.notify_guild(guild, message) await guild.leave() await self.baron_log("mass_leave", guilds=unwl_guilds, author=ctx.author) await ctx.send(f"Done. I left {len(unwl_guilds)} servers.") else: await ctx.send("Action cancelled.")
async def _embed_react_prompt(self, ctx, embed, existing_message=None, success_embed=None, reject_embed=None, clear_after_confirm=True): user = ctx.message.author if existing_message: react_msg = existing_message await react_msg.edit(embed=embed) else: react_msg = await ctx.send(embed=embed) start_adding_reactions(react_msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: pred = ReactionPredicate.yes_or_no(react_msg, user) await ctx.bot.wait_for("reaction_add", check=pred, timeout=verify_timeout) if pred.result: await react_msg.edit(embed=success_embed) if clear_after_confirm: await react_msg.clear_reactions() return True if reject_embed: await react_msg.edit(embed=reject_embed) return False except asyncio.TimeoutError: await react_msg.edit(embed=reject_embed) await ctx.send( "Sorry {}, you didn't react quick enough. Please try again.". format(user.mention)) return False
async def buy_gem_skin(self, ctx: Context, user: discord.User, config: Config, item_data: dict): brawler = item_data["brawler"] cost = item_data["cost"] skin = item_data["skin"] gems = await config.user(user).gems() if gems < cost: await ctx.send(f"You do not have enough gems! ({gems}/{cost})") return False msg = await ctx.send( f"{user.mention} Buying **{skin} {brawler}**" f" skin will cost {emojis['gem']} {cost}. Continue?") start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, user) await ctx.bot.wait_for("reaction_add", check=pred) if pred.result: # User responded with tick pass else: # User responded with cross await ctx.send("Purchase cancelled.") return False async with config.user(user).brawlers() as brawlers: brawlers[brawler]["skins"].append(skin) await config.user(user).gems.set(gems - cost) await ctx.send(f"Bought {skin} {brawler} skin!") return True
async def find_game_name(self, ctx, game_name): games = await self.get_games(ctx) match = get_close_matches(game_name, games.keys(), 1, 0.3) if not match: # No match was found. Returing a list of games. return # Found a match. msg = await ctx.send(f'I can\'t find a game called `{game_name}`.\nDid you mean `{match[0]}`?') start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: # Wait for a reaction on question pred = ReactionPredicate.yes_or_no(msg, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred, timeout=15) except asyncio.TimeoutError: await ctx.send("You didn\'t react in time, cancelled.") try: # Delete reactions from question message if ctx.channel.permissions_for(ctx.me).manage_messages: await msg.clear_reactions() except: pass if pred.result is not True: return # User didn't responded with tick game_name = match[0] return game_name
async def delete_trigger(self, payload: discord.RawReactionActionEvent) -> None: """Enables and disables triggers""" member = self.ctx.guild.get_member(payload.user_id) if await self.cog.can_edit(member, self.source.selection): msg = await self.ctx.send( _("Are you sure you want to delete trigger {name}?").format( name=self.source.selection.name)) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, self.ctx.author) await self.ctx.bot.wait_for("reaction_add", check=pred) if pred.result: await msg.delete() self.source.selection.disable() done = await self.cog.remove_trigger( payload.guild_id, self.source.selection.name) if done: page = await self._source.get_page(self.current_page) kwargs = await self._get_kwargs_from_page(page) await self.message.edit( content=_("This trigger has been deleted."), embed=kwargs["embed"]) for t in self.cog.triggers[self.ctx.guild.id]: if t.name == self.source.selection.name: self.cog.triggers[self.ctx.guild.id].remove(t)
async def verify_game_results(self, ctx, game, blue_team_wins, orange_team_wins, verifier: discord.Member): msg = await ctx.send( "{0} Please verify the results:\n**{1}** {2} - {3} **{4}**".format( verifier.mention, game.blue.name, blue_team_wins, orange_team_wins, game.orange.name)) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) game.scoreReported = True pred = ReactionPredicate.yes_or_no(msg, verifier) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=verify_timeout) if pred.result is True: return True else: game.scoreReported = False await ctx.send( ":x: Ladder game result not verified. To report the result you will need to use the `{0}lr` command again." .format(ctx.prefix)) return False except asyncio.TimeoutError: game.scoreReported = False await ctx.send( ":x: Ladder game result not verified in time. To report the result you will need to use the `{0}lr` command again.\n" "**If one of the captains is afk, have someone from that team use the command.**" .format(ctx.prefix)) return False
async def check_clear_event(self, ctx: commands.Context) -> bool: msg = await ctx.send( "You already have an event running, would you like to cancel it?") start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred) return pred.result
async def create_tag( self, ctx: commands.Context, tag_name: str, tagscript: str, *, global_tag: bool = False ): kwargs = {"author_id": ctx.author.id} if global_tag: guild = None tag = self.get_tag(None, tag_name, global_priority=True) else: guild = ctx.guild tag = self.get_tag(guild, tag_name, check_global=False) kwargs["guild_id"] = guild.id self.validate_tag_count(guild) if tag: tag_prefix = tag.name_prefix msg = await ctx.send( f"`{tag_name}` is already a registered {tag_prefix.lower()}. Would you like to overwrite it?" ) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: return await ctx.send(f"{tag_prefix} edit cancelled.") if pred.result is False: return await ctx.send(f"{tag_prefix} edit cancelled.") await ctx.send(await tag.edit_tagscript(tagscript)) return tag = Tag(self, tag_name, tagscript, **kwargs) await ctx.send(await tag.initialize())
async def yes_or_no(ctx, message) -> bool: msg = await ctx.send(message) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred) await msg.delete() return pred.result
async def cmd3(self, ctx): def check(m): return m.channel.id == ctx.channel.id and ctx.author.id == ctx.message.author.id await ctx.send("Email Address?") email = await ctx.bot.wait_for("message", check=check) await ctx.send("First Name?") firstname = await ctx.bot.wait_for("message", check=check) await ctx.send("Last Name?") lastname = await ctx.bot.wait_for("message", check=check) await ctx.send("Pirate Name?") piratename = await ctx.bot.wait_for("message", check=check) await ctx.send("Phone Number?") phonenumber = await ctx.bot.wait_for("message", check=check) msg1 = await ctx.send("Do you have an Emergency Contact? Y/N") start_adding_reactions(msg1, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg1, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred) if pred.result is True: # User responded with tick await ctx.send("Emergency Contact Name?") emgname = await ctx.bot.wait_for("message", check=check) await ctx.send("Emergency Contact Phone Number?") emgphone = await ctx.bot.wait_for("message", check=check) await ctx.send("Emergency Contact Relationship?") emgrelation = await ctx.bot.wait_for("message", check=check) # Begin posting data to Spreedsheet scope = [ 'https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive' ] file_path = bundled_data_path(self) / 'client_secret.json' creds = ServiceAccountCredentials.from_json_keyfile_name( file_path, scope) client = gspread.authorize(creds) sheet = client.open("DragonBot Tester").sheet1 index = 2 now = datetime.now() ts = int(datetime.timestamp(now)) row = [ datetime.utcfromtimestamp(ts).strftime('%m/%d/%Y %H:%M:%S'), email.content, firstname.content, lastname.content, piratename.content, phonenumber.content ] sheet.insert_row(row, index)
async def clean(self, ctx: commands.Context): """ Dehoist all members in the guild. NOTE: If the server owner is hoisted, [botname] cannot change their nickname. """ hoisted_count = await self.get_hoisted_count(ctx) guild_config = await self.config.guild(ctx.guild).all() nickname = guild_config["nickname"] ignored_users = guild_config["ignored_users"] if not hoisted_count: return await ctx.send("There are no hoisted members.") if not ctx.channel.permissions_for(ctx.me).add_reactions: return await ctx.send("I cannot add reactions.") if not ctx.channel.permissions_for(ctx.me).manage_nicknames: return await ctx.send("I do not have permission to edit nicknames." ) msg = await ctx.send( f"Are you sure you would like to dehoist {hoisted_count} hoisted users? " f"This may take a few moments.\nTheir nickname's will be changed to `{nickname}`, " f"you can cancel now and change this nickname via `{ctx.clean_prefix}hoist set nickname` " "if you wish.") pred = ReactionPredicate.yes_or_no(msg, ctx.author) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: await self.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: await msg.delete() return await ctx.send(f"You took too long to respond.") if pred.result: await ctx.trigger_typing() exceptions = 0 for m in ctx.guild.members: if m.display_name.startswith( HOIST) and not m.bot and m.id not in ignored_users: try: await m.edit( nick=await self.config.guild(ctx.guild).nickname()) except discord.Forbidden: # This exception will only occur if an attempt is made to dehoist server owner exceptions += 1 await ctx.send( f"I could not change {ctx.guild.owner.name}'s nickname because I cannot edit owner nicknames." ) await ctx.send( f"{hoisted_count - exceptions} users have been dehoisted.") else: await ctx.send("No changes have been made.")
async def relayAddChannel(self, ctx, chanObj, toWebhook): msgrelayStoreV2 = await self.config.guild(ctx.guild).msgrelayStoreV2() # Set attachsAsUrl attachsAsUrl = await ctx.send( "Do you want attachments (images) to be forwarded as links?\n> **Yes:** Images will be sent as links\n> **No:** Images will be re-uploaded as a new file" ) start_adding_reactions(attachsAsUrl, ReactionPredicate.YES_OR_NO_EMOJIS) attachsAsUrlPred = ReactionPredicate.yes_or_no(attachsAsUrl, ctx.author) await ctx.bot.wait_for("reaction_add", check=attachsAsUrlPred) # Set userProfiles userProfiles = await ctx.send( "Do you want messages to be forwarded with profiles?\n> **Yes:** Messages will be forwarded with usernames and profile pics\n> **No:** Messages will use the webhook's name and image instead" ) start_adding_reactions(userProfiles, ReactionPredicate.YES_OR_NO_EMOJIS) userProfilesPred = ReactionPredicate.yes_or_no(userProfiles, ctx.author) await ctx.bot.wait_for("reaction_add", check=userProfilesPred) # Create data store try: relayInfo = { "toWebhook": str(toWebhook), "attachsAsUrl": attachsAsUrlPred.result, "userProfiles": userProfilesPred.result, } except: return False # Append to data try: msgrelayStoreV2[str(chanObj.id)].append(relayInfo) except KeyError: msgrelayStoreV2[str(chanObj.id)] = [relayInfo] except: return False # Return changes return msgrelayStoreV2
async def confirm(self, ctx: commands.Context, content: str): msg = await ctx.send(content) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) try: await self.bot.wait_for("reaction_add", check=pred, timeout=60) except AsyncTimeoutError: return None finally: await msg.delete() return pred.result
async def rolereq_clear(self, ctx, raffle: RaffleFactoryConverter): """Clear the role requirement list for a raffle. **Arguments:** - `<raffle>` - The name of the raffle. """ async with self.config.guild(ctx.guild).raffles() as r: raffle_data = r.get(raffle, None) rolesreq = raffle_data.get("roles_needed_to_enter", []) if rolesreq is None: return await ctx.send(_("There are no required roles.")) message = _( "Are you sure you want to clear the role requirement list for this raffle?" ) can_react = ctx.channel.permissions_for(ctx.me).add_reactions if not can_react: message += " (yes/no)" message = await ctx.send(message) if can_react: start_adding_reactions(message, ReactionPredicate.YES_OR_NO_EMOJIS) predicate = ReactionPredicate.yes_or_no(message, ctx.author) event_type = "reaction_add" else: predicate = MessagePredicate.yes_or_no(ctx) event_type = "message" try: await self.bot.wait_for(event_type, check=predicate, timeout=30) except asyncio.TimeoutError: await ctx.send(_("You took too long to respond.")) return if predicate.result: with contextlib.suppress(KeyError): # Still wanna remove empty list here del raffle_data["roles_needed_to_enter"] msg = "Role requirement list cleared for this raffle." try: await message.edit(content=msg) except discord.NotFound: await ctx.send(msg) else: await ctx.send(_("No changes have been made.")) await self.clean_guild_raffles(ctx)
async def unsticky(self, ctx: commands.Context, force: bool = False): """Remove the sticky message from this channel. Deleting the sticky message will also unsticky it. Do `[p]unsticky yes` to skip the confirmation prompt. """ channel = ctx.channel settings = self.conf.channel(channel) self.locked_channels.add(channel) try: last_id = await settings.last() if last_id is None: await ctx.send("There is no stickied message in this channel.") return msg = None if not force and channel.permissions_for(ctx.me).add_reactions: msg = await ctx.send( "This will unsticky the current sticky message from " "this channel. Are you sure you want to do this?") start_adding_reactions( msg, emojis=ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg) try: resp = await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: resp = None if resp is None or pred.result is False: with contextlib.suppress(discord.NotFound): await msg.delete() return else: await ctx.send( f"I don't have the add_reactions permission here. " f"Use `{ctx.prefix}unsticky yes` to remove the sticky message." ) return await settings.set( # Preserve the header setting {"header_enabled": await settings.header_enabled()}) with contextlib.suppress(discord.HTTPException): last = await channel.fetch_message(last_id) await last.delete() if msg is not None: with contextlib.suppress(discord.NotFound): await msg.delete() await ctx.tick() finally: self.locked_channels.remove(channel)
async def pred(self, ctx: commands.Context, message: str): msg = await ctx.send( f"Please confirm that you want to send the following message: {box(message, lang='md')}" ) pred = ReactionPredicate.yes_or_no(msg, ctx.author) start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) try: await self.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: await ctx.send(f"You took too long to respond.") if pred.result: return True
async def ticket_channel_prune(self, ctx, user: Optional[Union[int, discord.User]] = None): """Clean out channels under the archive category. Pass a user to only delete the channels created by that user instead. WARNING: This will remove ALL channels unless otherwise specified!""" category = self.bot.get_channel( (await self.config.guild(ctx.guild).archive())["category"]) if not category: await ctx.send("Your archive category no longer exists!") return if isinstance(user, discord.User): user = user.id channels = [] if user: for channel in category.text_channels: if channel.name == f"ticket-{user}": channels.append(channel) message = await ctx.send( f"Are you sure you want to remove all archived ticket channels from user {user}? " f"This will delete {len(channels)} Text Channels.") else: channels = category.text_channels message = await ctx.send( "Are you sure you want to remove all archived ticket channels? " f"This will delete {len(channels)} Text Channels.") start_adding_reactions(message, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(message, ctx.author) await self.bot.wait_for("reaction_add", check=pred) if pred.result is True: progress = await ctx.send("Purging text channels...") for channel in channels: try: await channel.delete() except discord.Forbidden: await ctx.send( "I do not have permission to delete those text channels. " 'Make sure I have both "Manage Channels" and "View Channels".' ) return except discord.HTTPException: continue with contextlib.suppress(discord.HTTPException): await progress.edit(content="Channels successfully purged.") else: await ctx.send("Channel purge cancelled.")
async def _cog_update(self, ctx, cog_name: InstalledCog = None): """Update all cogs, or one of your choosing.""" installed_cogs = set(await self.installed_cogs()) async with ctx.typing(): if cog_name is None: updated = await self._repo_manager.update_all_repos() else: try: updated = await self._repo_manager.update_repo(cog_name.repo_name) except KeyError: # Thrown if the repo no longer exists updated = {} updated_cogs = set(cog for repo in updated for cog in repo.available_cogs) installed_and_updated = updated_cogs & installed_cogs if installed_and_updated: await self._reinstall_requirements(installed_and_updated) await self._reinstall_cogs(installed_and_updated) await self._reinstall_libraries(installed_and_updated) message = _("Cog update completed successfully.") cognames = {c.name for c in installed_and_updated} message += _("\nUpdated: ") + humanize_list(tuple(map(inline, cognames))) else: await ctx.send(_("All installed cogs are already up to date.")) return await ctx.send(message) cognames &= set(ctx.bot.extensions.keys()) # only reload loaded cogs if not cognames: return await ctx.send( _("None of the updated cogs were previously loaded. Update complete.") ) message = _("Would you like to reload the updated cogs?") can_react = ctx.channel.permissions_for(ctx.me).add_reactions if not can_react: message += " (y/n)" query: discord.Message = await ctx.send(message) if can_react: # noinspection PyAsyncCall start_adding_reactions(query, ReactionPredicate.YES_OR_NO_EMOJIS, ctx.bot.loop) pred = ReactionPredicate.yes_or_no(query, ctx.author) event = "reaction_add" else: pred = MessagePredicate.yes_or_no(ctx) event = "message" try: await ctx.bot.wait_for(event, check=pred, timeout=30) except asyncio.TimeoutError: await query.delete() return if pred.result is True: if can_react: with contextlib.suppress(discord.Forbidden): await query.clear_reactions() await ctx.invoke(ctx.bot.get_cog("Core").reload, *cognames) else: if can_react: await query.delete() else: await ctx.send(_("OK then."))