Exemple #1
0
    async def clone(self, ctx, category: commands.CategoryChannelConverter(), *IDs):
        '''
        Clones multiple archives into a channel category.
        '''

        # Prepares the channels 
        channels = []
        for ID in IDs:
            channel = await category.create_text_channel(ID)
            channels.append(channel)

        # Creates a coroutine for each cloning process
        coroutines = []
        for ID,channel in zip(IDs, channels):
            # Searches through archived channels for the provided archive
            sourcePath = None
            for guild in listdir("archives/guilds"):
                for sourceChannel in listdir(f"archives/guilds/{guild}"):
                    if isfile(f"archives/guilds/{guild}/{sourceChannel}/{ID}.json"):
                        sourcePath = f"archives/guilds/{guild}/{sourceChannel}"
            
            # Schedules to fill the new channels
            coroutines.append(self.bot.get_cog("Cloning:").fill(ctx, sourcePath, ID, channel))
        
        output = await asyncio.gather(*coroutines)
        
        await ctx.send(f"{ctx.author.mention} Done. Created messages:\n{output}")
Exemple #2
0
async def config(ctx):
    """ This is for admins to configure the bot's behaviour on their guild. """

    if ctx.invoked_subcommand is None:
        options = [cmd.name for cmd in config.commands]
        title = ctx.translate('guided configuration')
        description = ctx.translate('this will guid you through all configurations')

        msg = None

        while True:  # config dialog loop
            action, msg = await multiple_choice(ctx, options, title, description, message=msg)

            if action is None:
                await msg.edit(content=ctx.translate("configuration dialog closed"), embed=None)
                await msg.clear_reactions()
                break

            choice = None
            converter = None
            content = None
            if action == 'prefix':
                content = 'type the new prefix'

            elif action == 'notifications':
                content = 'which channel do you wanna use as notification channel'
                converter = commands.TextChannelConverter()

            elif action == 'role':
                content = "which role do you wanna use as support role"
                converter = commands.RoleConverter()

            elif action == 'scope':
                title = ctx.translate("choose a scope as default")
                choice = await multiple_choice(ctx, [s.value for s in enums.Scope], title, message=msg)
                choice = choice[0]
                converter = Scope()

            elif action == 'language':
                title = ctx.translate("choose the language of the server")
                choice = await multiple_choice(ctx, [l.value for l in enums.Language], title, message=msg)
                choice = choice[0]
                converter = Language()

            elif action == 'category':
                content = "which category do you wanna use for channel-tickets"
                converter = commands.CategoryChannelConverter()

            elif action == 'voice':
                content = 'which category do you wanna use for voice support'
                converter = commands.CategoryChannelConverter()

            elif action == 'log':
                content = 'which channel do you wanna use for logging'
                converter = commands.TextChannelConverter()

            elif action == 'assigning':
                text = ctx.translate("do you want to enable auto-assigning")
                conf = Confirmation(ctx)
                await conf.confirm(text)

                choice = conf.confirmed

            prefix = ctx.prefix

            if content is not None:
                await msg.clear_reactions()
                note = ctx.translate("type [pfx]abort to close this dialog").format(prefix)
                await msg.edit(content=ctx.translate(content) + note, embed=None)

                def check(message):
                    return message.author.id == ctx.author.id and message.channel.id == msg.channel.id

                try:
                    choice = await ctx.bot.wait_for('message', check=check, timeout=60)
                except asyncio.TimeoutError:
                    continue
                choice = choice.content

            if choice is None or choice == prefix + 'abort':
                await msg.edit(content=ctx.translate("configuration dialog closed"), embed=None)
                await msg.clear_reactions()
                break

            if converter is not None:
                try:
                    choice = await converter.convert(ctx, choice)  # convert string to specific Object (like Channel)
                except commands.BadArgument:
                    await ctx.send(ctx.translate("invalid input"))
                    continue

            command = ctx.bot.get_command('config ' + action)
            await ctx.invoke(command, choice)
Exemple #3
0
    async def enable(self, ctx, *features):
        """Enable features in the current channel.

        **Arguments**
        *features:* list of features to enable. Can include any of
        `['raid', 'wild', 'research', 'users', 'train', 'trade', 'clean', 'archive', 'welcome', 'meetup', 'forecast', 'rocket']`

        Raid, wild, research, train and meetup require a defined location. Use `!setlocation`
        before enabling these.
        """
        guild_id = ctx.guild.id
        settings = ctx.bot.dbi.table('guild_settings')
        insert = settings.insert
        insert.row(guild_id=guild_id, version=ctx.bot.version)
        await insert.commit(do_update=True)
        try:
            await ctx.guild.me.edit(nick='Meowth 3.0')
        except:
            pass
        channel_id = ctx.channel.id
        channel_table = self.bot.dbi.table('report_channels')
        query = channel_table.query.where(channelid=channel_id)
        data = await query.get()
        if data:
            rcrd = dict(data[0])
        else:
            rcrd = {'channelid': channel_id, 'guild_id': ctx.guild.id}
        possible_commands = [
            'raid', 'wild', 'research', 'users', 'train', 'trade', 'clean',
            'archive', 'welcome', 'meetup', 'forecast', 'rocket'
        ]
        features = [x for x in features if x in possible_commands]
        if not features:
            return await ctx.send(
                "The list of valid command groups to enable is `raid, train, research, wild, "
                "rocket, users, trade, clean, welcome, archive, meetup`.")
        location_commands = [
            'raid', 'wild', 'research', 'train', 'meetup', 'forecast', 'rocket'
        ]
        enabled_commands = []
        required_perms = {}
        me = ctx.guild.me
        perms = ctx.channel.permissions_for(me)
        for x in features:
            if x in [
                    'raid', 'wild', 'trade', 'train', 'users', 'meetup',
                    'research', 'rocket'
            ]:
                required_perms['Add Reactions'] = perms.add_reactions
                required_perms['Manage Messages'] = perms.manage_messages
                required_perms['Use External Emojis'] = perms.external_emojis
            if x == 'users':
                required_perms['Manage Roles'] = perms.manage_roles
            if x in location_commands:
                if not rcrd.get('city'):
                    await ctx.send(
                        f"You must set a location for this channel before enabling `{ctx.prefix}{x}`. Use `{ctx.prefix}setlocation`"
                    )
                    continue
            if x != 'welcome' and x != 'archive':
                rcrd[x] = True
            enabled_commands.append(x)
        if 'meetup' in enabled_commands:
            column = 'category_meetup'
            content = (
                'How do you want Meetup channels created from this channel '
                'to be categorized? You can type the name or ID of the category you want '
                'the channel to appear in.')
            await ctx.send(content)

            def check(m):
                return m.author == ctx.message.author and m.channel == ctx.channel

            while True:
                try:
                    resp = await self.bot.wait_for('message', check=check)
                except:
                    break
                converter = commands.CategoryChannelConverter()
                category = await converter.convert(ctx, resp.content)
                if category:
                    rcrd[column] = category.id
                    required_perms['Manage Channels'] = perms.manage_channels
                    break
                else:
                    await ctx.send(
                        'I could not interpret your response. Try again!')
                    continue
        if 'raid' in enabled_commands:
            raid_levels = ['1', '3', '5', '7', 'EX', 'EX Raid Gyms']
            for level in raid_levels:
                column = f'category_{level.lower()}'
                if level == 'EX Raid Gyms':
                    column = 'category_ex_gyms'
                    content = (
                        'I can categorize raids of any level that are reported at '
                        'recognized EX Raid Gyms differently from other raids of the same level. '
                        'You can type `disable` if you do not want this, or type the name or ID of '
                        'the category you want those raid channels to appear in.'
                    )
                else:
                    if level == '7':
                        level_str = 'Mega'
                    elif level == 'EX':
                        level_str = "EX"
                    else:
                        level_str = f"Level {level}"
                    content = (
                        f'How do you want {level_str} Raids reported in this '
                        'channel to be displayed? You can type `message` if you want just '
                        'a message in this channel. If you want each raid to be given its own '
                        'channel for coordination, type the name or ID of the category you '
                        'want the channel to appear in, or type `none` for an uncategorized '
                        'channel. You can also type `disable` to disallow reports of '
                        f'{level_str} Raids in this channel.')
                await ctx.send(content)

                def check(m):
                    return m.author == ctx.message.author and m.channel == ctx.channel

                while True:
                    try:
                        resp = await self.bot.wait_for('message', check=check)
                    except:
                        break
                    if resp.content.lower() == 'message':
                        rcrd[column] = 'message'
                        break
                    elif resp.content.lower() == 'disable':
                        rcrd[column] = None
                        break
                    elif resp.content.lower() == 'none':
                        rcrd[column] = 'none'
                        break
                    else:
                        converter = commands.CategoryChannelConverter()
                        category = await converter.convert(ctx, resp.content)
                        if category:
                            rcrd[column] = str(category.id)
                            required_perms[
                                'Manage Channels'] = perms.manage_channels
                            break
                        else:
                            await ctx.send(
                                'I could not interpret your response. Try again!'
                            )
                            continue
        if 'welcome' in enabled_commands:
            old_welcome_channel, message = await self.welcome_channel(ctx.guild
                                                                      )
            new_welcome_channel = None
            if old_welcome_channel:
                if old_welcome_channel == 'dm':
                    name = 'Direct Message'
                else:
                    name = old_welcome_channel.mention
                content = f"This server's current welcome channel is {name}. "
                content += "Do you want to disable that channel and enable another?"
                oldmsg = await ctx.send(content)
                payload = await ask(ctx.bot, [oldmsg],
                                    user_list=[ctx.author.id])
                if not payload:
                    await oldmsg.edit(content='Timed out!')
                elif str(payload.emoji) == '❎':
                    if old_welcome_channel == 'dm':
                        new_welcome_channel = 'dm'
                    else:
                        new_welcome_channel = str(old_welcome_channel.id)
                elif str(payload.emoji) == '✅':
                    pass
            if not new_welcome_channel:
                await ctx.send(
                    'What channel do you want to use? You can type the name or ID of a text channel, or type `dm` if you want the welcome message sent to DMs.'
                )

                def check(m):
                    return m.author == ctx.author and m.channel == ctx.channel

                while True:
                    reply = await ctx.bot.wait_for('message', check=check)
                    if reply.content.lower() == 'dm':
                        new_welcome_channel = 'dm'
                        break
                    else:
                        converter = commands.TextChannelConverter()
                        channel = await converter.convert(ctx, reply.content)
                        if channel:
                            new_welcome_channel = str(channel.id)
                            break
                        else:
                            await ctx.send(
                                "I couldn't understand your reply. Try again.")
                            continue
            if not message:
                message = "Welcome to {server}, {user}!"
            content = f"Current welcome message: {message}\n"
            content += "Do you want to change the welcome message?"
            oldmsg = await ctx.send(content)
            payload = await ask(ctx.bot, [oldmsg], user_list=[ctx.author.id])
            if not payload:
                await oldmsg.edit(content='Timed out!')
            elif str(payload.emoji) == '❎':
                newmessage = message
            elif str(payload.emoji) == '✅':
                content = (
                    "Type your welcome message below. Key: \n**{@member}** - Replace member with user name or ID\n"
                    "**{#channel}** - Replace channel with channel name or ID\n"
                    "**{&role}** - Replace role name or ID (shows as @deleted-role DM preview)\n"
                    "**{user}** - Will mention the new user\n"
                    "**{server}** - Will print your server's name\n")
                await ctx.send(content)

                def check(m):
                    return m.author == ctx.author and m.channel == ctx.channel

                while True:
                    reply = await ctx.bot.wait_for('message', check=check)
                    if len(reply.content) > 500:
                        await ctx.send(
                            "Please shorten your message to fewer than 500 characters."
                        )
                        continue
                    message, errors = do_template(reply.content, ctx.author,
                                                  ctx.guild)
                    if errors:
                        content = "The following could not be found:\n"
                        content += "\n".join(errors)
                        content += "\nPlease try again."
                        await ctx.send(content)
                        continue
                    q = await ctx.send(
                        f"Here's what you sent:\n\n{message}\n\nDoes that look right?"
                    )
                    payload = await ask(ctx.bot, [q],
                                        user_list=[ctx.author.id],
                                        timeout=None)
                    if str(payload.emoji) == '❎':
                        await ctx.send('Try again.')
                        continue
                    elif str(payload.emoji) == '✅':
                        newmessage = message
                        break
            d = {
                'guild_id': ctx.guild.id,
                'channelid': new_welcome_channel,
                'message': newmessage
            }
            table = ctx.bot.dbi.table('welcome')
            insert = table.insert.row(**d)
            await insert.commit(do_update=True)
        if 'archive' in enabled_commands:
            category, phrase_list = await self.archive_cat_phrases(ctx.guild)
            new_category = None
            new_phrase_list = []
            if category:
                content = f"This server's current archive category is {category.name}. "
                content += "Do you want to disable that category and enable another?"
                oldmsg = await ctx.send(content)
                payload = await ask(ctx.bot, [oldmsg],
                                    user_list=[ctx.author.id])
                if not payload:
                    await oldmsg.edit(content='Timed out!')
                elif str(payload.emoji) == '❎':
                    new_category = category.id
                elif str(payload.emoji) == '✅':
                    pass
            if not new_category:
                await ctx.send(
                    'What category do you want to use? You can type the name or ID of a category.'
                )

                def check(m):
                    return m.author == ctx.author and m.channel == ctx.channel

                while True:
                    reply = await ctx.bot.wait_for('message', check=check)
                    converter = commands.CategoryChannelConverter()
                    channel = await converter.convert(ctx, reply.content)
                    if channel:
                        new_category = channel.id
                        break
                    else:
                        await ctx.send(
                            "I couldn't understand your reply. Try again.")
                        continue
            content = f"Current phrase list: {phrase_list}\n"
            content += "Do you want to change the phrase list?"
            oldmsg = await ctx.send(content)
            payload = await ask(ctx.bot, [oldmsg], user_list=[ctx.author.id])
            if not payload:
                await oldmsg.edit(content='Timed out!')
            elif str(payload.emoji) == '❎':
                new_phrase_list = phrase_list
            elif str(payload.emoji) == '✅':
                content = "Type your phrase list below. I will automatically archive any temporary channel in which your phrases are said. Separate each phrase with a comma."
                await ctx.send(content)

                def check(m):
                    return m.author == ctx.author and m.channel == ctx.channel

                while True:
                    reply = await ctx.bot.wait_for('message', check=check)
                    phrases = reply.content.split(',')
                    phrases = [x.strip() for x in phrases]
                    q = await ctx.send(
                        f"Here's what you sent:\n\n`{phrases}`\n\nDoes that look right?"
                    )
                    payload = await ask(ctx.bot, [q],
                                        user_list=[ctx.author.id],
                                        timeout=None)
                    if str(payload.emoji) == '❎':
                        await ctx.send('Try again.')
                        continue
                    elif str(payload.emoji) == '✅':
                        new_phrase_list = phrases
                        break
            d = {
                'guild_id': ctx.guild.id,
                'category': new_category,
                'phrase_list': new_phrase_list
            }
            table = ctx.bot.dbi.table('archive')
            insert = table.insert.row(**d)
            await insert.commit(do_update=True)
        if 'forecast' in enabled_commands:
            g = ctx.bot.get_guild(344960572649111552)
            gm = g.get_member(ctx.author.id)
            if not gm:
                gm = await g.fetch_member(ctx.author.id)
            r = g.get_role(616734835104546826)
            if r not in gm.roles:
                content = 'Unfortunately, because of the cost of using the AccuWeather API, you must be a Meowth Patreon Super Nerd to enable in-game weather forecasts. Visit www.patreon.com/meowthbot to become a Patron!'
                await ctx.send(content)
            else:
                d = {
                    'guild_id': ctx.guild.id,
                    'patron_id': ctx.author.id,
                    'enabled': True
                }
                table = ctx.bot.dbi.table('forecast_config')
                insert = table.insert.row(**d)
                await insert.commit(do_update=True)
                content = f'Forecasts have been enabled in this server! Please note that it may take up to eight hours for this to take effect. You can use `{ctx.prefix}forecast` in any reporting channel to check the forecast, and you can use `{ctx.prefix}weather` in raid channels at known Gyms to improve the forecast.'
                await ctx.send(content)
        if not all(required_perms.values()):
            missing_perms = [
                x for x in required_perms if not required_perms[x]
            ]
            while True:
                content = "I am missing the following required permissions in this channel. Please respond with `done` when you have granted me those permissions or `cancel` to cancel.\n\n"
                content += "\n".join(missing_perms)
                await ctx.send(content)

                def check(m):
                    return m.author == ctx.message.author and m.channel == ctx.channel

                resp = await self.bot.wait_for('message', check=check)
                if resp.content.lower() == 'cancel':
                    return await ctx.send("Configuration canceled.")
                elif resp.content.lower() == 'done':
                    channel = resp.channel
                    new_perms = channel.permissions_for(me)
                    req_perms = {x: None for x in required_perms}
                    for x in req_perms:
                        if x == 'Manage Channels':
                            req_perms[x] = new_perms.manage_channels
                        elif x == 'Manage Roles':
                            req_perms[x] = new_perms.manage_roles
                        elif x == 'Manage Messages':
                            req_perms[x] = new_perms.manage_messages
                        elif x == 'Use External Emojis':
                            req_perms[x] = new_perms.external_emojis
                        elif x == 'Add Reactions':
                            req_perms[x] = new_perms.add_reactions
                    if not all(req_perms.values()):
                        missing_perms = [
                            x for x in req_perms if not req_perms[x]
                        ]
                        continue
                    else:
                        await ctx.send('Thanks for fixing those!')
                        break
        insert = channel_table.insert
        insert.row(**rcrd)
        await insert.commit(do_update=True)
        return await ctx.send(
            f'The following commands have been enabled in this channel: `{", ".join(enabled_commands)}`'
        )
Exemple #4
0
    # Builtins
    bool: commands.core._convert_to_bool,
    int: built_in_converter(int),
    str: str,
    # Discord objects
    Role: commands.RoleConverter(),
    User: commands.UserConverter(),
    Member: commands.MemberConverter(),
    Color: commands.ColorConverter(),
    Invite: commands.InviteConverter(),
    Emoji: commands.EmojiConverter(),
    Message: commands.MessageConverter(),
    PartialEmoji: commands.PartialEmojiConverter(),
    TextChannel: commands.TextChannelConverter(),
    VoiceChannel: commands.VoiceChannelConverter(),
    CategoryChannel: commands.CategoryChannelConverter(),
}

_to_str = {
    Message: lambda m: f"Message with id {m.id} in {m.channel.mention}",
}


def to_str(argument: UserInputable) -> str:
    _type = type(argument)
    if issubclass(_type, Enum):
        return argument.name.capitalize().replace("_", " ")
    if _type is Reaction:
        if argument.custom_emoji:
            e = argument.emoji
            if isinstance(e, PartialEmoji):
Exemple #5
0
import json
import os
from datetime import datetime, timedelta
from random import randint
import discord
from discord.ext import commands, tasks

# Definitions
TOKEN = os.environ["ACCESS_TOKEN"]
bot = commands.Bot(command_prefix="!")

ROLE_CONVERTER = commands.RoleConverter()
CHANNEL_CONVERTER = commands.TextChannelConverter()
CATEGORY_CONVERTER = commands.CategoryChannelConverter()
MEMBER_CONVERTER = commands.MemberConverter()


# JSON support
def datetime_parser(value):
    if isinstance(value, dict):
        for k, v in value.items():
            value[k] = datetime_parser(v)
    elif isinstance(value, list):
        for index, row in enumerate(value):
            value[index] = datetime_parser(row)
    elif isinstance(value, str) and value:
        try:
            value = datetime.strptime(value, "%Y-%m-%d %H:%M:%S.%f")
        except (ValueError, AttributeError):
            pass
    return value