async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    new_word = params_str.replace('\n',
                                  ' ')  # Can't have newlines in channel name.
    new_word = utils.strip_quotes(new_word)
    previous_word = ("text" if 'text_channel_name' not in settings else
                     func.esc_md(settings['text_channel_name']))
    if not new_word:
        return False, (
            "You need to define a new name, e.g. `{}textchannelname links` to make "
            "**links** shown instead of **{}**.".format(
                ctx['print_prefix'], previous_word))
    settings['text_channel_name'] = new_word
    utils.set_serv_settings(guild, settings)
    e_new_word = func.esc_md(new_word)
    await func.server_log(
        guild,
        "💬 {} (`{}`) définissez le nom \"text\" du serveur sur **{}**".
        format(func.user_hash(author), author.id, e_new_word), 2, settings)

    for p, pv in settings['auto_channels'].items():
        for s, sv in pv['secondaries'].items():
            if 'tc' in sv:
                tc = guild.get_channel(sv['tc'])
                try:
                    await tc.edit(name=utils.nice_cname(new_word))
                except discord.errors.Forbidden:
                    pass

    return True, (
        "Done! From now on I'll use **{}** instead of **{}**.".format(
            e_new_word, previous_word))
Esempio n. 2
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    new_word = params_str.replace('\n',
                                  ' ')  # Can't have newlines in channel name.
    new_word = utils.strip_quotes(new_word)
    previous_word = "General" if 'general' not in settings else func.esc_md(
        settings['general'])
    if not new_word:
        return False, (
            "You need to define a new word, e.g. `{}general Lounge` to make "
            "**Lounge** shown instead of **{}**.".format(
                ctx['print_prefix'], previous_word))
    settings['general'] = new_word
    utils.set_serv_settings(guild, settings)
    e_new_word = func.esc_md(new_word)
    await func.server_log(
        guild,
        "🎮 {} (`{}`) set the server's \"General\" word to **{}**".format(
            func.user_hash(author), author.id, e_new_word), 2, settings)
    return True, (
        "Done! From now on I'll use **{}** instead of **{}**.".format(
            e_new_word, previous_word))
Esempio n. 3
0
async def execute(ctx, params):
    guild = ctx['guild']
    settings = ctx['settings']
    vc = ctx['voice_channel']

    for p, pv in settings['auto_channels'].items():
        for s, sv in pv['secondaries'].items():
            if s == vc.id:
                if 'priv' not in sv or not sv['priv']:
                    return False, ("Your channel is already public. "
                                   "Use `{}private` to make it private instead.".format(ctx['print_prefix']))
                try:
                    await vc.set_permissions(guild.default_role, connect=True)
                except discord.errors.Forbidden:
                    return False, ("I don't have permission to do that."
                                   "Please make sure I have the *Manage Roles* permission in this server and category.")
                settings['auto_channels'][p]['secondaries'][s]['priv'] = False
                try:
                    jcid = settings['auto_channels'][p]['secondaries'][s]['jc']
                    del settings['auto_channels'][p]['secondaries'][s]['jc']
                except KeyError:
                    jcid = 0
                utils.set_serv_settings(guild, settings)
                if s in cfg.PRIV_CHANNELS:
                    del cfg.PRIV_CHANNELS[s]
                try:
                    jc = guild.get_channel(jcid)
                    if jc:
                        await jc.delete()
                except discord.errors.Forbidden:
                    return False, "You channel is now public, but I'm not allowed to delete your **⇩ Join** channel."
                return True, "Your channel is now public!"
    return False, "It doesn't seem like you're in a voice channel anymore."
def for_looper(client):
    for guild in func.get_guilds(client):
        settings = utils.get_serv_settings(guild)  # Need fresh in case some were deleted
        dead_secondaries = []
        for p in settings['auto_channels']:
            for sid, sv in settings['auto_channels'][p]['secondaries'].items():
                s = client.get_channel(sid)
                if s is None:
                    dying = sv['dying'] + 1 if 'dying' in sv else 1
                    settings['auto_channels'][p]['secondaries'][sid]['dying'] = dying
                    cfg.GUILD_SETTINGS[
                        guild.id] = settings  # Temporarily settings, no need to write to disk.
                    log("{} is dead ({})".format(sid, dying), guild)
                    if dying >= 3:
                        dead_secondaries.append(sid)
                else:
                    if 'dying' in sv:
                        settings['auto_channels'][p]['secondaries'][sid]['dying'] = 0
                        cfg.GUILD_SETTINGS[
                            guild.id] = settings  # Temporarily settings, no need to write to disk.

        if dead_secondaries:
            for p, pv in settings['auto_channels'].items():
                tmp = {}
                for s, sv in pv['secondaries'].items():
                    if s not in dead_secondaries:
                        tmp[s] = sv
                settings['auto_channels'][p]['secondaries'] = tmp

            utils.set_serv_settings(guild, settings)

            for s in dead_secondaries:
                if s in cfg.ATTEMPTED_CHANNEL_NAMES:
                    del cfg.ATTEMPTED_CHANNEL_NAMES[s]
Esempio n. 5
0
async def execute(ctx, params):
    params = [p for p in params if p]  # Remove any empty params
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author

    cmd = params[0]

    from commands import commands
    if cmd not in commands:
        if 'dcnf' not in ctx['settings'] or ctx['settings']['dcnf'] is False:
            return False, (
                "`{}` is not a recognized command. Run '**{}help**' "
                "to get a list of commands".format(cmd, ctx['print_prefix']))
        else:
            return False, "NO RESPONSE"

    if params[1].lower() == "none":
        if 'restrictions' in settings:
            try:
                del settings['restrictions'][cmd]
                utils.set_serv_settings(guild, settings)
                await func.server_log(
                    guild,
                    "✋ {} (`{}`) removed all restrictions for the `{}` command."
                    .format(func.user_hash(author), author.id,
                            cmd), 2, settings)
                return True, "Done! Removed restrictions for the `{}` command.".format(
                    cmd)
            except KeyError:
                return False, "There are no restrictions for the `{}` command.".format(
                    cmd)
        else:
            return False, "There are no command restrictions."

    roles = []
    for r in params[1:]:
        try:
            role = guild.get_role(int(r))
            if role is None:
                raise ValueError
        except ValueError:
            return False, (
                "`{}` is not a valid role ID. "
                "Use `{}listroles` to get a list of roles and their IDs.".
                format(r, ctx['print_prefix']))
        roles.append(role)

    if 'restrictions' not in settings:
        settings['restrictions'] = {}
    settings['restrictions'][cmd] = [r.id for r in roles]
    utils.set_serv_settings(guild, settings)

    roles_str = ', '.join("**{}**".format(r.name) for r in roles)
    await func.server_log(
        guild, "✋ {} (`{}`) set a restriction for the `{}` command: {}".format(
            func.user_hash(author), author.id, cmd, roles_str), 2, settings)
    return True, (
        "Done! From now on only users with one of the following roles can use the `{}` command: {}"
        "".format(cmd, roles_str))
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    new_prefix = utils.strip_quotes(params_str)
    if not new_prefix:
        return False, ("You need to define a new prefix, e.g. `{}prefix avc-` to make "
                       "`avc-` the new prefix.".format(ctx['print_prefix']))
    disallowed_characters = ['\n', '\t', '`']
    for c in disallowed_characters:
        if c in new_prefix:
            return False, "Your prefix can't contain **new lines**, **tab characters**, or **\`**."
    response = ("Done! My prefix in your server is now `{0}`. Try running `{0}ping` to test it out.\n"
                "Remember, you can always mention me instead of using my prefix (e.g: **{1} ping**)"
                ".".format(new_prefix, ctx['message'].guild.me.mention))
    if len(new_prefix) == 1:
        response += ("\n\n:information_source: Note: If you use the **same prefix as another bot**, "
                     "you should also run `{}dcnf` to prevent error messages when using that bot's commands."
                     "".format(new_prefix))
    cfg.PREFIXES[guild.id] = new_prefix
    settings['prefix'] = new_prefix
    utils.set_serv_settings(guild, settings)
    await func.server_log(
        guild,
        "💬 {} (`{}`) set the server's prefix to `{}`".format(
            func.user_hash(author), author.id, new_prefix
        ), 1, settings)
    return True, response
Esempio n. 7
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    nick = utils.strip_quotes(params_str)

    if nick.lower() == 'reset':
        try:
            del settings['custom_nicks'][str(author.id)]
            utils.set_serv_settings(guild, settings)
        except KeyError:
            return False, "You haven't set a custom nickname."
        return True, "Your custom nickname has been removed."

    if 'custom_nicks' not in settings:
        settings['custom_nicks'] = {}
    settings['custom_nicks'][str(author.id)] = nick
    utils.set_serv_settings(guild, settings)

    await func.server_log(
        guild, "🙋 {} (`{}`) set their custom nick to {}".format(
            func.user_hash(author), author.id, nick), 2, settings)
    return True, (
        "Done! Channels that show the creator's name will now call you **{}** instead of **{}**."
        .format(nick, author.display_name))
Esempio n. 8
0
async def execute(ctx, params):
    guild = ctx['guild']
    settings = ctx['settings']
    settings['uniquenames'] = not settings[
        'uniquenames'] if 'uniquenames' in settings else True
    utils.set_serv_settings(guild, settings)
    return True, (
        "Done. From now on, custom channel names {}. Run this command again to swap back."
        .format("will **have to be unique**" if settings['uniquenames'] else
                "**no longer** have to be unique"))
async def execute(ctx, params):
    settings = ctx['settings']
    guild = ctx['guild']
    if settings['enabled']:
        return False, "Already enabled. Use '{}disable' to turn off.".format(ctx['print_prefix'])
    else:
        log("Enabling", guild)
        settings['enabled'] = True
        utils.set_serv_settings(guild, settings)
        return True, "Enabling auto voice channels. Turn off with '{}disable'.".format(ctx['print_prefix'])
async def on_guild_remove(guild):
    num_members = len([m for m in guild.members if not m.bot])
    if cfg.SAPPHIRE_ID is None:
        settings = utils.get_serv_settings(guild)
        settings['left'] = datetime.now(
            pytz.timezone(
                cfg.CONFIG['log_timezone'])).strftime("%Y-%m-%d %H:%M")
        utils.set_serv_settings(guild, settings)
        log("Left guild {} `{}` with {} members".format(
            guild.name, guild.id, num_members))
    await func.admin_log(
        ":new_moon: Left: **{}** (`{}`) - **{}** members".format(
            func.esc_md(guild.name), guild.id, num_members), client)
Esempio n. 11
0
async def execute(ctx, params):
    guild = ctx['guild']
    settings = ctx['settings']
    asip = not settings['asip'] if 'asip' in settings else True
    settings['asip'] = asip
    utils.set_serv_settings(guild, settings)
    if asip:
        r = (
            "OK, from now on I'll assume channel members without any activity/status are also playing the same thing "
            "as most other members in the channel.")
    else:
        r = ("ASIP is now **OFF** :)")
    return True, r
async def on_guild_join(guild):
    num_members = len([m for m in guild.members if not m.bot])
    important = num_members > 5000
    if cfg.SAPPHIRE_ID is None:
        settings = utils.get_serv_settings(guild)
        settings['left'] = False
        utils.set_serv_settings(guild, settings)
        log("Joined guild {} `{}` with {} members".format(
            guild.name, guild.id, num_members))
    await func.admin_log(
        ":bell:{} Joined: **{}** (`{}`) - **{}** members".format(
            utils.guild_size_icon(num_members), func.esc_md(guild.name),
            guild.id, num_members),
        client,
        important=important)
Esempio n. 13
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    bitrate = utils.strip_quotes(params_str)
    v = author.voice
    in_vc = v is not None and v.channel.id in func.get_secondaries(
        guild, settings)
    if bitrate.lower() == 'reset':
        try:
            del settings['custom_bitrates'][str(author.id)]
            utils.set_serv_settings(guild, settings)
        except KeyError:
            return False, "You haven't set a custom bitrate."
        if in_vc:
            await func.update_bitrate(v.channel, settings, reset=True)
        return True, "Your custom bitrate has been reset, the channel default will be used for you from now on."

    try:
        bitrate = float(bitrate)
    except ValueError:
        return False, "`{}` is not a number.".format(bitrate)

    if bitrate < 8:
        return False, "The bitrate must be higher than 8."

    if bitrate * 1000 > guild.bitrate_limit:
        return False, "{} is higher than the maximum bitrate in this server ({}).".format(
            bitrate, guild.bitrate_limit / 1000)

    if 'custom_bitrates' not in settings:
        settings['custom_bitrates'] = {}
    settings['custom_bitrates'][str(author.id)] = bitrate
    utils.set_serv_settings(guild, settings)

    if in_vc:
        await func.update_bitrate(v.channel, settings)

    await func.server_log(
        guild, "🎚 {} (`{}`) set their custom bitrate to {}kbps".format(
            func.user_hash(author), author.id, bitrate), 2, settings)
    return True, (
        "Done! From now on, channels you join will have their bitrate set to {}kbps.\n"
        "If multiple users in the channel have set custom bitrates, the average will be used.\n\n"
        "Use `{}channelinfo` to check the current bitrate of your channel.".
        format(bitrate, ctx['print_prefix']))
async def execute(ctx, params):
    guild = ctx['guild']
    settings = ctx['settings']
    textchannels = not settings[
        'text_channels'] if 'text_channels' in settings else True
    settings['text_channels'] = textchannels
    utils.set_serv_settings(guild, settings)
    if textchannels:
        r = "OK, from now on I'll create private text channels for each voice chat."
        perms = guild.me.permissions_in(ctx['channel'])
        if not perms.manage_roles:
            r += (
                "\n:warning: Make sure I have the **Manage Roles** permission in this server and any categories that "
                "contain my voice channels, otherwise I won't be able to make the text channels."
            )
    else:
        r = "Text channel creation is now **OFF** :)"
    return True, r
async def execute(ctx, params):
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    vc = ctx['voice_channel']

    for p, pv in settings['auto_channels'].items():
        for s, sv in pv['secondaries'].items():
            if s == vc.id:
                if 'priv' in sv and sv['priv']:
                    return False, (
                        "Your channel is already private. "
                        "Use `{}public` to make it public again.".format(
                            ctx['print_prefix']))
                try:
                    await vc.set_permissions(author, connect=True)
                    await vc.set_permissions(guild.default_role, connect=False)
                except discord.errors.Forbidden:
                    return False, (
                        "I don't have permission to do that."
                        "Please make sure I have the *Manage Roles* permission in this server and category."
                    )
                settings['auto_channels'][p]['secondaries'][s]['priv'] = True
                settings['auto_channels'][p]['secondaries'][s]['msgs'] = ctx[
                    'channel'].id
                utils.set_serv_settings(guild, settings)
                cfg.PRIV_CHANNELS[s] = {
                    'creator': author,
                    'voice_channel': vc,
                    'primary_id': p,
                    'text_channel': ctx['channel'],
                    'guild_id': guild.id,
                    'request_time': time(),
                    'prefix': ctx['print_prefix'],
                }
                return True, (
                    "Your channel is now private!\n"
                    "A \"**⇧ Join {}**\" channel will appear below your one shortly. "
                    "When someone enters this channel to request to join you, "
                    "I'll send a message here asking you to approve or deny their request.\n"
                    "Use `{}public` to make it public again."
                    "".format(func.esc_md(author.display_name),
                              ctx['print_prefix']))
    return False, "It doesn't seem like you're in a voice channel anymore."
Esempio n. 16
0
async def execute(ctx, params):
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    vc = ctx['voice_channel']

    for p, pv in settings['auto_channels'].items():
        for s, sv in pv['secondaries'].items():
            if s == vc.id:
                if 'priv' in sv and sv['priv']:
                    return False, (
                        "Votre chaîne est déjà privée."
                        "Utilisez `{}public` pour le rendre à nouveau public.".
                        format(ctx['print_prefix']))
                try:
                    await vc.set_permissions(author, connect=True)
                    await vc.set_permissions(guild.default_role, connect=False)
                except discord.errors.Forbidden:
                    return False, (
                        "I don't have permission to do that."
                        "Please make sure I have the *Manage Roles* permission in this server and category."
                    )
                settings['auto_channels'][p]['secondaries'][s]['priv'] = True
                settings['auto_channels'][p]['secondaries'][s]['msgs'] = ctx[
                    'channel'].id
                utils.set_serv_settings(guild, settings)
                cfg.PRIV_CHANNELS[s] = {
                    'creator': author,
                    'voice_channel': vc,
                    'primary_id': p,
                    'text_channel': ctx['channel'],
                    'guild_id': guild.id,
                    'request_time': time(),
                    'prefix': ctx['print_prefix'],
                }
                return True, (
                    "Votre canal est désormais privée!\n"
                    "Un canal \"**⇩ Rejoignez {}**\" chaîne apparaîtra au-dessus de votre chaîne sous peu. "
                    "Lorsque quelqu'un entre sur ce canal pour demander à vous rejoindre, "
                    "Je vais envoyer un message ici vous demandant d'approuver ou de refuser leur demande.\n"
                    "Utilisez `{}public` pour le rendre à nouveau public."
                    "".format(func.esc_md(author.display_name),
                              ctx['print_prefix']))
    return False, "It doesn't seem like you're in a voice channel anymore."
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    param = utils.strip_quotes(params_str)

    if param.lower() == 'none':
        try:
            del settings['stct']
            utils.set_serv_settings(guild, settings)
            return (
                True,
                "From now on, new text channels will only be visible to the channel's occupants. "
                "Existing channels will not be affected.")
        except KeyError:
            return False, "Text channels are already invisible to everyone but the channel's occupants."

    role = None
    try:
        param = int(param)
        role = guild.get_role(param)
    except ValueError:
        if param == "@everyone":
            role = guild.default_role
        else:
            for r in guild.roles:
                if r.mention == param:
                    role = r
                    break

    if role is None:
        return False, "I can't find that role. You need to specify either the role ID, or `@mention` it."

    settings['stct'] = role.id
    utils.set_serv_settings(guild, settings)
    return (
        True,
        "From now on, new text channels can be seen by users with the \"{}\" role. "
        "Existing channels will not be affected.".format(
            discord.utils.escape_mentions(role.name)))
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    gsplit = params_str.split('>>')
    if len(gsplit) != 2 or not gsplit[0] or not gsplit[-1]:
        return False, (
            "Incorrect syntax for alias command. Should be: `{}alias [Actual game name] >> "
            "[New name]` (without square brackets).".format(
                ctx['print_prefix']))
    else:
        gname = utils.strip_quotes(gsplit[0])
        aname = utils.strip_quotes(gsplit[1])
        if gname in settings['aliases']:
            oaname = settings['aliases'][gname]
            response = "'{}' already has an alias ('{}'), it will be replaced with '{}'.".format(
                gname, oaname, aname)
        else:
            response = "'{}' will now be shown as '{}'.".format(gname, aname)
        settings['aliases'][gname] = aname
        utils.set_serv_settings(guild, settings)
        return True, response
Esempio n. 19
0
async def execute(ctx, params):
    mode = ctx['clean_paramstr'].lower()
    guild = ctx['guild']
    settings = ctx['settings']
    c = ctx['voice_channel']

    options = {
        'primary': 'PRIMARY',
        'parent': 'PRIMARY',
        'default': 'PRIMARY',
        'category': 'CATEGORY',
    }

    if mode not in options:
        try:
            mode = int(mode)
        except ValueError:
            return False, (
                "\"{}\" is not a valid option or channel ID. Please run `{}help inheritpermissions` "
                "to learn how to use this command.".format(
                    ctx['clean_paramstr'], ctx['print_prefix']))
        perm_channel = guild.get_channel(mode)
        if perm_channel is None:
            return False, (
                "`{}` is not a valid channel ID, it looks to me like that channel doesn't exist. "
                "Maybe I don't have permission to see it?".format(mode))
        if not isinstance(perm_channel, discord.VoiceChannel):
            return False, "Sorry, that channel is not a voice channel."
    else:
        mode = options[mode]
        if mode == 'CATEGORY' and c.category is None:
            return False, "Your channel is not in a category."

    for p in settings['auto_channels']:
        for sid in settings['auto_channels'][p]['secondaries']:
            if sid == c.id:
                settings['auto_channels'][p]['inheritperms'] = mode
                utils.set_serv_settings(guild, settings)
                return True, "Done! Note that this will only affect new channels."
async def execute(ctx, params):
    alias = ' '.join(params).strip()
    guild = ctx['guild']
    settings = ctx['settings']

    if not settings['aliases']:
        return True, "You haven't set any aliases yet."

    keys_to_delete = []
    for a, av in settings['aliases'].items():
        if (alias == a or alias == av) and a not in keys_to_delete:
            keys_to_delete.append(a)

    if keys_to_delete:
        for k in keys_to_delete:
            del settings['aliases'][k]
        utils.set_serv_settings(guild, settings)
        return True, ("Removed {} alias{}".format(
            len(keys_to_delete), "es" if len(keys_to_delete) != 1 else ""))
    else:
        return False, (
            "There is no alias for the game `{}` - please be exact, this operation is case-sensitive. "
            "Use `{}aliases` to get a list of the aliases in this server.".
            format(alias, ctx['print_prefix']))
Esempio n. 21
0
async def admin_command(cmd, ctx):
    client = ctx['client']
    message = ctx['message']
    channel = message.channel
    params = ctx['params']
    params_str = ctx['params_str']
    guilds = ctx['guilds']
    LAST_COMMIT = ctx['LAST_COMMIT']

    if cmd == 'log':
        logfile = "log{}.txt".format("" if cfg.SAPPHIRE_ID is None else cfg.SAPPHIRE_ID)
        if not os.path.exists(logfile):
            await channel.send("No log file")
            return
        with open(logfile, 'r', encoding="utf8") as f:
            data = f.read()
        data = data[-10000:]  # Drop everything but the last 10k characters to make string ops quicker
        data = data.replace('  Creating channel for ', '  ✅')
        data = data.replace('  Deleting ', '    ❌')
        data = data.replace('  Renaming ⌛  to  ', ' ⏩ ')
        data = data.replace('  Renaming ', ' 🔄')
        data = data.replace('  to  ', ' ⏩ ')
        data = data.replace('  CMD Y: ', '  C✔ ')
        data = data.replace('  CMD F: ', '  C✖ ')
        data = data.replace(" creating channels too quickly", " creating channels too quickly❗❗")
        data = data.replace(" where I don't have permissions", " where I don't have permissions❗❗")
        data = data.replace("Traceback (most recent", "❗❗Traceback (most recent")
        data = data.replace("discord.errors.", "❗❗discord.errors.")
        data = data.replace("Remembering channel ", "❗❗Remembering ")
        data = data.replace("New tickrate is ", "🕐")
        data = data.replace(", seed interval is ", " 🕐")
        data = data.replace('  ', ' ')  # Reduce indent to save character space
        today = datetime.now(pytz.timezone(cfg.CONFIG['log_timezone'])).strftime("%Y-%m-%d")
        data = data.replace(today, 'T')
        character_limit = 2000 - 17  # 17 for length of ```autohotkey\n at start and ``` at end.
        data = data[character_limit * -1:]
        data = data.split('\n', 1)[1]
        lines = data.split('\n')
        for i, l in enumerate(lines):
            # Fake colon (U+02D0) to prevent highlighting the line
            if " ⏩" in l:
                lines[i] = l.replace(':', 'ː')
            elif l.startswith('T '):
                if '[' in l:
                    s = l.split('[', 1)
                    lines[i] = s[0] + '[' + s[1].replace(':', 'ː')
        data = '\n'.join(lines)
        data = '```autohotkey\n' + data
        data = data + '```'
        await channel.send(data)

    if cmd == 'stats':
        r = await channel.send(". . .")
        t1 = message.created_at
        t2 = r.created_at
        response_time = (t2 - t1).total_seconds()
        num_users = 0
        for g in guilds:
            num_users += len([m for m in g.members if not m.bot])

        lines_of_code = 0
        for f in os.listdir(cfg.SCRIPT_DIR):
            if f.lower().endswith('.py'):
                lines_of_code += utils.count_lines(os.path.join(cfg.SCRIPT_DIR, f))
            elif f == "commands":
                for sf in os.listdir(os.path.join(cfg.SCRIPT_DIR, f)):
                    if sf.lower().endswith('.py'):
                        lines_of_code += utils.count_lines(os.path.join(cfg.SCRIPT_DIR, f, sf))

        cpu = psutil.cpu_percent()
        mem = psutil.virtual_memory()
        disk = psutil.disk_usage('/')
        await r.edit(content=(
            "Servers: **{tot_servs}** (A:{active_servs} S:{shards}) \t "
            "Users: **{users}** \t Channels: **{channels}** \n"
            "Response time: **{rt}** \t Tick rate: **{tr}** \t Tick time: **{tt}** | **{gtt}**\n"
            "CPU: **{cpu}%** \t MEM: **{memg} ({memp}%)** \t DISK: **{diskg} ({diskp}%)**\n"
            "**Last commit:** {commit}\n"
            "**Lines of code:** {lines}\n"
            "**Timings:** \n{timings}".format(
                tot_servs=len(guilds),
                active_servs=utils.num_active_guilds(guilds),
                shards=utils.num_shards(guilds),
                users=num_users,
                channels=utils.num_active_channels(guilds),
                rt="{0:.2f}s".format(response_time),
                tr="{0:.1f}s".format(cfg.TICK_RATE),
                tt="{0:.2f}s".format(cfg.TICK_TIME),
                gtt="{0:.2f}s".format(cfg.G_TICK_TIME),
                cpu=cpu, memg="{0:.1f}GB".format(mem.used / 1024 / 1024 / 1024), memp=round(mem.percent),
                diskg="{0:.1f}GB".format(disk.used / 1024 / 1024 / 1024), diskp=round(disk.percent),
                commit=LAST_COMMIT,
                lines=lines_of_code,
                timings=utils.format_timings()
            )
        ))

    if cmd == 'ping':
        r = await channel.send(". . .")
        t1 = message.created_at
        t2 = r.created_at
        response_time = (t2 - t1).total_seconds()
        e = '🔴🔴🔴' if response_time > 5 else ('🟠🟠' if response_time > 1 else '🟢')
        await r.edit(content="**{0} {1:.1f}s**".format(e, response_time))

    if cmd == 'top':
        top_guilds = []
        for g in guilds:
            s = func.get_secondaries(g)
            top_guilds.append({"name": g.name,
                               "size": len([m for m in g.members if not m.bot]),
                               "num": len(s) if s is not None else 0})
        top_guilds = sorted(top_guilds, key=lambda x: x['num'], reverse=True)[:10]
        r = "**Top Guilds:**"
        for g in top_guilds:
            r += "\n`{}` {}: \t**{}**".format(
                g['size'],
                func.esc_md(g['name']),
                g['num']
            )
        r += "\n\n**{}**".format(utils.num_active_channels(guilds))
        await channel.send(r)

    if cmd == 'patrons':
        if patreon_info is None:
            await channel.send(content='❌')
            return

        patrons = patreon_info.fetch_patrons(force_update=True)
        if not patrons:
            await channel.send(content='❌')
            return
        fields = {}
        auths = patreon_info.update_patron_servers(patrons)
        for p, pv in patrons.items():
            pu = client.get_user(p)
            if pu is not None:
                pn = pu.name
            else:
                pn = "Unknown"
            gn = ""
            if str(p) in auths:
                for s in auths[str(p)]['servers']:
                    gn += "`{}` ".format(s)
                if 'extra_gold' in auths[str(p)]:
                    for s in auths[str(p)]['extra_gold']:
                        gn += "+g`{}` ".format(s)
            fields["`{}` **{}** {}".format(p, pn, cfg.TIER_ICONS[pv])] = gn
        try:
            for field_chunk in utils.dict_chunks(fields, 25):
                e = discord.Embed(color=discord.Color.from_rgb(205, 220, 57))
                e.title = "{} Patrons".format(len(field_chunk))
                for f, fv in field_chunk.items():
                    fv = fv if fv else "None"
                    e.add_field(name=f, value=fv)
                await channel.send(embed=e)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'sapphiredebug':
        if cfg.SAPPHIRE_ID is None:
            await channel.send(content='❌ Not a sapphire')
            return

        if patreon_info is None:
            await channel.send(content='❌ No patreon_info')
            return

        auths = utils.read_json(os.path.join(cfg.SCRIPT_DIR, "patron_auths.json"))
        initiator_id = cfg.CONFIG["sapphires"][str(cfg.SAPPHIRE_ID)]['initiator']
        msg = ("Sapphire ID: {}\n"
               "User: `{}`\n"
               "Actual guilds: {}\n"
               "Config guilds: {}\n"
               "Authenticated guilds: {}\n"
               "get_guilds: {}".format(
                   cfg.SAPPHIRE_ID,
                   initiator_id,
                   ", ".join(['`' + str(g.id) + '`' for g in client.guilds]),
                   ", ".join(['`' + str(g) + '`' for g in cfg.CONFIG["sapphires"][str(cfg.SAPPHIRE_ID)]['servers']]),
                   ", ".join(['`' + str(g) + '`' for g in auths[str(initiator_id)]['servers']]),
                   ", ".join(['`' + str(g.id) + '`' for g in func.get_guilds(client)]))
               )
        await channel.send(msg)

    if cmd == 'status':
        g = utils.strip_quotes(params_str)
        if not g:
            await func.react(message, '❌')
            return
        try:
            await client.change_presence(
                activity=discord.Activity(name=g, type=discord.ActivityType.watching)
            )
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'settings':
        gid = utils.strip_quotes(params_str)
        try:
            int(gid)
        except ValueError:
            for x in guilds:
                if x.name == gid:
                    gid = str(x.id)
                    break
        fname = gid + '.json'
        fp = os.path.join(cfg.SCRIPT_DIR, "guilds", fname)
        if os.path.exists(fp):
            gid = int(gid)
            g = client.get_guild(gid)
            head = "**{}** `{}`{}".format(g.name, gid, ("✅" if g in func.get_guilds(client) else "❌"))
            head += "💎" if func.is_sapphire(gid) else ("💳" if func.is_gold(gid) else "")
            s = head
            s += "\n```json\n"
            with open(fp, 'r') as f:
                file_content = f.read()
            s += file_content
            s += '```'
            try:
                await channel.send(s)
            except discord.errors.HTTPException:
                # Usually because message is over character limit
                haste_url = await utils.hastebin(file_content)
                await channel.send("{}\n{}".format(head, haste_url))
        else:
            await func.react(message, '❌')

    if cmd == 'refetch':
        gid = utils.strip_quotes(params_str)
        try:
            gid = int(gid)
        except ValueError:
            await func.react(message, '❌')
            return

        g = client.get_guild(gid)

        if g is None:
            await func.react(message, '❓')
            return

        utils.get_serv_settings(g, force_refetch=True)
        await func.react(message, '✅')
        return

    if cmd == 'disable':
        try:
            g = client.get_guild(int(utils.strip_quotes(params_str)))
            settings = utils.get_serv_settings(g)
            settings['enabled'] = False
            utils.set_serv_settings(g, settings)
            log("Force Disabling", g)
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'enable':
        try:
            g = client.get_guild(int(utils.strip_quotes(params_str)))
            settings = utils.get_serv_settings(g)
            settings['enabled'] = True
            utils.set_serv_settings(g, settings)
            log("Force Enabling", g)
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'info':
        cid = utils.strip_quotes(params_str)
        try:
            c = client.get_channel(int(cid))
            members = [m.display_name + " \t {}".format(utils.debug_unicode(m.display_name)) for m in c.members]
            games = []
            for m in c.members:
                if m.activity:
                    games.append(m.activity.name + " \t {}".format(utils.debug_unicode(m.activity.name)))
            s = "**__Server:__** {} `{}`\n**__Name:__** {}\n{}\n\n".format(
                c.guild.name, c.guild.id, c.name, utils.debug_unicode(c.name)
            )
            if c.id in cfg.ATTEMPTED_CHANNEL_NAMES:
                s += "**__Attempted Name:__** {}\n{}\n\n".format(
                    cfg.ATTEMPTED_CHANNEL_NAMES[c.id],
                    utils.debug_unicode(cfg.ATTEMPTED_CHANNEL_NAMES[c.id])
                )
            s += "**__{} Members:__**\n".format(len(members))
            s += '\n'.join(members)
            s += '\n\n**__{} Games:__**\n'.format(len(games))
            s += '\n'.join(games)
            s = s.replace('\n\n\n', '\n\n')
            await channel.send(s)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'whois':
        uid = utils.strip_quotes(params_str)
        try:
            u = client.get_user(int(uid))
            in_guilds = {}
            for g in client.guilds:
                if u in g.members:
                    m = g.get_member(int(uid))
                    in_guilds[g.id] = {
                        "guild_name": func.esc_md(g.name),
                        "guild_size": g.member_count,
                        "patron": "💎" if func.is_sapphire(g) else ("💳" if func.is_gold(g) else ""),
                        "user_name": func.esc_md(m.display_name),
                        "role": m.top_role.name,
                    }
            if in_guilds:
                s = "**{}**".format(func.user_hash(u))
                s += " \t :b: :regional_indicator_o: :regional_indicator_t:" if u.bot else ""
                can_dm = True
                try:
                    await u.create_dm()
                    can_dm = client.user.permissions_in(u.dm_channel).send_messages
                except discord.errors.Forbidden:
                    can_dm = False
                s += " \t Can DM: {}".format('✅' if can_dm else '❌')

                for gid, g in in_guilds.items():
                    s += "\n{}`{}` **{}** (`{}`) \t {} ({})".format(
                        g['patron'], gid, g['guild_name'], g['guild_size'], g['user_name'], g['role']
                    )

                await echo(s, channel)
            else:
                await channel.send("¯\\_(ツ)_/¯")
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'votekicks':
        try:
            readable = {}
            for k, kv in cfg.VOTEKICKS.items():
                readable[k] = {
                    "initiator": kv['initiator'].display_name,
                    "participants": [m.display_name for m in kv['participants']],
                    "required_votes": kv['required_votes'],
                    "offender": kv['offender'].display_name,
                    "reason": kv['reason'],
                    "in_favor": [m.display_name for m in kv['in_favor']],
                    "voice_channel": kv['voice_channel'].id,
                    "message": kv['message'].id,
                    "end_time": datetime.fromtimestamp(kv['end_time']).strftime("%Y-%m-%d %H:%M")
                }
            s = "```json\n" + json.dumps(readable, indent=1, sort_keys=True) + "```"
            print(s)
            try:
                await channel.send(s)
            except discord.errors.HTTPException:
                # Usually because message is over character limit
                haste_url = await utils.hastebin(s)
                await channel.send(haste_url)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'exit':
        attempts = 0
        while attempts < 100:
            attempts += 1
            if not cfg.WRITES_IN_PROGRESS:
                print("Exiting!")
                await client.close()
                sys.exit()
                break
        else:
            print("Failed to close", cfg.WRITES_IN_PROGRESS)
            await func.react(message, '❌')

    if cmd == 'loop':
        mode = params[0]
        loop_name = params[1]
        try:
            loop = ctx['loops'][loop_name]
            modes = {  # Dict of possible loop functions/attrs as [fn, arg]
                'current_loop': [loop.current_loop, None],
                'next_iteration': [loop.next_iteration, None],
                'next_run': [loop.next_iteration, None],  # Alias
                'start': [loop.start, client],
                'stop': [loop.stop, None],
                'cancel': [loop.cancel, None],
                'restart': [loop.restart, client],
                'is_being_cancelled': [loop.is_being_cancelled, None],
                'last_run': [loop.last_run, None],
            }
            if mode not in modes:
                await func.react(message, '❓')
                return
            fn, arg = modes[mode]
            if callable(fn):
                if arg is None:
                    r = fn()
                else:
                    r = fn(arg)
            else:
                r = fn
            if r is not None:
                if isinstance(r, date):
                    r = r.astimezone(pytz.timezone(cfg.CONFIG['log_timezone']))
                    await channel.send(r.strftime("%Y-%m-%d %H:%M:%S"))
                else:
                    await channel.send(str(r))
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await channel.send("Loops: \n{}".format('\n'.join(ctx['loops'].keys())))
            await func.react(message, '❌')

    if cmd == 'rename':
        try:
            cid = utils.strip_quotes(params[0])
            c = client.get_channel(int(cid))
            new_name = ' '.join(params[1:])
            if not new_name:
                new_name = "⌛"
            await c.edit(name=new_name)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')
            log("{0}  Force Renaming to {1}".format(cid[-4:], new_name), c.guild)

    if cmd == 'forget':
        try:
            cid = int(utils.strip_quotes(params[0]))
            c = client.get_channel(cid)
            settings = utils.get_serv_settings(c.guild)
            for p, pv in settings['auto_channels'].items():
                tmp = settings['auto_channels'][p]['secondaries'].copy()
                for s, sv in pv['secondaries'].items():
                    if s == cid:
                        del settings['auto_channels'][p]['secondaries'][s]
                        break
            utils.set_serv_settings(c.guild, settings)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')

    if cmd == 'delete':
        try:
            cid = int(utils.strip_quotes(params[0]))
            c = client.get_channel(cid)
            await c.delete()
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')

    if cmd == 'whisper':
        params_str = utils.strip_quotes(params_str)
        if '\n' not in params_str:
            await func.react(message, '❌')
            return
        uid, msg = params_str.split('\n', 1)
        try:
            u = await client.fetch_user(uid)
        except discord.errors.NotFound:
            await func.react(message, '❌')
            return
        if u.dm_channel is None:
            await u.create_dm()
        try:
            await u.dm_channel.send(msg)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')

    if cmd == 'cleanprimaries':
        try:
            n_primaries = 0
            n_real_primaries = 0
            for g in client.guilds:
                settings = utils.get_serv_settings(g)
                tmp = {}
                n_primaries += len(settings['auto_channels'])
                for p, pv in settings['auto_channels'].items():
                    c = g.get_channel(p)
                    if c:
                        tmp[p] = pv
                n_real_primaries += len(tmp)
                if len(settings['auto_channels']) != len(tmp):
                    settings['auto_channels'] = tmp
                    utils.set_serv_settings(g, settings)
            await channel.send("Cleaned {} of {} primaries".format(n_real_primaries, n_primaries))
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'leaveinactive':
        params_str = utils.strip_quotes(params_str)
        try:
            total_guilds = 0
            inactive_guilds = 0
            cfg.CONFIG['leave_inactive'] = []
            for g in client.guilds:
                total_guilds += 1
                if g and (not utils.guild_is_active(g) or g not in guilds):
                    cfg.CONFIG['leave_inactive'].append(g.id)
                    inactive_guilds += 1
                    if params_str == "go":
                        try:
                            await g.leave()
                        except discord.errors.NotFound:
                            pass
            if params_str == "go":
                await channel.send("Left {} of {} guilds.".format(inactive_guilds, total_guilds))
            else:
                await channel.send("Will leave {} of {} guilds. "
                                   "Rerun command with 'go' at end to actually leave them.".format(
                                       inactive_guilds, total_guilds))
            cfg.CONFIG['leave_inactive'] = []
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
Esempio n. 22
0
async def execute(ctx, params):
    ctx['settings']['dcnf'] = True
    utils.set_serv_settings(ctx['guild'], ctx['settings'])
    return True, "OK, I'll no longer tell you if you typed a command incorrectly."
Esempio n. 23
0
async def execute(ctx, params):
    ctx['settings']['dcnf'] = False
    utils.set_serv_settings(ctx['guild'], ctx['settings'])
    return True, "From now on I'll tell you if you typed a command incorrectly."
async def on_message(message):
    if not client.is_ready():
        return

    if message.author.bot:
        # Don't respond to self or bots
        return

    guilds = func.get_guilds(client)

    admin = ADMIN
    admin_channels = []
    if admin is not None:
        admin_channels = [admin.dm_channel]
    if 'admin_channel' in cfg.CONFIG and ADMIN_CHANNEL is not None:
        admin_channels.append(ADMIN_CHANNEL)
    if message.channel in admin_channels:
        split = message.content.split(' ')
        cmd = split[0].split('\n')[0].lower()
        params_str = message.content[len(cmd):].strip()
        params = params_str.split(' ')

        if cmd == 'reload':
            m = utils.strip_quotes(params_str)
            success = await reload_modules(m)
            await func.react(message, '✅' if success else '❌')
        else:
            ctx = {
                'client': client,
                'admin': admin,
                'message': message,
                'params': params,
                'params_str': params_str,
                'guilds': guilds,
                'LAST_COMMIT': LAST_COMMIT,
            }
            await admin_commands.admin_command(cmd, ctx)
        return

    if not message.guild:  # DM
        if 'help' in message.content and len(
                message.content) <= len("@Auto Voice Channels help"):
            await message.channel.send(
                "Sorry I don't respond to commands in DMs, "
                "you need to type the commands in a channel in your server.\n"
                "If you've tried that already, then make sure I have the right permissions "
                "to see and reply to your commands in that channel.")
        elif message.content.lower().startswith("power-overwhelming"):
            channel = message.channel
            params_str = message.content[len("power-overwhelming"):].strip()
            if not params_str:
                await channel.send(
                    "You need to specify a guild ID. "
                    "Try typing `who am I` to get a list of guilds we're both in"
                )
                return
            auth_guilds = params_str.replace(' ', '\n').split('\n')
            for auth_guild in auth_guilds:
                try:
                    g = client.get_guild(int(auth_guild))
                    if g is None:
                        await channel.send(
                            "`{}` is not a guild I know about, "
                            "maybe you need to invite me there first?".format(
                                auth_guild))
                        return
                except ValueError:
                    await channel.send(
                        "`{}` is not a valid guild ID, try typing "
                        "`who am I` to get a list of guilds we're both in.".
                        format(auth_guild))
                    return
                except Exception as e:
                    error_text = "Auth Error `{}`\nUser `{}`\nCMD `{}`".format(
                        type(e).__name__, message.author.id, message.content)
                    await func.admin_log(error_text, ctx['client'])
                    log(error_text)
                    error_text = traceback.format_exc()
                    await func.admin_log(error_text, ctx['client'])
                    log(error_text)
                    return False, (
                        "A `{}` error occured :(\n"
                        "An admin has been notified and will be in touch.\n"
                        "In the meantime, try asking for help in the support server: "
                        "https://discord.gg/qhMrz6u".format(type(e).__name__))

            ctx = {
                'message': message,
                'channel': channel,
                'client': client,
            }
            auth_guilds = [int(g) for g in auth_guilds]
            success, response = await func.power_overwhelming(ctx, auth_guilds)

            if success or response != "NO RESPONSE":
                log("DM CMD {}: {}".format("Y" if success else "F",
                                           message.content))

            if success:
                if response:
                    if response != "NO RESPONSE":
                        await echo(response, channel, message.author)
                else:
                    await func.react(message, '✅')
            else:
                if response != "NO RESPONSE":
                    await func.react(message, '❌')
                    if response:
                        await echo(response, channel, message.author)
        elif message.content.lower() in ["who am i", "who am i?"]:
            in_guilds = []
            for g in client.guilds:
                if message.author in g.members:
                    in_guilds.append("`{}` **{}**".format(g.id, g.name))
            if in_guilds:
                await message.channel.send(
                    "We're both in the following guilds:\n{}".format(
                        '\n'.join(in_guilds)))
            else:
                await message.channel.send(
                    "I'm not in any of the same guilds as you.")
        else:
            await admin_channels[-1].send(
                embed=discord.Embed(title="DM from **{}** [`{}`]:".format(
                    message.author.name, message.author.id),
                                    description=message.content))
        return

    if message.guild not in guilds:
        return

    prefix_m = message.guild.me.mention
    prefix_mx = "<@!" + prefix_m[2:]
    if message.guild.id in cfg.PREFIXES:
        prefix_p = cfg.PREFIXES[message.guild.id]
    else:
        prefix_p = 'vc/'

    prefix = None
    if message.content.startswith(prefix_m):
        prefix = prefix_m
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.startswith(prefix_mx):
        prefix = prefix_mx
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.lower().startswith(prefix_p.lower()):
        prefix = prefix_p
        print_prefix = prefix_p

    # Commands
    if prefix:
        msg = message.content[len(prefix):].strip()  # Remove prefix
        split = msg.split(' ')
        cmd = split[0].lower()
        params = split[1:]
        params_str = ' '.join(params)
        clean_paramstr = ' '.join(
            message.clean_content[len(prefix):].strip().split(' ')[1:])

        guild = message.guild
        channel = message.channel

        settings = utils.get_serv_settings(guild)
        if channel.id not in func.get_voice_context_channel_ids(
                guild, settings):
            settings['last_channel'] = channel.id
            utils.set_serv_settings(guild, settings)

        ctx = {
            'client': client,
            'guild': guild,
            'prefix': prefix,
            'print_prefix': print_prefix,
            'prefix_p': prefix_p,
            'command': cmd,
            'gold': func.is_gold(guild),
            'sapphire': func.is_sapphire(guild),
            'settings': settings,
            'message': message,
            'channel': channel,
            'clean_paramstr': clean_paramstr,
        }

        # Restricted commands
        perms = message.author.permissions_in(channel)
        perms_required = [
            perms.manage_channels,
            perms.manage_roles,
        ]
        ctx['admin'] = all(perms_required)

        success, response = await commands.run(cmd, ctx, params)

        if success or response != "NO RESPONSE":
            log("CMD {}: {}".format("Y" if success else "F", msg), guild)

        if success:
            if response:
                if response != "NO RESPONSE":
                    await echo(response, channel, message.author)
            else:
                await func.react(message, '✅')
        else:
            if response != "NO RESPONSE":
                await func.react(message, '❌')
                if response:
                    await echo(response, channel, message.author)
async def create_join_channels(client):
    start_time = time()
    if not client.is_ready():
        return

    to_remove = []
    priv_channels = list(cfg.PRIV_CHANNELS.keys())
    for pc in priv_channels:
        try:
            pcv = cfg.PRIV_CHANNELS[pc]
        except KeyError:
            print("Ignoring error:")
            traceback.print_exc()
            continue

        if 'request_time' in pcv and time() - pcv['request_time'] > 120:
            # Unable to create join channel for 120s
            to_remove.append(pc)
            await pcv['text_channel'].send(
                ":warning: {} For some reason I was unable to create your \"⇩ Join\" channel, please try again later. "
                "Your channel is still private, but there's now no way for anyone to join you. "
                "Use `{}public` to make it public again."
                "".format(pcv['creator'].mention, pcv['prefix']))
            log("Failed to create join-channel, timed out.")
            continue

        guild = client.get_guild(pcv['guild_id'])
        if guild not in func.get_guilds(client):
            continue
        settings = utils.get_serv_settings(guild)
        for p, pv in settings['auto_channels'].items():
            for s, sv in pv['secondaries'].items():
                if 'priv' in sv and 'jc' not in sv:
                    creator = pcv['creator'].display_name
                    vc = pcv['voice_channel']

                    c_position = vc.position

                    overwrites = vc.overwrites
                    k = guild.default_role
                    v = overwrites[
                        k] if k in overwrites else discord.PermissionOverwrite(
                        )
                    v.update(connect=True)
                    overwrites[k] = v

                    try:
                        jc = await guild.create_voice_channel(
                            "⇩ Join {}".format(
                                creator),  # TODO creator can change
                            category=vc.category,
                            overwrites=overwrites)
                    except discord.errors.Forbidden:
                        to_remove.append(pc)
                        try:
                            await pcv['text_channel'].send(
                                ":warning: {} I don't have permission to make the \"⇩ Join\" channel for you anymore."
                                "".format(pcv['creator'].mention))
                        except:
                            log("Failed to create join-channel, and failed to notify {}"
                                .format(creator))
                            break
                    utils.permastore_secondary(jc.id)
                    settings['auto_channels'][p]['secondaries'][s][
                        'jc'] = jc.id
                    utils.set_serv_settings(guild, settings)
                    to_remove.append(pc)
                    try:
                        # Set position again, sometimes create_voice_channel gets it wrong.
                        await jc.edit(position=c_position)
                    except discord.errors.Forbidden:
                        # Harmless error, no idea why it sometimes throws this, seems like a bug.
                        pass
                    break

    for i in to_remove:
        try:
            del cfg.PRIV_CHANNELS[i]
        except KeyError:
            # Already deleted somehow.
            print("Ignoring error:")
            traceback.print_exc()
            pass

    end_time = time()
    fn_name = "create_join_channels"
    cfg.TIMINGS[fn_name] = end_time - start_time
    if cfg.TIMINGS[fn_name] > 10:
        await func.log_timings(client, fn_name)
Esempio n. 26
0
async def execute(ctx, params):
    guild = ctx['guild']
    settings = ctx['settings']
    previous_c = False if 'logging' not in settings else str(
        settings['logging'])
    was_previously_enabled = False
    tc = params[0].lower()
    if tc == previous_c:
        if tc is False:
            return False, "Logging is already disabled."
        was_previously_enabled = True
    if tc == 'off':
        await func.server_log(guild, "📕 Logging is now disabled", 1,
                              settings)
        settings['logging'] = False
        utils.set_serv_settings(guild, settings)
        return True, None
    elif tc == 'here':
        tc = ctx['channel']
    else:
        try:
            tc = int(tc)
        except ValueError:
            return False, (
                "`{}` is not a valid channel ID. Get the ID by right clicking the channel, "
                "or just run `{}logging here` in that channel.".format(
                    tc, ctx['print_prefix']))
        tmp = guild.get_channel(tc)
        if tmp is None:
            return False, (
                "`{}` is not a valid channel ID. Get the ID by right clicking the channel, "
                "or just run `{}logging here` in that channel.".format(
                    tc, ctx['print_prefix']))
        tc = tmp

    level = 1 if 'log_level' not in settings else settings['log_level']
    if len(params) > 1:
        level = params[1]
        try:
            level = int(level)
        except ValueError:
            return False, "The log level you chose (`{}`) is not a number.".format(
                level)
        if not (1 <= level <= 3):
            return False, "The log level must be between 1 and 3."
        if level == 3 and not func.is_sapphire(guild):
            return False, (
                "Only Sapphire Patron servers can use level 3 logging, as it may generate a large "
                "number of messages which may overload the bot and trigger Discord's rate limiting."
            )

    perms = tc.permissions_for(guild.me)
    if not perms.send_messages:
        return False, "I don't have permission to send messages to that channel."

    settings['logging'] = tc.id
    settings['log_level'] = level
    utils.set_serv_settings(guild, settings)
    await func.server_log(
        guild,
        ("📘 Logging level set to **{}**".format(level)
         if was_previously_enabled else
         "📗 Logging (level **{}**) is now enabled in this channel".format(
             level)), 1, settings)
    return True, None
Esempio n. 27
0
async def on_message(message):
    if not client.is_ready():
        return

    if message.author.bot:
        # Don't respond to self or bots
        return

    guilds = func.get_guilds(client)

    admin = ADMIN
    admin_channels = []
    if admin is not None:
        admin_channels = [admin.dm_channel]
    if 'admin_channel' in cfg.CONFIG:
        admin_channels.append(ADMIN_CHANNEL)
    if message.channel in admin_channels:
        split = message.content.split(' ')
        cmd = split[0].split('\n')[0].lower()
        params_str = message.content[len(cmd):].strip()
        params = params_str.split(' ')

        if cmd == 'stop':
            m = utils.strip_quotes(params_str)
            success = await reload_modules(m)
            await func.react(message, '⌛' if success else '❌')
            await asyncio.sleep(3)
            await func.react(message, '🌑' if success else '❌')
            await asyncio.sleep(1)
            await func.react(message, '🌓' if success else '❌')
            await asyncio.sleep(1)
            await func.react(message, '🌔' if success else '❌')
            await asyncio.sleep(1)
            await func.react(message, '✅' if success else '❌')
            await message.channel.send("restarting..")

            await client.logout()
        else:
            ctx = {
                'client': client,
                'admin': admin,
                'message': message,
                'params': params,
                'params_str': params_str,
                'guilds': guilds,
                'LAST_COMMIT': LAST_COMMIT,
            }

            await admin_commands.admin_command(cmd, ctx)
        return

    if not message.guild:  # DM
        if 'help' in message.content and len(
                message.content) <= len("@Auto Voice Channels help"):
            await message.channel.send(
                "Sorry I don't respond to commands in DMs, "
                "you need to type the commands in a channel in your server.\n"
                "If you've tried that already, then make sure I have the right permissions "
                "to see and reply to your commands in that channel.")
        else:
            await admin_channels[-1].send(
                embed=discord.Embed(title="DM from **{}** [`{}`]:".format(
                    message.author.name, message.author.id),
                                    description=message.content))
        return

    if message.guild not in guilds:
        return

    prefix_m = message.guild.me.mention
    prefix_mx = "<@!" + prefix_m[2:]
    if message.guild.id in cfg.PREFIXES:
        prefix_p = cfg.PREFIXES[message.guild.id]
    else:
        prefix_p = 'vc/'

    prefix = None
    if message.content.startswith(prefix_m):
        prefix = prefix_m
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.startswith(prefix_mx):
        prefix = prefix_mx
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.lower().startswith(prefix_p.lower()):
        prefix = prefix_p
        print_prefix = prefix_p

    # Commands
    if prefix:
        msg = message.content[len(prefix):].strip()  # Remove prefix
        split = msg.split(' ')
        cmd = split[0].lower()
        params = split[1:]
        params_str = ' '.join(params)
        clean_paramstr = ' '.join(
            message.clean_content[len(prefix):].strip().split(' ')[1:])

        guild = message.guild
        channel = message.channel

        settings = utils.get_serv_settings(guild)
        if channel.id not in func.get_voice_context_channel_ids(
                guild, settings):
            settings['last_channel'] = channel.id
            utils.set_serv_settings(guild, settings)

        ctx = {
            'client': client,
            'guild': guild,
            'prefix': prefix,
            'print_prefix': print_prefix,
            'prefix_p': prefix_p,
            'command': cmd,
            'gold': func.is_gold(guild),
            'sapphire': func.is_sapphire(guild),
            'settings': settings,
            'message': message,
            'channel': channel,
            'clean_paramstr': clean_paramstr,
        }

        # Restricted commands
        perms = message.author.permissions_in(channel)
        perms_required = [
            perms.manage_channels,
            perms.manage_roles,
        ]
        ctx['admin'] = all(perms_required)

        success, response = await commands.run(cmd, ctx, params)

        if success or response != "NO RESPONSE":
            log("CMD {}: {}".format("Y" if success else "F", msg), guild)

        if success:
            if response:
                if response != "NO RESPONSE":
                    await echo(response, channel, message.author)
            else:
                await func.react(message, '✅')
        else:
            if response != "NO RESPONSE":
                await func.react(message, '❌')
                if response:
                    await echo(response, channel, message.author)