async def prompt_for_reaction(self, ctx, reactions): text = "Please add the reaction to this message that you want to watch for (or :white_check_mark: to finish or cancel if nothing set so far)" if reactions: text += "\n\n**Current reactions**" for r in reactions: text += f"\n{r} <@&{reactions[r]}>" prompt_reaction_message = await ctx.send_success( description=text, title="Reaction roles") prompt_reaction = context.PromptDataReaction( message=prompt_reaction_message, reactions=[], timeout=30, delete_after=True, raw_emoji=True) reaction, _ = await ctx.prompt_reaction(prompt_reaction) return reaction
async def report(self, msg, user, word, invite=None): channel = msg.guild.get_channel( self.bot.settings.guild().channel_reports) ping_string = await self.prepare_ping_string(msg) embed = await self.prepare_embed(user, msg, word) if invite: report_msg = await channel.send( f"{ping_string}\nMessage contained invite: {invite}", embed=embed) else: report_msg = await channel.send(ping_string, embed=embed) report_reactions = ['β ', 'π', 'π§Ή'] ctx = await self.bot.get_context(report_msg, cls=context.Context) prompt_data = context.PromptDataReaction(report_msg, report_reactions) while True: self.pending_tasks[report_msg.id] = "NOT TERMINATED" reaction, reactor = await ctx.prompt_reaction(prompt_data) if reaction == "TERMINATE": return if not self.bot.settings.permissions.hasAtLeast( user.guild, user, 5) or reaction not in report_reactions: await report_msg.remove_reaction(reaction, reactor) if reaction == 'β ': try: await report_msg.delete() except Exception: pass return elif reaction == 'π': await channel.send(user.id) elif reaction == 'π§Ή': await channel.purge(limit=100) return
async def report_spam(self, msg, user, title): channel = msg.guild.get_channel( self.bot.settings.guild().channel_reports) ping_string = await self.prepare_ping_string(msg) embed = await self.prepare_embed(user, msg, title=title) embed.set_footer(text="β to pardon, π to ban, β οΈ to temp mute.") report_msg = await channel.send(ping_string, embed=embed) report_reactions = ['β ', 'π', 'β οΈ'] ctx = await self.bot.get_context(report_msg, cls=context.Context) prompt_data = context.PromptDataReaction(report_msg, report_reactions) while True: self.pending_tasks[report_msg.id] = "NOT TERMINATED" reaction, reactor = await ctx.prompt_reaction(prompt_data) if reaction == "TERMINATE": return if not self.bot.settings.permissions.hasAtLeast( user.guild, user, 5) or reaction not in report_reactions: await report_msg.remove_reaction(reaction, reactor) if reaction == 'β ': ctx.author = ctx.message.author = reactor unmute = self.bot.get_command("unmute") if unmute is not None: try: await unmute(ctx=ctx, user=user, reason="Reviewed by a moderator.") except Exception: pass await report_msg.delete() else: await ctx.send_warning("I wasn't able to unmute them.") return elif reaction == 'π': ctx.author = ctx.message.author = reactor ban = self.bot.get_command("ban") if ban is not None: try: await ban(ctx=ctx, user=user, reason="Spam detected") except Exception: pass await report_msg.delete() else: await ctx.send_warning("I wasn't able to ban them.") return elif reaction == 'β οΈ': ctx.author = ctx.message.author = reactor now = datetime.datetime.now() delta = await self.prompt_time(ctx) if delta is None: continue try: time = now + datetime.timedelta(seconds=delta) ctx.tasks.schedule_unmute(user.id, time) await ctx.send_success( title="Done!", description= f"{user.mention} was muted for {humanize.naturaldelta(time - now)}.", delete_after=5) await report_msg.delete() try: await user.send(embed=discord.Embed( title="Ping spam unmute", description= f"A moderator has reviewed your ping spam report. You will be unmuted in {humanize.naturaldelta(time - now)}.", color=discord.Color.orange())) except Exception: pass return except Exception: return
async def report_possible_raid_phrase(self, msg, user, domain): channel = msg.guild.get_channel( self.bot.settings.guild().channel_reports) ping_string = await self.prepare_ping_string(msg) ping_string = "" embed = await self.prepare_embed( user, msg, word=domain, title=f"Possible new raid phrase detected\n{domain}") embed.set_footer(text="β to pardon, π to ban and add new raid phrase") report_msg = await channel.send(ping_string, embed=embed) report_reactions = ['β ', 'π'] ctx = await self.bot.get_context(report_msg, cls=context.Context) prompt_data = context.PromptDataReaction(report_msg, report_reactions) while True: self.pending_tasks[report_msg.id] = "NOT TERMINATED" reaction, reactor = await ctx.prompt_reaction(prompt_data) if reaction == "TERMINATE": return if not self.bot.settings.permissions.hasAtLeast( user.guild, user, 5) or reaction not in report_reactions: await report_msg.remove_reaction(reaction, reactor) if reaction == 'β ': ctx.author = ctx.message.author = reactor unmute = self.bot.get_command("unmute") if unmute is not None: try: await unmute(ctx=ctx, user=user, reason="Reviewed by a moderator.") except Exception: pass await report_msg.delete() else: await ctx.send_warning("I wasn't able to unmute them.") return elif reaction == 'π': ctx.author = ctx.message.author = reactor ban = self.bot.get_command("ban") if ban is not None: try: await ban(ctx=ctx, user=user, reason="Raid phrase detected") except Exception: pass await report_msg.delete() else: await ctx.send_warning("I wasn't able to ban them.") done = await self.bot.settings.add_raid_phrase(domain) if done: await channel.send( f"{domain} was added to the raid phrase list.", delete_after=5) else: await channel.send( f"{domain} was already in the raid phrase list.", delete_after=5) return
async def batchraid(self, ctx: context.Context, *, phrases: str) -> None: """Add a list of (newline-separated) phrases to the raid filter. Example usage -------------- !raid <phrase> Parameters ---------- phrases : str "Phrases to add, separated with enter" """ async with ctx.typing(): phrases = list(set(phrases.split("\n"))) phrases = [phrase.strip() for phrase in phrases] phrases_contenders = set(phrases) phrases_already_in_db = set( [phrase.word for phrase in ctx.settings.guild().raid_phrases]) duplicate_count = len( phrases_already_in_db & phrases_contenders) # count how many duplicates we have new_phrases = list(phrases_contenders - phrases_already_in_db) if not new_phrases: raise commands.BadArgument( "All the phrases you supplied are already in the database.") phrases_prompt_string = "\n".join( [f"**{i+1}**. {phrase}" for i, phrase in enumerate(new_phrases)]) if len(phrases_prompt_string) > 3900: phrases_prompt_string = phrases_prompt_string[:3500] + "\n... (and some more)" embed = Embed( title="Confirm raidphrase batch", color=discord.Color.dark_orange(), description= f"{phrases_prompt_string}\n\nShould we add these {len(new_phrases)} phrases?" ) if duplicate_count > 0: embed.set_footer( text= f"Note: we found {duplicate_count} duplicates in your list.") message = await ctx.send(embed=embed) prompt_data = context.PromptDataReaction(message=message, reactions=['β ', 'β'], timeout=120, delete_after=True) response, _ = await ctx.prompt_reaction(info=prompt_data) if response == 'β ': async with ctx.typing(): for phrase in new_phrases: await ctx.settings.add_raid_phrase(phrase) await ctx.send_success( f"Added {len(new_phrases)} phrases to the raid filter.", delete_after=5) else: await ctx.send_warning("Cancelled.", delete_after=5) await ctx.message.delete(delay=5)
async def adddevice(self, ctx: context.Context, *, device: str) -> None: """Add device name to your nickname, i.e `SlimShadyIAm [iPhone 12, 14.2]`. See !listdevices to see the list of possible devices. Example usage ------------- !adddevice <device name> Parameters ---------- device : str "device user wants to use" """ new_nick = ctx.author.display_name # check if user already has a device in their nick if re.match(self.devices_test, ctx.author.display_name): # they already have a device set prompt = await ctx.send_warning( description= "You already have a device nickname set. Would you like to modify it?" ) prompt_data = context.PromptDataReaction(prompt, ['β ', 'β'], timeout=15, delete_after=True) response, _ = await ctx.prompt_reaction(prompt_data) if response is None or response == 'β': # timeout or X reacted await ctx.send_warning( description="Cancelled adding device to your name.", delete_after=5) await ctx.message.delete(delay=5) return elif response == 'β ': # user wants to remove existing device, let's do that new_nick = re.sub(self.devices_remove_re, "", ctx.author.display_name).strip() if len(new_nick) > 32: raise commands.BadArgument("Nickname too long") await ctx.send_success("Alright, we'll swap your device!", delete_after=5) if not device.split(" ")[0].lower() in self.possible_devices: raise commands.BadArgument( "Unsupported device. Please see `!listdevices` for possible devices." ) the_device = await self.find_device_from_ipsw_me(device) # did we find a device with given name? if the_device is None: raise commands.BadArgument("Device doesn't exist!") # prompt user for which firmware they want in their name firmware = await self.prompt_for_firmware(ctx, the_device) # change the user's nickname! if firmware is not None: name = the_device["name"] name = name.replace(' Plus', '+') name = name.replace('Pro Max', 'PM') new_nick = f"{new_nick} [{name}, {firmware}]" if len(new_nick) > 32: raise commands.BadArgument("Nickname too long! Aborting.") await ctx.author.edit(nick=new_nick) await ctx.send_success("Changed your nickname!", delete_after=5) await ctx.message.delete(delay=5)