Exemplo n.º 1
0
    async def my_lists(self, ctx: commands.Context):
        """
        Show the lists the current user is subscribed to.
        :param ctx: The current context. (discord.ext.commands.Context)
        """

        guild_data = await get_guild_data(ctx.message.guild.id)
        subbed_lists = []

        # Error if no lists exist yet
        if not guild_data.notification_lists:
            msg = translate("no_existing_lists", await culture(ctx))
            return await ctx.send(msg)

        # Fetch the lists the author is subscribed to
        for list_name, list_data in guild_data.notification_lists.items():
            if ctx.author.id in list_data["users"]:
                subbed_lists.append(list_name)

        # Error if the author is not subscribed to any lists
        if len(subbed_lists) < 1:
            msg = translate("no_subscriptions_error", await culture(ctx))
            return await ctx.send(msg)

        # Show the user his lists
        msg = translate("your_lists_title", await
                        culture(ctx)) + "\n - " + "\n - ".join(
                            sorted(subbed_lists))
        await ctx.send(msg)
Exemplo n.º 2
0
async def command_help(ctx: commands.Context, command_name: str):
    """
    Builds and sends the help info on the given command to the current context.
    :param ctx: The current context. (discord.ext.commands.Context)
    :param command_name: The command to request help on. (str)
    """
    # TODO print aliases
    embed = discord.Embed()

    command = ctx.bot.get_command(str(command_name))

    title = ctx.prefix + command.name
    help_text = translate(command.help, await culture(ctx))

    if command.usage is None:
        title += '\n'
        embed.add_field(name=title, value=help_text, inline=False)
        return await send_embed(ctx, embed)

    title += '\u2000' + translate(command.usage, await culture(ctx)) + '\n'
    embed.add_field(name=title, value=help_text, inline=False)

    extra_info = translate("help_info_arguments", await culture(ctx))
    embed.add_field(name=empty, value=extra_info, inline=False)

    await send_embed(ctx, embed)
Exemplo n.º 3
0
    async def remove_youtube_channel(self, ctx: commands.Context,
                                     youtube_channel_id: str):
        """
        Remove a Youtube channel that was being notified
        :param ctx: The current context. (discord.ext.commands.Context)
        :param youtube_channel_id: The Youtube channel to be notified of (str)
        """

        guild_data = await get_guild_data(ctx.message.guild.id)
        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        remove_response = await guild_data.remove_youtube_channel(
            youtube_channel_id)
        msg = ""
        if remove_response:
            msg = translate("youtube_removed", await
                            culture(ctx)).format(youtube_channel_id)
        else:
            msg = translate("youtube_no_exists", await
                            culture(ctx)).format(youtube_channel_id)
        info(msg)
        await ctx.send(msg)
Exemplo n.º 4
0
    async def act_unsubscribe(self, ctx: commands.Context, list_name: str,
                              user_id: int):
        """
        Unsubscribes the user from the provided list
        :param ctx: The current context. (discord.ext.commands.Context)
        :param list_name: The list to unsubscribe from. (str)
        :param user_id: the user to unsubscribe (int)
        """
        # make sure list is lowercase
        list_name = list_name.lower()

        guild_data = await get_guild_data(ctx.message.guild.id)

        # Error if list does not exist
        if not guild_data.does_list_exist(list_name):
            msg = translate("list_err_does_not_exit", await culture(ctx))
            return await ctx.send(msg)

        # Unsubscribe user and error if failed
        if not await guild_data.unsub_user(list_name, user_id):
            msg = translate("list_err_not_subscribed", await
                            culture(ctx)).format(str(user_id), list_name)
            return await ctx.send(msg)

        # Unsubscribe successful, show result to user
        msg = translate("list_unsubscribed", await
                        culture(ctx)).format(str(user_id), list_name)
        await ctx.send(msg)
Exemplo n.º 5
0
    async def list_purger_channels(self, ctx: commands.Context):
        """
        List all purger channels that are being monitored
        """

        guild_data = await get_guild_data(ctx.message.guild.id)
        msg = translate("purger_list_title", await culture(ctx))

        for text_channel, max_age in guild_data.purgers.items():
            msg = (msg + "\n" +
                   translate("purger_list_item", await culture(ctx)).format(
                       text_channel, max_age))
        await ctx.send(msg)
Exemplo n.º 6
0
    async def add_youtube_channel(self, ctx: commands.Context,
                                  youtube_channel_id: str, text_channel: str):
        """
        Add a Youtube channel to be notified
        :param ctx: The current context. (discord.ext.commands.Context)
        :param youtube_channel_id: The Youtube channel to be notified of (str)
        :param text_channel: The text channel that will receive the notification (str)
        """
        guild_data = await get_guild_data(ctx.message.guild.id)
        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        # TODO: throw specific error with message when channel ID is wrong
        latest_video = await get_latest_video(youtube_channel_id)

        # Get the channel
        channel = get_channel(ctx, text_channel)

        # TODO: Give information to the user when the text channel does not exist
        if not channel:
            await ctx.channel.send(
                translate("membercount_channel_nonexistant", await
                          culture(ctx)))
            raise Exception("Invalid text channel provided")

        if isinstance(channel, discord.VoiceChannel):
            await ctx.channel.send(
                translate("channel_is_voice", await culture(ctx)))
            return

        add_response = await guild_data.add_youtube_channel(
            youtube_channel_id, channel, latest_video["video_id"])

        msg = ""
        if add_response:
            msg = translate("youtube_added", await
                            culture(ctx)).format(youtube_channel_id, channel)
        else:
            msg = translate("youtube_exists", await
                            culture(ctx)).format(youtube_channel_id)
        info(msg)
        await ctx.send(msg)
Exemplo n.º 7
0
    async def on_command_error(self, ctx: commands.Context, error: Any):
        """
        Handles any errors thrown by the commands.
        :param ctx: The current context. (discord.ext.commands.Context)
        :param error: The current error. (Any)
        """

        # Log the error
        log_error(error)

        # Notify user for MissingRequiredArgument errors
        if isinstance(error, commands.MissingRequiredArgument):
            command_name = ctx.message.content.split(" ")[0]
            msg = translate("err_missing_parameter", await culture(ctx)).format(command_name, error.param.name)
            return await ctx.send(msg)

        # Notify user with general error
        msg = translate("err_unrecognized_command", await culture(ctx))
        await ctx.send(msg)
Exemplo n.º 8
0
    async def add_admin(self, ctx: commands.Context):
        """
        Add a new bot admin.
        :param ctx: The current context. (discord.ext.commands.Context)
        """

        guild_data = await get_guild_data(ctx.guild.id)

        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        # Error if the command had no mention
        if not ctx.message.mentions:
            err = translate("mention_required", await culture(ctx))
            return await ctx.send(err)

        # Fetch user data
        user_id_to_add = ctx.message.mentions[0].id
        user_to_add = ctx.guild.get_member(int(user_id_to_add))
        user_name_to_add = user_to_add.display_name

        # Error if the user is a server admin (no point in giving him bot admin rights)
        if ctx.guild.get_member(
                int(user_id_to_add)).guild_permissions.administrator:
            err = translate("bot_admin_error_discord_admin", await
                            culture(ctx)).format(user_name_to_add)
            return await ctx.send(err)

        # Error if the user already is a bot admin
        if ctx.message.mentions[0].id in guild_data.bot_admins:
            err = translate("bot_admin_error_already_admin", await
                            culture(ctx)).format(user_name_to_add)
            return await ctx.send(err)

        # Actually add the user to the admins
        await guild_data.add_admin(user_id_to_add)

        # Display success
        msg = translate("bot_admin_add_success", await
                        culture(ctx)).format(user_name_to_add)
        await ctx.send(msg)
Exemplo n.º 9
0
    async def set_language(self, ctx: commands.Context):
        """
        Show the current language, and allow for updates.
        :param ctx: The current context. (discord.ext.commands.Context)
        """

        # Get guild data
        guild_data = await get_guild_data(ctx.guild.id)

        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        # Get current language
        current_culture = await culture(ctx)

        # Show current language
        msg = translate("current_language", current_culture).format(
            translate(current_culture, current_culture))
        await ctx.send(msg)

        # Request new language
        confirmation_message = translate("pick_new_language", current_culture)
        confirmation_ref = await ctx.send(confirmation_message)
        for emoji in flags.values():
            await confirmation_ref.add_reaction(emoji)

        # Handle user reaction
        try:
            reaction, user = await ctx.bot.wait_for(
                "reaction_add",
                check=lambda new_reaction, author: new_reaction.message.id ==
                confirmation_ref.id and author == ctx.message.author,
                timeout=INTERACT_TIMEOUT,
            )

            # Parse reaction
            new_language = None
            for lan in flags.keys():
                if flags[lan] == reaction.emoji:
                    new_language = lan
                    break

            # Update language if found
            if new_language:
                await guild_data.update_language(new_language)
                await confirmation_ref.delete()
                msg = translate("picked_new_language", new_language).format(
                    translate(new_language, new_language))
                return await ctx.send(msg)

        # Handle timeout
        except asyncio.TimeoutError:
            await confirmation_ref.delete()
            msg = translate("snooze_lose", await culture(ctx))
            return await ctx.send(msg)
Exemplo n.º 10
0
    async def select_random_user(self,
                                 ctx: commands.Context,
                                 *,
                                 channel_name: str = None):
        """
        Selects a random user from the server, channel, or online members.
        :param ctx: The current context. (discord.ext.commands.Context)
        :param channel_name: The channel to pick from, 'online' in order to pick an online member from the server. (str)
        """

        # Error for missing parameter
        if channel_name is None:
            msg = translate("random_user_no_channel", await culture(ctx))
            return await ctx.send(msg)

        # Choose from online members if requested
        if channel_name == "online":
            member = pick_random_online_member(ctx)
            msg = translate("random_user_chosen", await
                            culture(ctx)).format(member.id)
            return await ctx.send(msg)

        # Sanitize channel name
        channel = get_channel(ctx, channel_name)

        # Error if channel does not exist
        if channel is None:
            msg = translate("membercount_channel_nonexistant", await
                            culture(ctx))
            return await ctx.send(msg)

        # Error if channel empty
        if len(channel.members) < 1:
            msg = translate("membercount_empty_channel", await
                            culture(ctx)).format(channel.id)
            return await ctx.send(msg)

        # Pick a random user from channel, and report back to user
        member = random.choice(channel.members)
        msg = translate("random_user_chosen", await
                        culture(ctx)).format(member.id)
        await ctx.send(msg)
Exemplo n.º 11
0
    async def cmd_wombat_pic(self, ctx):
        wombat_list = [
            os.path.join(WOMBATS_DIR_NAME, w)
            for w in os.listdir(WOMBATS_DIR_NAME)
        ]

        if not wombat_list:
            msg = translate("empty_wombat_list", await culture(ctx))
            return await ctx.send(msg)

        await ctx.send(file=discord.File(random.choice(wombat_list)))
Exemplo n.º 12
0
    async def admins_bot(self, ctx: commands.Context):
        """
        Show a list of all bot admins.
        :param ctx: The current context. (discord.ext.commands.Context)
        """

        guild_data = await get_guild_data(ctx.guild.id)

        # Error if no admins found
        if not guild_data.bot_admins:
            msg = translate("bot_admin_err_no_admins", await culture(ctx))
            return await ctx.send(msg)

        # Build list
        message = translate("bot_admin_list_prefix", await culture(ctx))
        for user_id in guild_data.bot_admins:
            message += f"\n- {ctx.guild.get_member(int(user_id)).display_name}"

        # Show list
        await ctx.send(message)
Exemplo n.º 13
0
async def general_help(ctx: commands.Context):
    """
    Builds and sends the general help info to the current context.
    :param ctx: The current context. (discord.ext.commands.Context)
    """
    embed = discord.Embed()

    for cog_name in ctx.bot.cogs:
        content = await build_commands_message(ctx.bot.get_cog(cog_name), await culture(ctx))

        if len(content) == 0:
            continue

        title = build_title(cog_name)
        embed.add_field(name=title, value=content, inline=False)

    extra_info_command = translate("help_info_command", await culture(ctx)).format(ctx.prefix)
    extra_info_category = translate("help_info_category", await culture(ctx)).format(ctx.prefix)
    extra_info = f'{extra_info_command}\n{extra_info_category}'
    embed.add_field(name=empty, value=extra_info, inline=False)
    await send_embed(ctx, embed)
Exemplo n.º 14
0
    async def remove_purger(self, ctx: commands.Context, text_channel: str):
        """
        Remove a purger channel that was being notified
        :param ctx: The current context. (discord.ext.commands.Context)
        :param text_channel: The channel where the purger is attached to (str)
        """

        guild_data = await get_guild_data(ctx.message.guild.id)
        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        # Get channel
        channel = get_channel(ctx, text_channel)

        # TODO: Give information to the user when the text channel does not exist
        if not channel:
            await ctx.channel.send(
                translate("membercount_channel_nonexistant", await
                          culture(ctx)))
            raise Exception("Invalid text channel provided")

        #Give error if the channel is a voice channel
        if isinstance(channel, discord.VoiceChannel):
            await ctx.channel.send(
                translate("channel_is_voice", await culture(ctx)))
            return

        remove_response = await guild_data.remove_purger(channel)
        msg = ""
        if remove_response:
            msg = translate("purger_removed", await
                            culture(ctx)).format(str(channel.id))
        else:
            msg = translate("purger_no_exists", await
                            culture(ctx)).format(str(channel.id))
        info(msg)
        await ctx.send(msg)
Exemplo n.º 15
0
async def send_embed(ctx: commands.Context, embed: discord.Embed):
    """
    Send embed to the current context
    :param ctx: The current context. (discord.ext.commands.Context)
    :param embed: the embed to send back to the current context. (discord.Embed)
    """
    if len(embed) > 0:
        return await ctx.channel.send(embed=embed)

    # if we reach here, the embed is empty and we show an error
    name = empty
    value = translate("help_err_not_recognized", await culture(ctx)).format(ctx.prefix)
    embed.add_field(name=name, value=value, inline=False)
    await ctx.channel.send(ctx, embed)
Exemplo n.º 16
0
async def build_commands_message(cog: commands.Cog, current_culture: str) -> str:
    """
    Builds the help info for a certain cog
    :param cog: The requested cog. (discord.ext.commands.Cog)
    :param current_culture: The culture in which the help should be generated (str)
    :return: The help info for the given cog (str)
    """

    message = {}
    for command in cog.get_commands():
        if command.hidden:
            continue

        if command.brief is None:
            message[command.name] = translate(command.help, current_culture)
        else:
            message[command.name] = translate(command.brief, current_culture)

    strings = []
    for name in sorted(message):
        strings.append("*{0}*\n \u2003 {1}\n".format(name, message[name]))

    return ' '.join(strings)
Exemplo n.º 17
0
    async def list_youtube_channels(self, ctx: commands.Context):
        """
        List all Youtube channels that are being monitored
        """

        guild_data = await get_guild_data(ctx.message.guild.id)
        msg = translate("youtube_list_title", await culture(ctx))

        for channel_id, channel_data in guild_data.youtube_channels.items():
            msg = (
                msg +
                f"\n - Channel `{channel_id}` posts in <#{channel_data['text_channel_id']}>, last video ID: `{channel_data['latest_video_id']}`"
            )
        await ctx.send(msg)
Exemplo n.º 18
0
    async def remove_list(self, ctx: commands.Context, list_name: str):
        """
        Removes the given list.
        :param ctx: The current contest. (discord.ext.commands.Context)
        :param list_name: The list to be removed. (str)
        """

        guild_data = await get_guild_data(ctx.message.guild.id)

        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        # Make sure the list name is lowercase
        list_name = list_name.lower()

        # Error if list does not exist
        if not guild_data.does_list_exist(list_name):
            msg = translate("list_err_does_not_exit", await culture(ctx))
            return await ctx.send(msg)

        # Ask user confirmation
        msg = translate("confirmation_question", await culture(ctx))
        confirmation_ref = await ctx.send(msg)
        await confirmation_ref.add_reaction(thumbs_up)
        await confirmation_ref.add_reaction(thumbs_down)

        # Handle user reaction
        try:
            reaction, user = await ctx.bot.wait_for(
                "reaction_add",
                check=lambda emoji, author: emoji.message.id ==
                confirmation_ref.id and author == ctx.message.author,
                timeout=INTERACT_TIMEOUT,
            )

            # Process emoji
            if reaction.emoji == thumbs_up:
                await guild_data.remove_notification_list(list_name)
                msg = translate("remove_list_success", await
                                culture(ctx)).format(list_name)
                await ctx.send(msg)

            elif reaction.emoji == thumbs_down:
                msg = translate("remove_list_cancel", await
                                culture(ctx)).format(list_name)
                await ctx.send(msg)

            # Delete message
            await confirmation_ref.delete()

        # Handle Timeout
        except asyncio.TimeoutError:
            await confirmation_ref.delete()
            msg = translate("snooze_lose", await culture(ctx))
            return await ctx.send(msg)
Exemplo n.º 19
0
async def subject_help(ctx: commands.Context, cog_name: str):
    """
    Builds and sends the help info for the given cog to the current context.
    :param ctx: The current context. (discord.ext.commands.Context)
    :param cog_name: The subject to request help on. (str)
    """
    embed = discord.Embed()
    cog = ctx.bot.get_cog(cog_name)
    content = await build_commands_message(cog, await culture(ctx))

    # add subject title
    title = f'**{cog_name}**\n'
    embed.add_field(name=title, value=content, inline=False)

    # add extra info
    extra_info = translate("help_info_command", await culture(ctx)).format(ctx.prefix)
    embed.add_field(name=empty, value=extra_info, inline=False)

    await send_embed(ctx, embed)
Exemplo n.º 20
0
    async def add_purger(self, ctx: commands.Context, text_channel: str,
                         max_age: int):
        """
        Add a channel to be regularly purged.
        :param ctx: The current context. (discord.ext.commands.Context)
        :param text_channel: The text channel that will be purged (str)
        :param max_age: The max age of messages in days (int)
        """
        guild_data = await get_guild_data(ctx.message.guild.id)
        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        text_channel = text_channel.lower()

        # Get channel
        channel = get_channel(ctx, text_channel)

        # TODO: Give information to the user when the text channel does not exist
        if not channel:
            await ctx.channel.send(
                translate("membercount_channel_nonexistant", await
                          culture(ctx)))
            raise Exception("Invalid text channel provided")

        #Give error if the channel is a voice channel
        if isinstance(channel, discord.VoiceChannel):
            await ctx.channel.send(
                translate("channel_is_voice", await culture(ctx)))
            return

        # member = ctx.get_member(ctx.user.id)
        channel_permissions = channel.permissions_for(ctx.me)
        if not (channel_permissions.manage_messages
                and channel_permissions.read_message_history):
            return await ctx.send(
                translate("purger_permissions", await culture(ctx)))

        add_response = await guild_data.add_purger(channel, max_age)

        msg = ""
        if add_response:
            msg = translate("purger_added", await
                            culture(ctx)).format(str(channel.id), max_age)
        else:
            msg = translate("purger_exists", await
                            culture(ctx)).format(str(channel.id))
        info(msg)
        await ctx.send(msg)
Exemplo n.º 21
0
    async def on_member_join(self, member: discord.Member):
        """
        This function is executed on every member_join event, and logs a message if a certain threshold is passed.
        :param member: The member that just joined. (discord.Member)
        """
        # Fetch server
        guild = member.guild

        # Get member count
        member_count = guild.member_count

        # Return if count is no multiple of threshold
        if member_count % member_notification_trigger != 0:
            return

        # Send message to dedicated channel
        channel = discord.utils.get(guild.channels,
                                    name=notification_channel_name)
        culture = (await get_guild_data(member.guild.id)).culture
        msg = translate("member_join_count",
                        culture).format(member.guild, member_count)
        await channel.send(msg)
Exemplo n.º 22
0
    async def count(self, ctx, *, channel_name=None):
        """
        Count the members in a given channel, the members in the current server, or the online members in the current server.
        :param ctx: The current context. (discord.ext.commands.Context)
        :param channel_name: The name of the channel to count, 'online' to count online members, or nothing to count the entire server. (optional - str - default = None)
        """
        if channel_name == "online":
            online_member_count = count_online_members(ctx)
            msg = translate("membercount_online_result", await
                            culture(ctx)).format(online_member_count)
            return await ctx.send(msg)

        if not channel_name:
            msg = translate("membercount_server_result", await
                            culture(ctx)).format(len(ctx.guild.members),
                                                 ctx.guild.name)
            return await ctx.send(msg)

        # Sanitize channel name
        channel = get_channel(ctx, channel_name)

        if channel is None:
            msg = translate("membercount_channel_nonexistant", await
                            culture(ctx))
            return await ctx.send(msg)

        if len(channel.members) < 1:
            msg = translate("membercount_empty_channel", await
                            culture(ctx)).format(channel.id)
            return await ctx.send(msg)

        if len(channel.members) == 1:
            msg = translate("membercount_single_person", await
                            culture(ctx)).format(channel.id)
            return await ctx.send(msg)

        msg = translate("membercount_channel_result", await
                        culture(ctx)).format(len(channel.members), channel.id)
        await ctx.send(msg)
Exemplo n.º 23
0
    async def remove_admin(self, ctx: commands.Context):
        """
        Remove a bot admin.
        :param ctx: The current context. (discord.ext.commands.Context)
        """

        guild_data = await get_guild_data(ctx.guild.id)

        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        # Error if the command had no mention
        if not ctx.message.mentions:
            err = translate("mention_required", await culture(ctx))
            return await ctx.send(err)

        # Fetch user data
        user_id_to_remove = ctx.message.mentions[0].id
        user_to_remove = ctx.guild.get_member(int(user_id_to_remove))
        user_name_to_remove = user_to_remove.display_name

        # Error if the user is not a bot admin
        if user_id_to_remove not in guild_data.bot_admins:
            err = translate("bot_admin_error_not_admin", await
                            culture(ctx)).format(user_name_to_remove)
            return await ctx.send(err)

        # User is trying to revoke his own rights
        if ctx.author.id == user_id_to_remove:
            # Ask confirmation
            confirmation_text = translate("bot_admin_confirm_remove_self",
                                          await culture(ctx))
            confirmation_ref = await ctx.send(confirmation_text)
            await confirmation_ref.add_reaction(thumbs_up)
            await confirmation_ref.add_reaction(thumbs_down)

            # Handle user reaction
            try:
                reaction, user = await ctx.bot.wait_for(
                    "reaction_add",
                    check=lambda new_reaction, author: new_reaction.message.id
                    == confirmation_ref.id and author == ctx.message.author,
                    timeout=INTERACT_TIMEOUT,
                )

                # Process thumbs up
                if reaction.emoji == thumbs_up:
                    await guild_data.remove_admin(user_id_to_remove)
                    msg = translate("bot_admin_remove_success", await
                                    culture(ctx)).format(user_name_to_remove)
                    return await ctx.send(msg)

                # Process thumbs down
                if reaction.emoji == thumbs_down:
                    msg = translate("bot_admin_remove_cancel", await
                                    culture(ctx)).format(user_name_to_remove)
                    return await ctx.send(msg)

                # If we reach here, an invalid emoji was used
                await confirmation_ref.delete()
                return

                # Handle timeout
            except asyncio.TimeoutError:
                await confirmation_ref.delete()
                msg = translate("snooze_lose", await culture(ctx))
                return await ctx.send(msg)

        # Authorized user wants to remove another bot admin
        # Ask confirmation
        confirmation_text = translate("bot_admin_confirm_remove", await
                                      culture(ctx)).format(user_name_to_remove)
        confirmation_ref = await ctx.send(confirmation_text)
        await confirmation_ref.add_reaction(thumbs_up)
        await confirmation_ref.add_reaction(thumbs_down)

        # Handle user reaction
        try:
            reaction, user = await ctx.bot.wait_for(
                "reaction_add",
                check=lambda new_reaction, author: new_reaction.message.id ==
                confirmation_ref.id and author == ctx.message.author,
                timeout=INTERACT_TIMEOUT,
            )

            # Process thumbs up
            if reaction.emoji == thumbs_up:
                await guild_data.remove_admin(user_id_to_remove)
                msg = translate("bot_admin_remove_success", await
                                culture(ctx)).format(user_name_to_remove)
                return await ctx.send(msg)

            # Process thumbs down
            elif reaction.emoji == thumbs_down:
                msg = translate("bot_admin_remove_cancel", await
                                culture(ctx)).format(user_name_to_remove)
                return await ctx.send(msg)

            # If we reach here, an invalid emoji was used
            await confirmation_ref.delete()
            return

        # Handle timeout
        except asyncio.TimeoutError:
            await confirmation_ref.delete()
            msg = translate("snooze_lose", await culture(ctx))
            return await ctx.send(msg)
Exemplo n.º 24
0
    async def notify(self,
                     ctx: commands.Context,
                     list_name: str,
                     *,
                     message: typing.Optional[str] = None):
        """
        Notify all subscribers for the given list with the given message.
        :param ctx:The current context. (discord.ext.commands.Context)
        :param list_name: The name of the list to notify. (str)
        :param message: The message to send with the notification. (optional - str - default= None)
        """

        guild_data = await get_guild_data(ctx.message.guild.id)

        # Error if list does not exist
        list_name = list_name.lower()
        if not guild_data.does_list_exist(list_name):
            msg = translate("list_err_does_not_exit", await culture(ctx))
            return await ctx.send(msg)

        # Fetch users to notify
        users = guild_data.get_users_list(list_name)
        emoji, is_custom_emoji = guild_data.get_emoji(list_name)
        if is_custom_emoji:
            emoji = get_custom_emoji(ctx, int(emoji))

        # Error if no users were found
        if len(users) < 1:
            msg = translate("list_err_empty", await culture(ctx))
            return await ctx.send(msg)

        # Setup the announcement with the subject and caller
        message_text = translate("notifying", await culture(ctx)).format(
            list_name.capitalize(), ctx.message.author.id,
            ctx.guild.get_member(ctx.bot.user.id).display_name)

        # build users mentioning strings
        user_tags = f'<@{str(users[0])}>'
        user_messages = []
        for user_id in users[1:]:
            if len(user_tags) + len(str(user_id)) + 5 < DISCORD_MAX_MSG_LENGTH:
                user_tags += ', ' + (f'<@{str(user_id)}>')
            else:
                user_messages.append(user_tags)
                user_tags = (f'<@{str(user_id)}>')
        user_messages.append(user_tags)

        embed = discord.Embed(
            title=emoji + "\t" + list_name.capitalize() + "\t" + emoji,
            description=message_text,
            color=NOTIFY_EMBED_COLOR,
        )

        # append the message if provided
        if message:
            # If message too long, tell user to write shorter message
            excess = (-1 * NOTIFY_MAX_MSG_LENGTH) + len(message)
            if excess > 0:
                msg = translate("notif_too_long", await
                                culture(ctx)).format(excess)
                return await ctx.send(msg)
            embed.add_field(name=translate("message", await culture(ctx)),
                            value=message)

        await ctx.channel.send(embed=embed)
        for users_str in user_messages:
            await ctx.send(users_str)
Exemplo n.º 25
0
    async def add_list(self, ctx: commands.Context, list_name: str):
        """
        Adds a new notification list with the given name.
        :param ctx: The current context. (discord.ext.commands.Context)
        :param list_name: The name to be used for the list. (str)
        """

        guild_data = await get_guild_data(ctx.message.guild.id)

        # Error if not admin
        if not guild_data.user_is_admin(ctx.author):
            gif = translate("not_admin_gif", await culture(ctx))
            return await ctx.send(gif)

        # Make sure the list name is lowercase
        list_name = list_name.lower()

        # Error if list already exists
        if guild_data.does_list_exist(list_name):
            msg = translate("list_already_exists", await
                            culture(ctx)).format(list_name)
            return await ctx.send(msg)

        # Request emoji from user
        msg = await ctx.send("What emoji do you want to use for " + list_name +
                             " ?")

        # Handle user reaction
        try:
            reaction, user = await ctx.bot.wait_for(
                "reaction_add",
                check=lambda emoji, author: emoji.message.id == msg.id and
                author == ctx.message.author,
                timeout=INTERACT_TIMEOUT,
            )

            # Process emoji
            if reaction.custom_emoji:
                try:
                    reaction_emoji = str(reaction.emoji.id)
                    emoji_to_print = get_custom_emoji(ctx, int(reaction_emoji))
                    custom_emoji = True
                except AttributeError:
                    msg = translate("unknown_emoji", await culture(ctx))
                    return await ctx.send(msg)
            else:
                reaction_emoji = reaction.emoji
                emoji_to_print = str(reaction_emoji)
                custom_emoji = False

            # Error if emoji is being used already on this server
            for data in guild_data.notification_lists.values():
                if reaction_emoji == data["emoji"]:
                    msg = translate("emoji_already_in_use", await culture(ctx))
                    return await ctx.send(msg)

            # Add list to GuildData
            await guild_data.add_notification_list(list_name, reaction_emoji,
                                                   custom_emoji)

            # Show success message to user
            await ctx.send("The list `" + list_name +
                           "` is saved with the emoji " + emoji_to_print)

        # Handle timeout
        except asyncio.TimeoutError:
            await msg.delete()
            msg = translate("snooze_lose", await culture(ctx))
            return await ctx.send(msg)
Exemplo n.º 26
0
    async def poll(self, ctx: commands.Context, *, input_str: str):
        """
        Create a poll with either yes or no as an answer or self submitted options.
        Poll will be open for an amount of time determined by the user.

        Syntax: question (multiple words) timeout (numerals) <options> (words split by ;)
        Example: This is a quention? 10 option 1; option 2; option 3

        :param input: input to be parsed according to above syntax
        """

        poller_id = ctx.message.author.id

        #check if there is a question
        if '?' not in input_str:
            await ctx.send(
                translate("poll_no_questionmark", await culture(ctx)))
            return

        input_split = input_str.split('?', 1)
        question = input_split[0]
        numbers_and_options = input_split[1].strip()

        # parse timeout and options
        if len(numbers_and_options) > 0:
            first_word = numbers_and_options.split()[0]
            if not first_word.isdigit():
                await ctx.send(
                    translate("poll_no_timeout", await
                              culture(ctx)).format(POLL_DEFAULT_TIMEOUT))
                timeout_s = POLL_DEFAULT_TIMEOUT * 60
            else:
                timeout_s = int(first_word) * 60

            if timeout_s > POLL_MAX_TIMEOUT * 60:
                await ctx.send(
                    translate("poll_max_timeout", await
                              culture(ctx)).format(POLL_MAX_TIMEOUT))
                timeout_s = POLL_MAX_TIMEOUT * 60

            # parse options
            options = numbers_and_options.split(first_word, 1)[1].strip()
            if len(options) > 0:
                options_list = options.split(';')
                is_yes_no = False
            else:
                is_yes_no = True
        else:
            is_yes_no = True
            await ctx.send(
                translate("poll_no_timeout", await
                          culture(ctx)).format(POLL_DEFAULT_TIMEOUT))
            timeout_s = POLL_DEFAULT_TIMEOUT * 60

        # create message to send to channel
        txt = translate("poll_start", await
                        culture(ctx)).format(poller_id, question)

        # add options to message
        options_dict = dict()
        if is_yes_no:
            txt += translate("poll_yes_no", await culture(ctx)).format(yes, no)
            options_dict[yes] = translate("yes", await culture(ctx))
            options_dict[no] = translate("no", await culture(ctx))
        else:
            i = 1
            for option in options_list:
                txt += "{} - {}\n".format(number_emojis[i], option)
                options_dict[number_emojis[i]] = option
                i += 1

        msg = await ctx.send(txt)

        # add reactions to message
        if is_yes_no:
            await msg.add_reaction(yes)
            await msg.add_reaction(no)
        else:
            i = 1
            for option in options_list:
                await msg.add_reaction(number_emojis[i])
                i += 1

        # wait until timeout
        await asyncio.sleep(timeout_s)

        # refresh message
        msg = await ctx.fetch_message(msg.id)

        # get the reactions
        reactions = msg.reactions
        reactions_dict = dict()
        for reaction in reactions:
            reactions_dict[reaction.emoji] = reaction.count
        reactions_sorted = sorted(reactions_dict.items(),
                                  key=lambda x: x[1],
                                  reverse=True)

        # send poll results
        txt = translate("poll_results", await
                        culture(ctx)).format(drum, poller_id, question)
        for reaction in reactions_sorted:
            try:
                option_str = options_dict[reaction[0]].strip()
                count = reaction[1] - 1
                txt += translate("poll_votes", await
                                 culture(ctx)).format(option_str, count)
            except KeyError:
                pass

        # send message with results
        await ctx.send(txt)
Exemplo n.º 27
0
    async def show_lists(self, ctx: commands.Context):
        """
        Show all currently existing lists for this server
        :param ctx: The current context. (discord.ext.commands.Context)
        """

        guild_data = await get_guild_data(ctx.message.guild.id)

        # Error if no lists exist yet
        if not guild_data.notification_lists:
            msg = translate("no_existing_lists", await culture(ctx))
            return await ctx.send(msg)

        # Check list count
        max_per_page = NOTIFY_MAX_PER_PAGE
        page_count = math.ceil(
            len(guild_data.notification_lists) / max_per_page)
        sorted_lists = sorted(guild_data.notification_lists.items())

        messages = []
        for page in range(1, page_count + 1):
            # Init text with title
            text = translate("lists", await culture(ctx))

            if page_count > 1:
                text += " " + translate("lists_page_count", await
                                        culture(ctx)).format(page, page_count)

            text += ":\n"

            # Loop and append all lists
            first_index = (page - 1) * max_per_page
            last_index = (page * max_per_page)

            for list_name, list_data in sorted_lists[first_index:last_index]:
                if list_data["is_custom_emoji"]:
                    text += get_custom_emoji(ctx, int(list_data["emoji"]))
                else:
                    text += list_data["emoji"]

                text += " - " + list_name + "\n"

            # Send lists to context
            msg = await ctx.send(text)
            messages.append(msg)

            # Add reactions
            for _, list_data in sorted_lists[first_index:last_index]:
                await msg.add_reaction(
                    list_data["emoji"] if not list_data["is_custom_emoji"] else
                    ctx.bot.get_emoji(int(list_data["emoji"])))

        reaction_tasks = []
        for message in messages:
            reaction_added_task = asyncio.create_task(
                self.wait_for_added_reactions(ctx, message.id, guild_data))
            reaction_tasks.append(reaction_added_task)
            reaction_removed_task = asyncio.create_task(
                self.wait_for_removed_reactions(ctx, message.id, guild_data))
            reaction_tasks.append(reaction_removed_task)

        # Listen for reactions
        await asyncio.gather(*reaction_tasks, return_exceptions=True)

        # Delete messages
        for message in messages:
            await message.delete()