Пример #1
0
    def stars_update(self, event, mid):
        try:
            entry = StarboardEntry.select(StarboardEntry, Message).join(
                Message
            ).where(
                (Message.guild_id == event.guild.id) &
                (StarboardEntry.message_id == mid)
            ).get()
        except StarboardEntry.DoesNotExist:
            return event.msg.reply(':warning: no starboard entry exists with that message id')

        msg = self.client.api.channels_messages_get(
            entry.message.channel_id,
            entry.message_id)

        users = [i.id for i in msg.get_reactors(STAR_EMOJI)]

        if set(users) != set(entry.stars):
            StarboardEntry.update(
                stars=users,
                dirty=True
            ).where(
                (StarboardEntry.message_id == entry.message_id)
            ).execute()
        else:
            StarboardEntry.update(
                dirty=True
            ).where(
                (StarboardEntry.message_id == mid)
            ).execute()

        self.queue_update(event.guild.id, event.config)
        event.msg.reply(u'Forcing an update on message {}'.format(mid))
Пример #2
0
    def post_star(self, star, source_msg, starboard_id, config):
        # Generate the embed and post it
        content, embed = self.get_embed(star, source_msg, config)

        if not star.star_message_id:
            try:
                msg = self.client.api.channels_messages_create(starboard_id,
                                                               content,
                                                               embed=embed)
            except:
                self.log.exception('Failed to post starboard message: ')
                return
        else:
            try:
                msg = self.client.api.channels_messages_modify(
                    star.star_channel_id,
                    star.star_message_id,
                    content,
                    embed=embed)
            except APIException as e:
                # If we get a 10008, assume this message was deleted
                if e.code == ERR_UNKNOWN_MESSAGE:
                    star.star_message_id = None
                    star.star_channel_id = None

                    # Recurse so we repost
                    return self.post_star(star, source_msg, starboard_id,
                                          config)

        # Update our starboard entry
        StarboardEntry.update(
            dirty=False,
            star_channel_id=msg.channel_id,
            star_message_id=msg.id,
        ).where((StarboardEntry.message_id == star.message_id)).execute()
Пример #3
0
    def force_update_stars(self, event):
        # First, iterate over stars and repull their reaction count
        stars = StarboardEntry.select().join(Message).where(
            (Message.guild_id == event.guild.id)
            & (~(StarboardEntry.star_message_id >> None))).order_by(
                Message.timestamp.desc()).limit(100)

        msg = event.msg.reply('Updating starboard...')

        for star in stars:
            info_msg = self.client.api.channels_messages_get(
                star.message.channel_id, star.message_id)

            users = [i.id for i in msg.get_reactors(STAR_EMOJI)]

            if set(users) != set(star.stars):
                self.log.warning('star %s had outdated reactors list %s vs %s',
                                 star.message_id, users, star.stars)

                StarboardEntry.update(
                    stars=users,
                    dirty=True,
                ).where(
                    (StarboardEntry.message_id == star.message_id)).execute()

        info_msg.edit('Starboard updated!')
        self.queue_update(event.guild.id, event.config)
Пример #4
0
    def post_star(self, star, source_msg, starboard_id, config):
        # Generate the embed and post it
        content, embed = self.get_embed(star, source_msg, config)

        if not star.star_message_id:
            try:
                msg = self.client.api.channels_messages_create(starboard_id,
                                                               content,
                                                               embed=embed)
            except:
                self.log.exception('Failed to post starboard message: ')
                return
        else:
            msg = self.client.api.channels_messages_modify(
                star.star_channel_id,
                star.star_message_id,
                content,
                embed=embed)

        # Update our starboard entry
        StarboardEntry.update(
            dirty=False,
            star_channel_id=msg.channel_id,
            star_message_id=msg.id,
        ).where((StarboardEntry.message_id == star.message_id)).execute()
Пример #5
0
    def stars_stats(self, event, user=None):
        if user:
            try:
                given_stars = list(StarboardEntry.select(
                    fn.COUNT('*'),
                ).join(Message).where(
                    (~ (StarboardEntry.star_message_id >> None)) &
                    (StarboardEntry.stars.contains(user.id)) &
                    (Message.guild_id == event.guild.id)
                ).tuples())[0][0]

                recieved_stars_posts, recieved_stars_total = list(StarboardEntry.select(
                    fn.COUNT('*'),
                    fn.SUM(fn.array_length(StarboardEntry.stars, 1)),
                ).join(Message).where(
                    (~ (StarboardEntry.star_message_id >> None)) &
                    (Message.author_id == user.id) &
                    (Message.guild_id == event.guild.id)
                ).tuples())[0]
            except:
                return event.msg.reply(':warning: failed to crunch the numbers on that user')

            embed = MessageEmbed()
            embed.color = 0xffd700
            embed.title = user.username
            embed.set_thumbnail(url=user.avatar_url)
            embed.add_field(name='Total Stars Given', value=str(given_stars), inline=True)
            embed.add_field(name='Total Posts w/ Stars', value=str(recieved_stars_posts), inline=True)
            embed.add_field(name='Total Stars Recieved', value=str(recieved_stars_total), inline=True)
            # embed.add_field(name='Star Rank', value='#{}'.format(recieved_stars_rank), inline=True)
            return event.msg.reply('', embed=embed)

        total_starred_posts, total_stars = list(StarboardEntry.select(
            fn.COUNT('*'),
            fn.SUM(fn.array_length(StarboardEntry.stars, 1)),
        ).join(Message).where(
            (~ (StarboardEntry.star_message_id >> None)) &
            (Message.guild_id == event.guild.id)
        ).tuples())[0]

        top_users = list(StarboardEntry.select(fn.SUM(fn.array_length(StarboardEntry.stars, 1)), User.user_id).join(
            Message,
        ).join(
            User,
            on=(Message.author_id == User.user_id),
        ).where(
            (~ (StarboardEntry.star_message_id >> None)) &
            (fn.array_length(StarboardEntry.stars, 1) > 0) &
            (Message.guild_id == event.guild.id)
        ).group_by(User).order_by(fn.SUM(fn.array_length(StarboardEntry.stars, 1)).desc()).limit(5).tuples())

        embed = MessageEmbed()
        embed.color = 0xffd700
        embed.title = 'Star Stats'
        embed.add_field(name='Total Stars Given', value=total_stars, inline=True)
        embed.add_field(name='Total Starred Posts', value=total_starred_posts, inline=True)
        embed.add_field(name='Top Star Recievers', value='\n'.join(
            '{}. <@{}> ({})'.format(idx + 1, row[1], row[0]) for idx, row in enumerate(top_users)
        ))
        event.msg.reply('', embed=embed)
Пример #6
0
 def on_message_reaction_remove_all(self, event):
     StarboardEntry.update(
         stars=[],
         blocked_stars=[],
         dirty=True
     ).where(
         (StarboardEntry.message_id == event.message_id)
     ).execute()
     self.queue_update(event.guild.id, event.config)
Пример #7
0
    def post_star(self, star, source_msg, starboard_id, config):
        # Generate the embed and post it
        content, embed = self.get_embed(star, source_msg, config)

        if not source_msg.guild.channels.get(starboard_id):
            target = self.state.channels.get(starboard_id)
            if not (target and target.guild):
                return
            return self.log.exception((
                u'post_star: attempted cross-guild post from '
                u'{} ({}) to {} ({}) - #{} ({})'.format(
                    source_msg.guild.name,
                    source_msg.guild.id,
                    target.guild.name,
                    target.guild.id,
                    target.name,
                    target.id
                )
            ))

        if not star.star_message_id:
            try:
                msg = self.client.api.channels_messages_create(
                        starboard_id,
                        content,
                        embed=embed)
            except:
                self.log.exception('Failed to post starboard message: ')
                return
        else:
            try:
                msg = self.client.api.channels_messages_modify(
                    star.star_channel_id,
                    star.star_message_id,
                    content,
                    embed=embed)
            except APIException as e:
                # If we get a 10008, assume this message was deleted
                if e.code == ERR_UNKNOWN_MESSAGE:
                    star.star_message_id = None
                    star.star_channel_id = None

                    # Recurse so we repost
                    return self.post_star(star, source_msg, starboard_id, config)

        # Update our starboard entry
        StarboardEntry.update(
            dirty=False,
            star_channel_id=msg.channel_id,
            star_message_id=msg.id,
        ).where(
            (StarboardEntry.message_id == star.message_id)
        ).execute()
Пример #8
0
    def on_message_reaction_add(self, event):
        try:
            # Grab the message, and JOIN across blocks to check if a block exists
            #  for either the message author or the reactor.
            msg = Message.select(
                Message,
                StarboardBlock
            ).join(
                StarboardBlock,
                join_type=JOIN.LEFT_OUTER,
                on=(
                    (
                        (Message.author_id == StarboardBlock.user_id) |
                        (StarboardBlock.user_id == event.user_id)
                    ) &
                    (Message.guild_id == StarboardBlock.guild_id)
                )
            ).where(
                (Message.id == event.message_id)
            ).get()
        except Message.DoesNotExist:
            return

        # If either the reaction or message author is blocked, prevent this action
        if msg.starboardblock.user_id:
            event.delete()
            return

        # Check if the board prevents self stars
        sb_id, board = event.config.get_board(event.channel_id)
        if not sb_id:
            return

        if board.prevent_self_star and msg.author_id == event.user_id:
            event.delete()
            return

        try:
            StarboardEntry.add_star(event.message_id, event.user_id)
        except peewee.IntegrityError:
            msg = self.client.api.channels_messages_get(
                event.channel_id,
                event.message_id)

            if msg:
                Message.from_disco_message(msg)
                StarboardEntry.add_star(event.message_id, event.user_id)
            else:
                return

        self.queue_update(event.guild.id, event.config)
Пример #9
0
    def stars_unblock(self, event, entity):
        count = StarboardBlock.delete().where(
            (StarboardBlock.guild_id == event.guild.id)
            & (StarboardBlock.entity_id == entity.id)).execute()

        if not count:
            raise CommandFail('{} is already allowed on the starboard'.format(
                entity, ))

        # Reenable posts and stars for this user
        StarboardEntry.unblock(entity.id)

        # Finally, queue an update for the guild
        self.queue_update(event.guild.id, event.config)

        raise CommandSuccess('Allowed {} on the starboard'.format(entity, ))
Пример #10
0
    def unlock_stars(self, event, block=False):
        if event.guild.id not in self.locks:
            event.msg.reply(':warning: starboard is not locked')
            return

        # If the user does not wish to have the messages starred during the lock
        #  duration posted, block them entirely and unflag them as dirty.
        if block:
            StarboardEntry.update(dirty=False, blocked=True).join(Message).where(
                (StarboardEntry.dirty == 1) &
                (Message.guild_id == event.guild.id) &
                (Message.timestamp > (datetime.utcnow() - timedelta(hours=32)))
            ).execute()

        del self.locks[event.guild.id]
        event.msg.reply(':white_check_mark: starboard has been unlocked')
Пример #11
0
    def stars_unblock(self, event, user):
        count = StarboardBlock.delete().where(
            (StarboardBlock.guild_id == event.guild.id)
            & (StarboardBlock.user_id == user.id)).execute()

        if not count:
            raise CommandFail('{} was not blocked from the starboard'.format(
                user, ))

        # Renable posts and stars for this user
        StarboardEntry.unblock_user(user.id)

        # Finally, queue an update for the guild
        self.queue_update(event.guild.id, event.config)

        raise CommandSuccess('Unblocked {} from the starboard'.format(user, ))
Пример #12
0
    def stars_unblock(self, event, user):
        count = StarboardBlock.delete().where(
            (StarboardBlock.guild_id == event.guild.id)
            & (StarboardBlock.user_id == user.id)).execute()

        if not count:
            event.msg.reply(u'{} was not blocked from the starboard'.format(
                user, ))
            return

        # Renable posts and stars for this user
        StarboardEntry.unblock_user(user.id)

        # Finally, queue an update for the guild
        self.queue_update(event.guild.id, event.config, event)

        event.msg.reply(u'Unblocked {} from the starboard'.format(user, ))
Пример #13
0
    def on_message_update(self, event):
        sb_id, sb_config = event.config.get_board(event.channel_id)
        if not sb_id:
            return

        count = StarboardEntry.update(dirty=True).where(
            (StarboardEntry.message_id == event.message.id)).execute()

        if count:
            self.queue_update(event.guild.id, event.config)
Пример #14
0
    def delete_star(self, star, update=True):
        try:
            self.client.api.channels_messages_delete(
                star.star_channel_id,
                star.star_message_id,
            )
        except:
            pass

        if update:
            StarboardEntry.update(
                dirty=False,
                star_channel_id=None,
                star_message_id=None,
            ).where((StarboardEntry.message_id == star.message_id)).execute()

            # Update this for post_star
            star.star_channel_id = None
            star.star_message_id = None
Пример #15
0
    def stars_block(self, event, user):
        _, created = StarboardBlock.get_or_create(guild_id=event.guild.id,
                                                  user_id=user.id,
                                                  defaults={
                                                      'actor_id':
                                                      event.author.id,
                                                  })

        if not created:
            event.msg.reply(u'{} is already blocked from the starboard'.format(
                user, ))
            return

        # Update the starboard, remove stars and posts
        StarboardEntry.block_user(user.id)

        # Finally, queue an update for the guild
        self.queue_update(event.guild.id, event.config)

        event.msg.reply(u'Blocked {} from the starboard'.format(user, ))
Пример #16
0
    def stars_block(self, event, entity):
        _, created = StarboardBlock.get_or_create(guild_id=event.guild.id,
                                                  user_id=entity.id,
                                                  defaults={
                                                      'actor_id':
                                                      event.author.id,
                                                  })

        if not created:
            raise CommandFail(
                '{} is already not allowed on the starboard'.format(entity, ))

        # Update the starboard, remove stars and posts
        StarboardEntry.block(entity.id)

        # Finally, queue an update for the guild
        self.queue_update(event.guild.id, event.config)

        raise CommandSuccess('Disallowed {} from the starboard'.format(
            entity, ))
Пример #17
0
    def stars_hide(self, event, mid):
        count = StarboardEntry.update(
            blocked=True,
            dirty=True,
        ).where((StarboardEntry.message_id == mid)).execute()

        if not count:
            raise CommandFail('No starred message with that ID')

        self.queue_update(event.guild.id, event.config)
        raise CommandSuccess(
            'Message {} has been hidden from the starboard'.format(mid, ))
Пример #18
0
    def on_message_delete(self, event):
        sb_id, sb_config = event.config.get_board(event.channel_id)
        if not sb_id:
            return

        if sb_config.clear_on_delete:
            stars = list(StarboardEntry.delete().where(
                (StarboardEntry.message_id == event.id
                 )).returning(StarboardEntry).execute())

            for star in stars:
                self.delete_star(star, update=False)
Пример #19
0
    def stars_hide(self, event, mid):
        count = StarboardEntry.update(
            blocked=True,
            dirty=True,
        ).where((StarboardEntry.message_id == mid)).execute()

        if not count:
            event.msg.reply(u'No starred message with that ID')
            return

        self.queue_update(event.guild.id, event.config)
        event.msg.reply(
            u'Message {} has been hidden from the starboard'.format(mid, ))
Пример #20
0
    def update_starboard(self, guild_id, config, event):
        sb_id2, board = config.get_board(event.channel.id)
        if not sb_id2:
            return
        # Grab all dirty stars that where posted in the last 32 hours
        stars = StarboardEntry.select().join(Message).where(
            (StarboardEntry.dirty == 1) & (Message.guild_id == guild_id)
            & (Message.timestamp >
               (datetime.utcnow() - timedelta(hours=board.max_age))))

        for star in stars:
            sb_id, sb_config = config.get_board(star.message.channel_id)

            if not sb_id:
                StarboardEntry.update(dirty=False).where(
                    StarboardEntry.message_id == star.message_id).execute()
                continue

            # If this star has no stars, delete it from the starboard
            if not star.stars:
                if not star.star_channel_id:
                    StarboardEntry.update(
                        dirty=False).where(StarboardEntry.message_id ==
                                           star.message_id).execute()
                    continue

                self.delete_star(star)
                continue

            # Grab the original message
            try:
                source_msg = self.client.api.channels_messages_get(
                    star.message.channel_id, star.message_id)
            except:
                self.log.exception('Star message went missing %s / %s: ',
                                   star.message.channel_id, star.message_id)
                # TODO: really delete this
                self.delete_star(star, update=True)
                continue

            # If we previously posted this in the wrong starboard, delete it
            if star.star_channel_id and (star.star_channel_id != sb_id or len(
                    star.stars) < sb_config.min_stars) or star.blocked:
                self.delete_star(star, update=True)

            if len(star.stars) < sb_config.min_stars or star.blocked:
                StarboardEntry.update(dirty=False).where(
                    StarboardEntry.message_id == star.message_id).execute()
                continue

            self.post_star(star, source_msg, sb_id, sb_config)
Пример #21
0
    def stars_show(self, event, mid):
        try:
            star = StarboardEntry.select().join(Message).where(
                (Message.guild_id == event.guild.id)
                & (~(StarboardEntry.star_message_id >> None))
                & ((Message.id == mid)
                   | (StarboardEntry.star_message_id == mid))).get()
        except StarboardEntry.DoesNotExist:
            raise CommandFail('no starboard message with that id')

        _, sb_config = event.config.get_board(star.message.channel_id)

        try:
            source_msg = self.client.api.channels_messages_get(
                star.message.channel_id, star.message_id)
        except:
            raise CommandFail('no starboard message with that id')

        content, embed = self.get_embed(star, source_msg, sb_config)
        event.msg.reply(content, embed=embed)
Пример #22
0
 def on_message_reaction_remove(self, event):
     StarboardEntry.remove_star(event.message_id, event.user_id)
     self.queue_update(event.guild.id, event.config)
Пример #23
0
    def stars_update(self, event, mid):
        StarboardEntry.update(dirty=True).where(
            (StarboardEntry.message_id == mid)).execute()

        self.queue_update(event.guild.id, event.config)
        event.msg.reply(u'Forcing an update on message {}'.format(mid))