Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
 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]
Ejemplo n.º 3
0
 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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
 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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
 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)
Ejemplo n.º 12
0
 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)
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
 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)
Ejemplo n.º 15
0
    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()
Ejemplo n.º 16
0
 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}')
Ejemplo n.º 17
0
async def filter_bot_user_reactions(reaction: Reaction):
    return [user async for user in reaction.users() if not user.bot]