Пример #1
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
Пример #2
0
 async def check_authors_clan_contact_role(context, announces):
     """Check that all announce authors have the clan contact role."""
     if missing_clan_contact_role_announces := list(filter(
             lambda a: not checker.has_guild_role(context.guild, a.author, Stats.CLAN_CONTACT_ROLE_NAME), announces
     )):
         for block in utils.make_message_blocks([
             f"{announce.author.mention} ne possède pas le rôle @{Stats.CLAN_CONTACT_ROLE_NAME} nécessaire à la "
             f"publication d'une annonce : {announce.jump_url}" for announce in missing_clan_contact_role_announces
         ]):
             await context.send(block)
Пример #3
0
 async def on_reaction_add(self, reaction, user):
     message = reaction.message
     message_id = message.id
     emoji = reaction.emoji
     if message_id in Poll.pending_polls:
         poll_emoji_codes = Poll.pending_polls[message_id]['emoji_codes']
         same_emoji = any([
             emoji == poll_emoji_code
             if isinstance(emoji, str) else emoji.id == poll_emoji_code
             for poll_emoji_code in poll_emoji_codes
         ])
         if same_emoji and not user.bot:
             if required_role_name := Poll.pending_polls[message_id][
                     'required_role_name']:
                 if not checker.has_guild_role(self.guild, user,
                                               required_role_name):
                     try:
                         await utils.try_dm(
                             user,
                             f"Vous devez avoir le rôle @{required_role_name} pour "
                             f"participer à ce sondage.")
                         await message.remove_reaction(emoji, user)
                         return  # Don't enter other check blocks
                     except (discord.errors.HTTPException,
                             discord.errors.NotFound,
                             discord.errors.Forbidden):
                         pass
             if Poll.pending_polls[message_id]['is_exclusive']:
                 for existing_reaction in list(
                         filter(
                             lambda r: r.emoji != emoji and
                             (r.emoji
                              if isinstance(r.emoji, str) else r.emoji.id
                              ) in poll_emoji_codes, message.reactions)):
                     existing_reaction_users = await existing_reaction.users(
                     ).flatten()
                     if discord.utils.get(existing_reaction_users,
                                          id=user.id):
                         try:
                             await utils.try_dm(
                                 user,
                                 f"Vous ne pouvez voter que pour une seule option."
                             )
                             await message.remove_reaction(emoji, user)
                             return  # Don't enter other check blocks
                         except (discord.errors.HTTPException,
                                 discord.errors.NotFound,
                                 discord.errors.Forbidden):
                             pass
                         break
Пример #4
0
    async def validate_recruitments(self, context):
        if not checker.has_guild_role(context.guild, context.author,
                                      Stats.CLAN_CONTACT_ROLE_NAME):
            raise exceptions.MissingRoles([Stats.CLAN_CONTACT_ROLE_NAME])

        recruitment_channel = self.guild.get_channel(
            Admin.RECRUITMENT_CHANNEL_ID)
        all_recruitment_announces = await recruitment_channel.history(
        ).flatten()
        recruitment_announces = list(
            filter(lambda a: a.author == context.author,
                   all_recruitment_announces))
        last_recruitment_announce = recruitment_announces and recruitment_announces[
            0]

        if not last_recruitment_announce:
            await context.send("Aucune annonce de recrutement n'a été trouvée."
                               )
        else:
            patched_context = copy(context)
            patched_context.send = self.mock_send
            validation_succeeded = True
            if await Admin.check_recruitment_announces_uniqueness(
                    patched_context, recruitment_announces):
                validation_succeeded = False
                await context.send(
                    f"Tu as publié {len(recruitment_announces)} annonces. Une seule est autorisée à la fois."
                )
            if await Admin.check_recruitment_announces_length(
                    patched_context, [last_recruitment_announce]):
                validation_succeeded = False
                apparent_length = Admin.compute_apparent_length(
                    last_recruitment_announce)
                await context.send(
                    f"L'annonce est d'une longueur apparente de **{apparent_length}** caractères (max "
                    f"{Admin.MAX_RECRUITMENT_ANNOUNCE_LENGTH}). Réduit sa longueur en retirant du contenu ou en "
                    f"réduisant le nombre de sauts de lignes.")
            if await Admin.check_recruitment_announces_embeds(
                    patched_context, [last_recruitment_announce]):
                validation_succeeded = False
                await context.send(
                    f"Ton annonce contient un embed, ce qui n'est pas autorisé. Utilise un raccourcisseur d'URLs comme "
                    f"<https://tinyurl.com> pour héberger tes liens.")
            if await Admin.check_recruitment_announces_timespan(
                    patched_context, recruitment_channel,
                [last_recruitment_announce]):
                validation_succeeded = False
                await context.send(
                    f"Ton annonce a été postée avant le délai minimum de {Admin.MIN_RECRUITMENT_ANNOUNCE_TIMESPAN} "
                    f"jours entre deux annonces.")

            if validation_succeeded:
                await context.send(
                    f"L'annonce ne présente aucun problème. :ok_hand: ")

            last_announce_time_localized = converter.to_utc(
                zbot.db.load_recruitment_announces_data(
                    query={'author': context.author.id},
                    order=[('time', -1)])[0]['time'])
            min_timespan = datetime.timedelta(
                # Apply a tolerance of 2 days for players interpreting the 30 days range as "one month".
                # This is a subtraction because the resulting value is the number of days to wait before posting again.
                days=Admin.MIN_RECRUITMENT_ANNOUNCE_TIMESPAN -
                Admin.RECRUITMENT_ANNOUNCE_TIMESPAN_TOLERANCE)
            next_announce_time_localized = last_announce_time_localized + min_timespan
            await context.send(
                f"Tu pourras à nouveau poster une annonce à partir du "
                f"{converter.to_human_format(next_announce_time_localized)}.")