async def check_tattletale(reaction: discord.Reaction): if reaction.emoji != REACTION_EMOJI or reaction.count < REACTION_THRESHOLD: return m = reaction.message if m.author.bot: return # If enough users have flagged a message, take the following actions: # - Remove the flagged message # - Time out the flagged user # - Notify staff, both of the offending message as well as who reacted, for potential abuse # Limited rollout: Only count reactions by users with certain role reactors = [x async for x in reaction.users()] num_valid_reactors = len([x for x in reactors if check_roles(x, TTL_ROLES)]) if num_valid_reactors < REACTION_THRESHOLD: return reactor_list = "\n".join([str(x) for x in reactors]) if not m.author.is_timed_out(): await m.author.timeout(timedelta(minutes=TIMEOUT_MIN)) try: await m.delete() msg_txt = combine_message(m) staff_chan = client.get_channel(MAILBOX) report = f"Users have flagged a message by <@{m.author.id}> in <#{m.channel.id}>: {msg_txt}.\n\nThese are the users who flagged:\n {reactor_list}" await staff_chan.send(report) except discord.NotFound: pass
def check(reaction: Reaction, user): if reaction.message.id == message.id and user.id != self.user.id: asyncio.ensure_future(reaction.remove(user)) if user != target or reaction.message.id != message.id: return False return emotes is None or len(emotes) == 0 or str( reaction.emoji) in [str(e) for e in emotes]
async def buttonctrl(cls, reaction: discord.Reaction, user: discord.User, pgr: pager.Pager, *, double: int = 5): emj = reaction.emoji try: if emj == '⏪': if double == 0: pgr.go_first(exc=True) else: pgr.minus(double, exc=True) elif emj == '⏩': if double == 0: pgr.go_end(exc=True) else: pgr.plus(double, exc=True) elif emj == '◀': pgr.prev(exc=True) elif emj == '▶': pgr.next(exc=True) elif emj == '⏹': return reaction.message.clear_reactions() except StopIteration: await reaction.remove(user) return else: return reaction.remove(user)
async def on_raw_reaction_add(self, event: RawReactionActionEvent): reaction_data = dict(me=False, count=0) reaction = Reaction(message=self.message, data=reaction_data, emoji=str(event.emoji)) user = await self.bot.fetch_user(event.user_id) await self.on_reaction_add(reaction, user)
async def addReaction(self, reaction: discord.Reaction): try: message: discord.Message message = reaction.message name = message.channel.name if str(name).startswith("school-work-sports"): name = "ssr" emoji_name = "" if reaction.custom_emoji: emoji_name = reaction.emoji.name else: emoji_name = str(emoji.demojize(reaction.emoji)).replace( ":", "") date = str(message.created_at).split(".")[0] user: discord.User async for user in reaction.users(): #command = 'INSERT INTO `' + name + '` VALUES ("' + user.name + '","' + message.author.name + '","' + emoji_name + '","' + date + '")' command = f'INSERT INTO `{name}` VALUES ("{user.name}","{message.author.name}","{emoji_name}","{date}")' self.cursor.execute(command) self.mydb.commit() except: pass
async def on_reaction_add(self, reaction: discord.Reaction, user: discord.Member): member = conn.execute( "SELECT * FROM members WHERE main_account_id == ? AND id = ? AND member_enabled = 1", [user.id, reaction.message.author.id], ).fetchone() # Check for correct user if member is not None: # Delete React if type(reaction.emoji) is str: if (emoji.demojize(reaction.emoji) or "") == ":cross_mark:": # Discord name: x await reaction.message.delete() # Edit React if (emoji.demojize(reaction.emoji) or "") == ":memo:": # Discord name: pencil self.edit_session.append(user.id) embed = discord.Embed( description= f"You are now editing a [message]({reaction.message.jump_url})\nYour next message will replace it's contents.", color=discord.Color.orange(), ) embed.set_footer(text='Type "cancel" to cancel edit') instructions = await reaction.message.channel.send( f"{user.mention}", embed=embed) try: # Wait 30 seconds for new message message = await self.bot.wait_for( "message", check=lambda message: message.author.id == member[ "main_account_id"], timeout=30, ) # On new message, do all the things # If message isn't "cancel" then momentarily switch bot tokens and edit the message if message.content.lower() != "cancel": while await helper.edit_as( reaction.message, message.content, member["token"]) is False: await reset() # Delete instructions and edit message with main bot (again, low-level is easier without ctx) await instructions.delete() # bot.http.delete_message(instructions.channel.id, instructions.id), await message.delete() # bot.http.delete_message(message.channel.id, message.id), await reaction.remove(user) # On timeout, delete instructions and reaction except asyncio.TimeoutError: # Delete instructions with main bot await asyncio.gather(instructions.delete(), reaction.remove(user)) self.edit_session.remove(user.id)
async def remove_reactions(self, reaction: discord.Reaction) -> None: """Remove all candy/skull reactions.""" try: async for user in reaction.users(): await reaction.message.remove_reaction(reaction.emoji, user) except discord.HTTPException: pass
def update_reaction(self, react: discord.Reaction): if react.is_custom_emoji(): for reaction in self.reactions: if reaction[0] == str(react.emoji): reaction[1] = react.count + reaction[1] return self.reactions.append([str(react.emoji), react.count]) return return
async def get_user_ids(r: discord.Reaction) -> Set[int]: """ Extracts user ids from a discord reaction. This only exists because testing anything involving discord reactions is a pain, and we want to mock it out. """ pids = set() async for u in r.users(): pids.add(u.id) return pids
async def on_raw_reaction_add(self, event: RawReactionActionEvent): """ This listener is used for DMs to bypass having to use member intents """ message = await self.channel.fetch_message(event.message_id) reaction_data = dict(me=False, count=0) reaction = Reaction(message=message, data=reaction_data, emoji=str(event.emoji)) user = await self.bot.fetch_user(event.user_id) await self.on_reaction_add(reaction, user)
async def parse_message_reaction_remove_emoji(self, data, old): emoji = PartialEmoji.with_state( self, id=utils._get_as_snowflake(data["emoji"], "id"), name=data["emoji"]["name"], ) raw = RawReactionClearEmojiEvent(data, emoji) self.dispatch("raw_reaction_clear_emoji", raw) message = await self._get_message(raw.message_id) if message: reaction = Reaction(message=message, data=data, emoji=await self._upgrade_partial_emoji(emoji)) self.dispatch("reaction_clear_emoji", reaction)
async def parse_message_reaction_remove(self, data, old): emoji = PartialEmoji.with_state( self, id=utils._get_as_snowflake(data["emoji"], "id"), name=data["emoji"]["name"], ) raw = RawReactionActionEvent(data, emoji, "REACTION_REMOVE") self.dispatch("raw_reaction_remove", raw) message = await self._get_message(raw.message_id) if message: reaction = Reaction(message=message, data=data, emoji=await self._upgrade_partial_emoji(emoji)) user = await self._get_reaction_user(message.channel, raw.user_id) if user: self.dispatch("reaction_remove", reaction, user)
def check(self, reaction: discord.Reaction, user: discord.Member): if self.op.id != user.id or reaction.message.id != self.message.id: return False emoji = reaction.emoji if emoji != "◀️" and emoji != "▶️": return False asyncio.get_running_loop().create_task(reaction.remove(user)) if emoji == "◀️" and self.page > 0: self.page += -1 elif emoji == "▶️" and self.page < self.total_pages: self.page += 1 else: return False return True
async def parse_message_reaction_add(self, data, old): emoji = PartialEmoji.with_state( self, id=utils._get_as_snowflake(data["emoji"], "id"), animated=data["emoji"].get("animated", False), name=data["emoji"]["name"], ) raw = RawReactionActionEvent(data, emoji, "REACTION_ADD") member = data.get("member") if member: guild = await self._get_guild(raw.guild_id) if guild: raw.member = Member(guild=guild, state=self, data=member) self.dispatch("raw_reaction_add", raw) message = await self._get_message(raw.message_id) if message: reaction = Reaction(message=message, data=data, emoji=await self._upgrade_partial_emoji(emoji)) user = raw.member or await self._get_reaction_user( message.channel, raw.user_id) if user: self.dispatch("reaction_add", reaction, user)
async def archive(self, message: Message, reaction: Reaction) -> None: """ Archive the given message by sending it in the archive channel and removing it from the queue. @param message: discord.Message: The message to archive @param reaction: discord.Reaction: Reaction that triggered the archive event @return: """ # Get the archive channel try: channel = message.guild.get_channel( self.get_server_conf(message.guild).archive.id) if channel is None: self.get_server_conf(message.guild).set_archive(None) raise TypeError if not channel.permissions_for(message.guild.me).send_messages: raise ValueError # Channel exists, but the bot can't send messages in there. except (TypeError, AttributeError, ValueError) as e: reactor: Optional[Member] = None async for user in reaction.users( ): # Find the manager that tried to archive this message to mention them. if user == self.user: continue reactor = user break await reaction.remove(reactor) if type(e) == ValueError: m = await message.channel.send( "**I don't have permission to send messages in the archive channel!**" ) else: m = await message.channel.send( f"{reactor.mention} There is not yet an archive channel for this server. " f"Use the `{PREFIX}archive` command in the channel you wish to use as " f"archive.") await asyncio.sleep(7) await m.delete() return # Create the embed to send in the archive channel author = message.author embed = Embed( title= f"Question by {author.display_name} ({author.name}#{author.discriminator}) in " f"#{message.channel}", timestamp=message.created_at, colour=0xeeeeee) embed.set_thumbnail(url=author.avatar_url) embed.add_field(name=f"{author.display_name}:", value=message.content, inline=False) # Look for relevant messages to include in the archive. async for m in message.channel.history( after=message, limit=100): # Look in history from `message` to now if m.author == message.guild.me: # Ignore the bot continue if m.author == author: # Add messages from the same user to the chain embed.add_field(name=f"{m.author.display_name}:", value=m.content, inline=False) await m.delete() elif m.reference is not None: # Add messages that reply to the question's author if isinstance(ref := m.reference.resolved, Message) and ref.author == author: embed.add_field(name=f"{m.author.display_name} replied:", value=m.content, inline=False) await m.delete() elif author in m.mentions: # Add messages that mention the author of the question embed.add_field(name=f"{m.author.display_name}:", value=m.content, inline=False) await m.delete()
def footer_from_reaction(embed: Embed, reaction: Reaction): if reaction.is_custom_emoji(): embed.set_footer(icon_url=reaction.emoji.url, text=f'{reaction.count}') else: embed.set_footer(text=f'{reaction.emoji} {reaction.count}')
async def filter_bot_user_reactions(reaction: Reaction): return [user async for user in reaction.users() if not user.bot]