示例#1
0
    async def emojis(self,
                     context: commands.Context,
                     poll_id: int,
                     emoji_list: converter.to_emoji_list,
                     *,
                     options=""):
        message, channel, previous_emoji_list, is_exclusive, required_role_name, time, organizer = \
            await self.get_message_env(poll_id, raise_if_not_found=True)

        if context.author != organizer:
            checker.has_any_mod_role(context, print_error=True)
        if not context.author.permissions_in(channel).send_messages:
            raise exceptions.ForbiddenChannel(channel)
        if not emoji_list:
            raise commands.MissingRequiredArgument(
                context.command.params['emoji_list'])
        if len(emoji_list) > 20:
            raise exceptions.OversizedArgument(f"{len(emoji_list)} emojis",
                                               "20 emojis")
        required_role_name = utils.get_option_value(options, 'role')
        if required_role_name:
            utils.try_get(  # Raise if role does not exist
                self.guild.roles,
                error=exceptions.UnknownRole(required_role_name),
                name=required_role_name)

        is_exclusive = utils.is_option_enabled(options, 'exclusive')
        previous_reactions = [
            utils.try_get(message.reactions,
                          error=exceptions.MissingEmoji(previous_emoji),
                          emoji=previous_emoji)
            for previous_emoji in previous_emoji_list
        ]
        for previous_reaction in previous_reactions:
            await previous_reaction.remove(zbot.bot.user)
        for emoji in emoji_list:
            await message.add_reaction(emoji)
        embed = self.build_announce_embed(message.embeds[0].description,
                                          is_exclusive, required_role_name,
                                          organizer, time, self.guild.roles)
        await message.edit(embed=embed)

        job_id = self.pending_polls[message.id]['_id']
        poll_data = {
            'emoji_codes':
            list(map(lambda e: e if isinstance(e, str) else e.id, emoji_list)),
            'is_exclusive':
            is_exclusive,
            'required_role_name':
            required_role_name
        }
        zbot.db.update_poll_data(job_id, poll_data)
        self.pending_polls[message.id].update(poll_data)
        await context.send(
            f"Émojis du sondage d'identifiant `{poll_id}` mis à jour : <{message.jump_url}>"
        )
示例#2
0
    async def emoji(self, context: commands.Context, lottery_id: int,
                    emoji: typing.Union[discord.Emoji, str]):
        message, channel, previous_emoji, nb_winners, time, organizer = \
            await self.get_message_env(lottery_id, raise_if_not_found=True)

        if context.author != organizer:
            checker.has_any_mod_role(context, print_error=True)
        if isinstance(emoji, str) and emojis.emojis.count(emoji) != 1:
            raise exceptions.ForbiddenEmoji(emoji)

        previous_reaction = utils.try_get(
            message.reactions,
            error=exceptions.MissingEmoji(previous_emoji),
            emoji=previous_emoji)
        await previous_reaction.remove(zbot.bot.user)
        await message.add_reaction(emoji)
        embed = self.build_announce_embed(emoji, nb_winners, organizer, time,
                                          self.guild.roles)
        await message.edit(embed=embed)

        job_id = self.pending_lotteries[message.id]['_id']
        lottery_data = {
            'emoji_code': emoji if isinstance(emoji, str) else emoji.id
        }
        zbot.db.update_job_data(self.JOBSTORE, job_id, lottery_data)
        self.pending_lotteries[message.id].update(lottery_data)
        await context.send(
            f"Émoji du tirage au sort d'identifiant `{lottery_id}` remplacé par \"{emoji}\" : "
            f"<{message.jump_url}>")
示例#3
0
 async def count_votes(message, emoji_list, is_exclusive,
                       required_role_name):
     """Count the votes and compute the results of the poll."""
     reactions = [
         utils.try_get(message.reactions,
                       error=exceptions.MissingEmoji(emoji),
                       emoji=emoji) for emoji in emoji_list
     ]
     votes = {
         reaction.emoji: await reaction.users().flatten()
         for reaction in reactions
     }
     results = {}
     for emoji, voters in votes.items():
         valid_votes_count = 0
         for voter in voters:
             if voter.bot:
                 continue  # Exclude bot votes
             if is_exclusive and any([
                     voter in votes[other_emoji]
                     for other_emoji in votes if other_emoji != emoji
             ]):
                 continue  # Only count vote of voters having voted once in exclusive mode
             if required_role_name and not checker.has_guild_role(
                     message.guild, voter, required_role_name):
                 continue  # Only count vote of voters having the required role, if set
             valid_votes_count += 1
         results[emoji] = valid_votes_count
     return reactions, results
示例#4
0
 def build_announce_embed(
         description, is_exclusive, required_role_name, organizer, time, guild_roles
 ):
     embed = discord.Embed(
         title=f"Clôture du sondage le {converter.humanize_datetime(time)} :alarm_clock:",
         description=description,
         color=Poll.EMBED_COLOR,
     )
     embed.add_field(
         name="Participation",
         value="Réagissez avec un émoji ci-dessous." if is_exclusive
         else "Réagissez avec les émojis ci-dessous."
     )
     embed.add_field(
         name="Choix multiple",
         value="✅" if not is_exclusive else "❌"
     )
     embed.add_field(
         name="Rôle requis",
         value=utils.try_get(
             guild_roles,
             error=exceptions.UnknownRole(required_role_name),
             name=required_role_name
         ).mention if required_role_name else "Aucun"
     )
     embed.set_author(
         name=f"Organisateur : @{organizer.display_name}",
         icon_url=organizer.avatar_url
     )
     return embed
示例#5
0
 async def draw(message, emoji, nb_winners, seed=None):
     await Lottery.prepare_seed(seed)
     reaction = utils.try_get(message.reactions,
                              error=exceptions.MissingEmoji(emoji),
                              emoji=emoji)
     players, winners = await Lottery.pick_winners(message.guild, reaction,
                                                   nb_winners)
     return players, reaction, winners
示例#6
0
    async def simulate(self,
                       context: commands.Context,
                       src_channel: discord.TextChannel,
                       message_id: int,
                       emoji_list: converter.to_emoji_list = (),
                       dest_channel: discord.TextChannel = None,
                       *,
                       options=""):
        if dest_channel and not context.author.permissions_in(
                dest_channel).send_messages:
            raise exceptions.ForbiddenChannel(dest_channel)
        is_exclusive = utils.is_option_enabled(options, 'exclusive')
        required_role_name = utils.get_option_value(options, 'role')
        if required_role_name:
            utils.try_get(  # Raise if role does not exist
                self.guild.roles,
                error=exceptions.UnknownRole(required_role_name),
                name=required_role_name)

        message = await utils.try_get_message(
            src_channel,
            message_id,
            error=exceptions.MissingMessage(message_id))
        if not emoji_list:
            if len(message.reactions) == 0:
                raise exceptions.MissingConditionalArgument(
                    "Une liste d'émojis doit être fournie si le message ciblé n'a pas de réaction."
                )
            else:
                emoji_list = [reaction.emoji for reaction in message.reactions]
        elif len(emoji_list) > 20:
            raise exceptions.OversizedArgument(f"{len(emoji_list)} emojis",
                                               "20 emojis")

        reactions, results = await Poll.count_votes(message, emoji_list,
                                                    is_exclusive,
                                                    required_role_name)
        announcement = await (
            dest_channel
            or context).send("Évaluation des votes sur base des réactions.")
        await Poll.announce_results(results,
                                    message,
                                    announcement.channel,
                                    is_exclusive,
                                    required_role_name,
                                    dest_message=announcement)
示例#7
0
    async def announce_results(
            results: dict, src_message: discord.Message, channel: discord.TextChannel, is_exclusive,
            required_role_name, organizer: discord.User = None, dest_message: discord.Message = None
    ):
        announcement_embed = discord.Embed(
            title="Résultats du sondage",
            description=f"[Cliquez ici pour accéder au sondage 🗳️]({src_message.jump_url})",
            color=Poll.EMBED_COLOR
        )
        # Compute ranking of votes count: {votes_count: position, votes_count: position, ...}
        votes_ranking = {k: v for v, k in enumerate(sorted(set(results.values()), reverse=True), start=1)}
        # Compute ranking of emojis: {emoji: position, emoji: position, ...}
        emoji_ranking = {emoji: votes_ranking[vote_count] for emoji, vote_count in results.items()}
        ranking_medals = {1: "🥇", 2: "🥈", 3: "🥉"}
        for emoji, vote_count in results.items():
            rank = emoji_ranking[emoji]
            medal_message = f" {ranking_medals.get(rank, '')}" if vote_count > 0 else ""
            announcement_embed.add_field(
                name=f"{emoji}\u2000**# {rank}**",
                value=f"Votes: **{vote_count}**{medal_message}"
            )
        if organizer:
            announcement_embed.set_author(
                name=f"Organisateur : @{organizer.display_name}", icon_url=organizer.avatar_url)
        if dest_message:  # Poll simulation
            await dest_message.edit(embed=announcement_embed)
        else:  # Assessment of a poll
            dest_message = await channel.send(embed=announcement_embed)

            embed = discord.Embed(
                title="Sondage clôturé",
                description=f"[Cliquez ici pour accéder aux résultats 📊]({dest_message.jump_url})"
                            + (f"\n\n{src_message.embeds[0].description}"
                               if src_message.embeds[0].description else ""),
                color=Poll.EMBED_COLOR
            )
            embed.add_field(name="Choix multiple", value="✅" if not is_exclusive else "❌")
            embed.add_field(
                name="Rôle requis",
                value=utils.try_get(
                    src_message.guild.roles,
                    error=exceptions.UnknownRole(required_role_name),
                    name=required_role_name
                ).mention if required_role_name else "Aucun"
            )
            if organizer:
                embed.set_author(
                    name=f"Organisateur : @{organizer.display_name}", icon_url=organizer.avatar_url)
            await src_message.edit(embed=embed)

        logger.debug(f"Poll results: {results}")
示例#8
0
文件: server.py 项目: Zedd7/ZBot
 async def record_message_count(self, time):
     message_counts = []
     for channel_name in self.DISCUSSION_CHANNELS:
         channel = utils.try_get(self.guild.channels, name=channel_name)
         channel_message_count = len(await channel.history(
             after=converter.to_utc(time -
                                    datetime.timedelta(hours=1)).replace(
                                        tzinfo=None),
             limit=999).flatten())
         message_counts.append({
             'count': channel_message_count,
             'channel_id': channel.id
         })
     zbot.db.insert_timed_message_counts(time, message_counts)
示例#9
0
 def build_announce_embed(emoji, nb_winners, organizer, time, guild_roles):
     embed = discord.Embed(
         title=
         f"Tirage au sort le {converter.humanize_datetime(time)} :alarm_clock:",
         color=Lottery.EMBED_COLOR)
     embed.add_field(
         name="Nombre de gagnants",
         value=f"**{nb_winners}** joueur{('s' if nb_winners > 1 else '')}")
     embed.add_field(name="Inscription", value=f"Réagissez avec {emoji}")
     embed.add_field(name="Rôle requis",
                     value=utils.try_get(
                         guild_roles,
                         error=exceptions.UnknownRole(
                             Lottery.USER_ROLE_NAMES[0]),
                         name=Lottery.USER_ROLE_NAMES[0]).mention)
     embed.set_author(name=f"Organisateur : @{organizer.display_name}",
                      icon_url=organizer.avatar_url)
     return embed
示例#10
0
文件: info.py 项目: Itstrike20/ZBot
    async def members(self, context: commands.Context):
        role_sizes = {}
        for primary_role_name in self.PRIMARY_ROLES:
            guild_role = utils.try_get(context.guild.roles,
                                       name=primary_role_name)
            role_sizes[primary_role_name] = len(guild_role.members)

        embed = discord.Embed(
            title=f"Décompte des membres du serveur",
            description=f"Total : **{len(context.guild.members)}** membres pour "
            f"**{len(self.PRIMARY_ROLES)}** roles principaux",
            color=self.EMBED_COLOR)
        for role_name in self.PRIMARY_ROLES:
            embed.add_field(name=role_name,
                            value=f"**{role_sizes[role_name]}** membres",
                            inline=True)
        embed.add_field(name="Banni",
                        value=f"**{len(await context.guild.bans())}** boulets",
                        inline=True)
        await context.send(embed=embed)
示例#11
0
 async def cancel(self, context: commands.Context, poll_id: int):
     message, _, emoji_list, _, _, _, organizer = await self.get_message_env(
         poll_id, raise_if_not_found=False)
     if context.author != organizer:
         checker.has_any_mod_role(context, print_error=True)
     if message:
         for emoji in emoji_list:
             reaction = utils.try_get(
                 message.reactions, error=exceptions.MissingEmoji(emoji), emoji=emoji
             )
             await reaction.remove(zbot.bot.user)
         embed = discord.Embed(
             title=f"Sondage __annulé__ par {context.author.display_name}",
             description=message.embeds[0].description if message.embeds[0].description else "",
             color=Poll.EMBED_COLOR
         )
         embed.set_author(name=f"Organisateur : @{organizer.display_name}", icon_url=organizer.avatar_url)
         await message.edit(embed=embed)
         await message.unpin()
     self.remove_pending_poll(message.id, cancel_job=True)
     await context.send(f"Sondage d'identifiant `{poll_id}` annulé : <{message.jump_url}>")
示例#12
0
    async def cancel(self, context: commands.Context, lottery_id: int):
        message, _, emoji, _, _, organizer = await self.get_message_env(
            lottery_id, raise_if_not_found=False)

        if context.author != organizer:
            checker.has_any_mod_role(context, print_error=True)

        if message:
            reaction = utils.try_get(message.reactions,
                                     error=exceptions.MissingEmoji(emoji),
                                     emoji=emoji)
            await reaction.remove(zbot.bot.user)
            embed = discord.Embed(
                title=
                f"Tirage au sort __annulé__ par {context.author.display_name}",
                color=Lottery.EMBED_COLOR)
            embed.set_author(name=f"Organisateur : @{organizer.display_name}",
                             icon_url=organizer.avatar_url)
            await message.edit(embed=embed)
        self.remove_pending_lottery(message.id, cancel_job=True)
        await context.send(
            f"Tirage au sort d'identifiant `{lottery_id}` annulé : <{message.jump_url}>"
        )
示例#13
0
    async def start(self,
                    context: commands.Context,
                    announce: str,
                    description: str,
                    dest_channel: discord.TextChannel,
                    emoji_list: converter.to_emoji_list,
                    time: converter.to_future_datetime,
                    *,
                    options=""):
        # Check arguments
        if not context.author.permissions_in(dest_channel).send_messages:
            raise exceptions.ForbiddenChannel(dest_channel)
        if not emoji_list:
            raise commands.MissingRequiredArgument(
                context.command.params['emoji_list'])
        if len(emoji_list) > 20:
            raise exceptions.OversizedArgument(f"{len(emoji_list)} emojis",
                                               "20 emojis")
        do_announce = utils.is_option_enabled(options, 'do-announce')
        do_pin = utils.is_option_enabled(options, 'pin')
        if do_announce or do_pin:
            checker.has_any_mod_role(context, print_error=True)
        required_role_name = utils.get_option_value(options, 'role')
        if required_role_name:
            utils.try_get(  # Raise if role does not exist
                self.guild.roles,
                error=exceptions.UnknownRole(required_role_name),
                name=required_role_name)

        # Run command
        is_exclusive = utils.is_option_enabled(options, 'exclusive')
        organizer = context.author
        prefixed_announce = utils.make_announce(
            context.guild, announce, do_announce and self.ANNOUNCE_ROLE_NAME)
        embed = self.build_announce_embed(description, is_exclusive,
                                          required_role_name, organizer, time,
                                          self.guild.roles)
        message = await dest_channel.send(prefixed_announce, embed=embed)
        for emoji in emoji_list:
            await message.add_reaction(emoji)
        if do_pin:
            await message.pin()

        # Register data
        job_id = scheduler.schedule_stored_job(
            zbot.db.PENDING_POLLS_COLLECTION, time, self.close_poll,
            message.id).id
        poll_data = {
            'poll_id':
            self.get_next_poll_id(),
            'message_id':
            message.id,
            'channel_id':
            dest_channel.id,
            'emoji_codes':
            list(map(lambda e: e if isinstance(e, str) else e.id, emoji_list)),
            'organizer_id':
            organizer.id,
            'is_exclusive':
            is_exclusive,
            'required_role_name':
            required_role_name,
        }
        zbot.db.update_poll_data(job_id, poll_data)
        # Add data managed by scheduler later to avoid updating the database with them
        poll_data.update({
            '_id': job_id,
            'next_run_time': converter.to_timestamp(time)
        })
        self.pending_polls[message.id] = poll_data

        # Confirm command
        await context.send(
            f"Sondage d'identifiant `{poll_data['poll_id']}` programmé : <{message.jump_url}>."
        )