Beispiel #1
0
def config_create(guild):
    """
	Get the config file for the server and give to the user
	:param guild: <Discord.guild object>
	:return: <String> Describing file location
	"""
    with ENGINE.connect() as conn:
        select_st = select([Config]).where(Config.c.id == guild.id)
        result = conn.execute(select_st).fetchone()

        if result:
            if VERBOSE >= 2:
                print('[+] Found guild config for {}'.format(guild.name))
            # Create an in-memory version of the config
            columns = []
            for each in Config.c:
                columns.append(each.name)
            dict_ = dict(zip(columns, result))

            # For pretty printing, make the user's life easier
            for each in jsonFormatter[0]:
                dict_['schedule'] = dict_['schedule'].replace(each[0], each[1])
            for each in jsonFormatter[1]:
                dict_[each[1]] = dict_.pop(each[0])

            with open('{}/docs/config/{}.json'.format(DEFAULT_DIR, guild.id), 'w') as f:
                json.dump(dict_, f, indent=4)
                f.write('\n\n{}'.format(fetch_file('help', 'config')))
            return '{}/docs/config/{}.json'.format(DEFAULT_DIR, guild.id)

        else:
            # Guild has no config entry, create one and try again
            config_create_default(guild)
            return config_create(guild)
Beispiel #2
0
async def delete_command(message):
    """
    Permanently remove a custom command if it exists
    :param message: <Discord.message object>
    :return: <String> Notifying command has been removed 
    """
    admin = await is_admin_test(message.author, message)
    if admin:
        args = message.content.split()
        if VERBOSE >= 2:
            print("Args:")
            print(args)
        with ENGINE.connect() as conn:
            select_st = select([Commands]).where(
                and_(Commands.c.guild_id == message.guild.id,
                     Commands.c.name == args[0]))
            result = conn.execute(select_st).fetchone()
            if VERBOSE >= 2:
                print("Result:")
                print(result)
            if result:
                if VERBOSE >= 2:
                    print("Result:")
                    print(result)
                del_st = Commands.delete().where(
                    and_(Commands.c.guild_id == message.guild.id,
                         Commands.c.name == args[0]))
                conn.execute(del_st)
                import_custom_commands(message.guild.id)
                return 'Deleted {}'.format(args[0])
            else:
                return 'Command `{}` does not exist.'.format(args[0])
Beispiel #3
0
def get_quote_log(guild):
    """
	Return an xlsx of all quotes in the guild to the user.
	:param guild:
	:return:
	"""
    df = [None, None]
    for idx, Table in enumerate({Quotes, Lore}):
        select_st = select([Table]).where(Table.c.guild == guild)
        with ENGINE.connect() as conn:
            result = conn.execute(select_st).fetchall()
            keys = conn.execute(select_st).keys()

            entries = [each.values() for each in result]
            for each in entries:
                each[0] = 'id_{}'.format(each[0])
                each[4] = 'g_{}'.format(each[4])

            df[idx] = pd.DataFrame(entries, columns=keys)

    with pd.ExcelWriter('{}/log/quoteLog_{}.xlsx'.format(DEFAULT_DIR, guild),
                        engine='xlsxwriter') as writer:
        df[1].to_excel(writer, sheet_name='Sheet_1')
        df[0].to_excel(writer, sheet_name='Sheet_2')
    return [
        'Log of all quotes and lore for this guild:',
        '{}/log/quoteLog_{}.xlsx'.format(DEFAULT_DIR, guild)
    ]
Beispiel #4
0
def delete_quote(guild, msg_id):
    """
	Remove a quote from the database
	:param guild: <Int> Discord guild ID
	:param msg_id: <Int> Discord message ID
	:return: <String> Notify if quote has been removed
	"""
    with ENGINE.connect() as conn:
        for Table in {Quotes, Lore}:
            select_st = select([Table]).where(
                and_(Table.c.id == msg_id, Table.c.guild == guild))
            try:
                result = conn.execute(select_st).fetchone()
                if result:
                    quote = '{}\n ---{} on {}'.format(result[2], result[1],
                                                      result[3])

                    ins = Table.delete().where(
                        and_(Table.c.id == msg_id, Table.c.guild == guild))
                    conn.execute(ins)
                return "Deleted quote: {}".format(quote)
            except Exception as e:
                if VERBOSE >= 1:
                    print('[!] Exception in tquote: {}'.format(e))
                return None
Beispiel #5
0
def config_load(guild):
    """
	Load the JSON file supplied by user into the database
	:param guild: <Int> Discord guild ID
	:return: <None>
	"""
    # Undo the pretty printing
    with open('{}/docs/config/{}.json'.format(DEFAULT_DIR, guild), 'r') as f:
        dict_ = json.loads(f.read().split('```', maxsplit=1)[0])
    for each in jsonFormatter[1]:
        dict_[each[0]] = dict_.pop(each[1])
    for each in jsonFormatter[0]:
        dict_['schedule'] = dict_['schedule'].replace(each[1], each[0])

    with ENGINE.connect() as conn:
        ins = Config.update().where(Config.c.id == guild).values(
            locale=dict_['locale'],
            schedule=dict_['schedule'],
            quote_format=dict_['quote_format'],
            lore_format=dict_['lore_format'],
            url=dict_['url'],
            qAdd_format=dict_['qAdd_format'],
            filtered=dict_['filtered'],
            mod_roles=dict_['mod_roles'],
            anonymous=dict_['anonymous'],
            timer_channel=dict_['timer_channel'],
        )
        conn.execute(ins)
    # TODO ensure to lower
    modRoles[guild] = fetch_value(guild, 9, ';')
    if VERBOSE >= 1:
        print('[+] Loaded new config for {}'.format(guild.name))
Beispiel #6
0
def guild_list():
    """
	Get a list of all guilds ids
	:return: <List> IDs for all guilds the bot is active in
	"""
    with ENGINE.connect() as conn:
        select_st = select([Config])
        res = conn.execute(select_st)
        result = res.fetchall()

    return [each[0] for each in result]
Beispiel #7
0
def load_config(guild):
    """
	Retrieve any formatting options from database
	:param guild: <Int> Discord guild ID
	:return: <List> SQLAlchemy row entry from Config Table
	"""
    result = None
    with ENGINE.connect() as conn:
        select_st = select([Config]).where(Config.c.id == guild)
        result = conn.execute(select_st).fetchone()
    return result
Beispiel #8
0
def config_reset(guild):
    """
	Return the config to default values
	:param guild: <Discord.guild object>
	:return: <None>
	"""
    with ENGINE.connect() as conn:
        ins = Config.delete().where(Config.c.id == guild.id)
        conn.execute(ins)
    if VERBOSE >= 1:
        print('[+] Reset config for: {}'.format(guild.name))
    return config_create(guild)
Beispiel #9
0
def load_config(guild):
    """
	Internal function to get Guild configuration data for schedule formatting and default locale
	:param guild: <Int> Discord guild ID
	:return: <List> SQLAlchemy row result from database
	"""
    with ENGINE.connect() as conn:
        select_st = select([Config]).where(Config.c.id == guild)
        res = conn.execute(select_st)
        result = res.fetchone()
    if result:
        return result
Beispiel #10
0
def get_user(id_):
    """
	Internal function to get values from database for a single user
	:param id_: <Int> User ID
	:return: <List> SQLAlchemy row result from database
	"""
    with ENGINE.connect() as conn:
        select_st = select([Users]).where(Users.c.id == id_, )
        res = conn.execute(select_st)
        result = res.fetchone()
    if result:
        return result
Beispiel #11
0
def check_if_exists(guild, msg_id):
    """
	Internal function toeEnsure that we do not add the same message to the database multiple times
	:param guild: <Int> Discord guild ID
	:param msg_id: <Int> Discord message ID
	:return: <Bool>
	"""
    with ENGINE.connect() as conn:
        select_st = select([Quotes]).where(
            and_(Quotes.c.id == msg_id, Quotes.c.guild == guild))
        if conn.execute(select_st).fetchall():
            return True
    return False
Beispiel #12
0
def insert_command(message):
    """
	Add a new custom command to the database.
	:param message: <Discord.message> Raw message object
	:return: <str> Banner notifying if new command has been created or exisisting has been updated.
	"""
    # if await is_admin(message.author):
    args = message.content.split()
    links = str(message.attachments[0].url) if message.attachments else ''

    for each in args:
        if each.find('http') != -1:
            if each.split('.')[-1] in extSet['image']:
                links = '{}\n{}'.format(links, each)

    with ENGINE.connect() as conn:
        select_st = select([Commands]).where(
            and_(Commands.c.guild_id == message.guild.id,
                 Commands.c.name == args[0]))
        result = conn.execute(select_st).fetchone()

        if result:
            ins = Commands.update().where(
                and_(Commands.c.guild_name == message.guild.name,
                     Commands.c.name == args[0])).values(
                         value='{} {}'.format(' '.join(args[1:]), links),
                         links=links,
                     )
            conn.execute(ins)
            import_custom_commands(message.guild.id)
            banner = Embed(title='Updated `{}`'.format(
                args[0], description=' '.join(args[1:])))
            if VERBOSE >= 1:
                print('[+] Updated {}'.format((args[0])))
            return banner
        else:
            ins = Commands.insert().values(
                id=message.id,
                guild_id=message.guild.id,
                guild_name=message.guild.name,
                name=args[0],
                value='{} {}'.format(' '.join(args[1:]), links),
                embed=links,
            )
            conn.execute(ins)
            import_custom_commands(message.guild.id)
            banner = Embed(title='Added custom command `{}`'.format(args[0]),
                           description=' '.join(args[1:]))
            if VERBOSE >= 1:
                print('[+] Updated {}'.format((args[0])))
            return banner
Beispiel #13
0
async def override(message):
    """
	Admin command to manually change a user's saved location
	:param message: <Discord.message object> Describing which users to change to which locations
	:return: <String> Describing if the users' location was set or updated successfully
	"""
    increment_usage(message.guild, 'sched')
    if await is_admin(message.author, message):
        banner = Embed(title='Schedule Override',
                       description='Change a user\'s location.')
        args = message.content.split()
        # Args should translate as: 1 id, 2 name, 3 locale
        if len(args) < 4:
            banner.add_field(
                name='Invalid syntax.',
                value=
                'Formatting is: `!schedule override [TIMEZONE] @USER` you may mention any number of users.'
            )

        else:
            locale = TZ_ABBRS.get(args[2].lower(), args[2])
            success = [[], []]

            for each in message.mentions:
                user = get_user(int(each.id))

                if user:
                    with ENGINE.connect() as conn:
                        query = Users.update().where(
                            Users.c.id == each.id).values(locale=locale)
                        conn.execute(query)

                    if VERBOSE >= 2:
                        print('[+] {} UPDATED LOCALE TO {} FOR USER {}'.format(
                            message.author, locale, each.name))
                    success[0].append('Changed {} to: {}'.format(
                        each.name, locale))

                else:
                    insert_user(each.id, message.guild, each.name, locale)
                    if VERBOSE >= 2:
                        print('[+] {} SETTING {}\'s SCHEDULE TO: {}'.format(
                            message.author, each.name, locale))
                    success[1].append('Set {} to: {}'.format(
                        each.name, locale))
            banner.add_field(name='Updated schedule location.',
                             value='\n'.join(success[0]))
            banner.add_field(name='Created schedule location.',
                             value='\n'.join(success[1]))
        return banner
Beispiel #14
0
def insert_user(id_, guild_, name, locale):
    """
	Internal function to set values in database for a single user
	:param id_: <Int> User ID
	:param guild_: <Discord.guild object>
	:param name: <String> Username
	:param locale: <String> New location for the user
	:return: <None>
	"""
    with ENGINE.connect() as conn:
        ins = Users.insert().values(
            id=id_,
            name=name,
            locale=locale,
            guild=guild_.id,
            guild_name=guild_.name,
        )
        conn.execute(ins)
Beispiel #15
0
def fetch_value(guild, val, delim=None):
    """
	Get a specific cell from the guilds config table
	:param guild: <Int> Discord guild ID
	:param val: <String> Column name within Config Table
	:param delim: (Optional) <String> Delimeter for splitting values within the cell
	:return: <List> Values from within the specified cell
	"""
    with ENGINE.connect() as conn:
        select_st = select([Config]).where(Config.c.id == guild)
        res = conn.execute(select_st)
        result = res.fetchone()

    if result and result[val]:
        if type(result[val]) is str:
            result = result[val].split(delim)
            result[:] = (val for val in result if val not in {'', ' ', '\n', None})
        else:
            result = result[val]
        return result
Beispiel #16
0
def import_custom_commands(guild):
    """
    Internal function to grab any custom commands from the database
    :param guild: <Int> Discord guild ID
    :return: <None>
    """
    name = ' '.join(fetch_value(guild, 1))

    if VERBOSE >= 2:
        print(name)

    with ENGINE.connect() as conn:
        select_st = select([Commands]).where(Commands.c.guild_name == name)
        result = conn.execute(select_st).fetchall()

        if result:
            commands = dict()
            for each in result:
                each = list(each)
                commands[each[3]] = each[5]
            custom_commands[guild] = commands
Beispiel #17
0
def set_schedule(message):
    """
	User command to set their locale
	:param message: <Discord.message object> Describing where to set location to
	:return: <String> Describing new location for user
	"""
    increment_usage(message.guild, 'sched')
    args = message.content.split()
    config = load_config(message.guild.id)
    banner = Embed(title='Schedule')

    if config:
        server_locale = config[2]
    else:
        server_locale = 'Asia/Tokyo'

    # if no location provided default to server locale
    # if server has no locale default to Tokyo
    # if there is no server locale the schedule will not be displayed
    # however this allows users to still get their locations set
    locale = server_locale if len(args) < 3 else TZ_ABBRS.get(
        args[2].lower(), args[2])
    user = get_user(message.author.id)
    old_locale = user[2]
    if user:
        with ENGINE.connect() as conn:
            query = Users.update().where(
                Users.c.id == message.author.id, ).values(locale=locale)
            conn.execute(query)
        banner.add_field(name='Updated your schedule location.',
                         value='From: {}\nTo: {}'.format(old_locale, locale))
    else:
        insert_user(message.author.id, message.guild, message.author.name,
                    locale)
        banner.add_field(name='Set your schedule location.',
                         value='To: {}'.format(locale))
    return banner
Beispiel #18
0
def config_create_default(guild):
    """
	Create a new default entry for the given guild
	:param guild: <Discord.guild object>
	:return: <None>
	"""
    if VERBOSE >= 1:
        print('[+] Creating new guild config for {}'.format(guild.name))
    with ENGINE.connect() as conn:
        ins = Config.insert().values(
            id=guild.id,
            guild_name=guild.name,
            locale='Asia/Tokyo',
            schedule='0=10,17:15;1=10,12;2=16,10:15;3=2:44;4=10;5=16:30;',
            quote_format='{0}\n ---{1} on {2}',
            lore_format='{0}\n ---Scribed by the Lore Master {1}, on the blessed day of {2}',
            url='Come hang with us at: <https://www.twitch.tv/>',
            qAdd_format='Added:\n "{0}"\n by {1} on {2}',
            filtered='none',
            mod_roles='mod;admin;discord mod;',
            anonymous=1,
            timer_channel=0,
        )
        conn.execute(ins)
Beispiel #19
0
def get_quote(message, Table, username=None, raw=False):
    """
	Retrieve a quote from the database.
	:param guild: <int> message.guild.id
	:param Table: (Optional) <SQLAlchemy.Table> Quotes or Lore, defaults to Quotes
	:param username: (Optional) <str> Case sensitive Discord username, without discriminator
	"""

    if username:
        select_user = select([Table]).where(
            and_(Table.c.name == username,
                 Table.c.guild == message.guild.id)).order_by(func.random())
        select_id = select([Table]).where(
            and_(Table.c.id == username, Table.c.guild == message.guild.id))
    else:
        select_rand = select([
            Table
        ]).where(Table.c.guild == message.guild.id).order_by(func.random())

    with ENGINE.connect() as conn:
        if username:
            result = conn.execute(select_id).fetchone()
            if not result:
                result = conn.execute(select_user).fetchone()
        else:
            result = conn.execute(select_rand).fetchone()

        # Result fields translate as
        # [0]: message id, [1]: author, [2]: quote, [3]: date, [6]: embed url, [7]: jump_url
        if result:
            config = load_config(message.guild.id)
            if config:
                if Table.name == 'famQuotes':
                    stm = config[4].replace('\\n', '\n')
                    title = "Quote {}".format(result[0])
                    context_url = '{}'.format(result[7])
                elif Table.name == 'famLore':
                    stm = config[5].replace('\\n', '\n')
                    title = "Lore {}".format(result[0])
            else:
                if Table.name == 'famQuotes':
                    stm = '---{} on {}'
                    title = "Quote {}".format(result[0])
                    context_url = '{}'.format(result[7])
                elif Table.name == 'famLore':
                    stm = '---Scribed by the Lore Master {}, on the blessed day of {}'
                    title = "Lore {}".format(result[0])

        if raw:
            # Check if there is an attached img or file to send as well
            if len(result) > 6 and result[6]:
                stm = stm + '\n' + result[6]
                result[2].replace(result[6], '')
            # Result fields translate as
            # [1]: author, [2]: quote, [3]: date, [6]: embed url, [7]: jump_url
            if result[7]:
                text = '{} \n\n{}'.format(result[2], context_url)
            else:
                text = result[2]
            return stm.format(title, text, result[1], result[3])

        else:
            stm = stm.format(result[1], result[3])

            if len(result) > 6 and result[6]:
                result[2].replace(result[6], '')
            banner = Embed(title=title, description=result[2])
            banner.add_field(name='Context ', value=context_url, inline=False)
            if len(result) > 6 and result[6]:
                banner.set_image(url=result[6])
            banner.set_footer(text=stm)

            return banner
Beispiel #20
0
def insert_quote(message, Table, adder=None):
    """
	Insert a quote to the database
	:param message: <Discord.message object>
	:param Table: <SQLAlchemy.Table object>
	:param adder: <String> Username of the member who added the :speech_left:
	:return: <String> Notifying of message being added
	"""
    if Table is None:
        Table = Quotes
    config = load_config(message.guild.id)
    if config:
        server_locale = config[2]
        stm = config[7].replace('\\n', '\n')
    else:
        server_locale = 'Asia/Tokyo'
        stm = '--{} on {}'
    # Suppress any user or role mentions
    text = message.content
    for each in message.mentions:
        text = text.replace('<@!{}>'.format(each.id), each.name)
    for each in message.role_mentions:
        text = text.replace('<@&{}>'.format(each.id), each.name)
    text = text.replace('@everyone', '@ everyone')
    text = text.replace('@here', '@ here')

    jump_url = message.jump_url

    args = text.split()

    embed = str(message.attachments[0].url) if message.attachments else None
    if not embed:
        embed = ''
        for each in args:
            if each.find('http') != -1:
                if each.split('.')[-1] in extSet['image']:
                    embed = '{}\n{}'.format(embed, each)
    date = pendulum.now(tz=server_locale).to_day_datetime_string()

    with ENGINE.connect() as conn:
        if Table.name == 'famQuotes':
            ins = Table.insert().values(
                id=message.id,
                name=message.author.name,
                text=text,
                date=date,
                guild=str(message.guild.id),
                guild_name=message.guild.name,
                embed=embed,
                context=jump_url,
            )
            conn.execute(ins)

            if not fetch_value(message.guild.id, 10):
                banner = Embed(title="{} Added Quote: {}".format(
                    adder, message.id),
                               description=text)
            else:
                banner = Embed(title="Added Quote: {}".format(message.id),
                               description=text)
            if embed:
                banner.set_image(url=embed)
            banner.set_footer(text=stm.format(message.author.name, date))

        elif Table.name == 'famLore':
            ins = Table.insert().values(
                id=message.id,
                name=args[2],
                text=' '.join(args[3:]),
                date=date,
                guild=str(message.guild.id),
                embed=embed,
                guild_name=message.guild.name,
            )
            conn.execute(ins)

            banner = Embed(title="Added Lore: {}".format(message.id),
                           description=' '.join(args[3:]))
            if embed:
                banner.set_image(url=embed)
            banner.set_footer(text=stm.format(args[2], date))

    return banner
Beispiel #21
0
def increment_usage(guild, command):
    """Keeps track of how many times various commands have been used"""
    with ENGINE.connect() as conn:
        select_st = select([Stats]).where(Stats.c.id == guild.id)
        result = conn.execute(select_st).fetchone()

        if result:
            columns = []
            for each in Stats.c:
                columns.append(each.name)
            dict_ = dict(zip(columns, result))
            dict_[command] = int(dict_[command]) + 1

            ins = Stats.update().where(Stats.c.id == guild.id).values(
                raw_messages=dict_['raw_messages'],
                quote=dict_['quote'],
                lore=dict_['lore'],
                wolf=dict_['wolf'],
                wotd=dict_['wotd'],
                dict=dict_['dict'],
                trans=dict_['trans'],
                google=dict_['google'],
                config=dict_['config'],
                sched=dict_['sched'],
                filter=dict_['filter'],
                doip=dict_['doip'],
                gif=dict_['gif'],
                stats=dict_['stats'],
                eight=dict_['eight'],
                help=dict_['help'],
                custom=dict_['custom'],
            )
            conn.execute(ins)
            return 1

        else:
            if VERBOSE >= 2:
                print('[+] Creating usage counter for {}'.format(guild.name))
            ins = Stats.insert().values(
                id=guild.id,
                guild_name=guild.name,
                raw_messages=0,
                quote=0,
                lore=0,
                wolf=0,
                wotd=0,
                dict=0,
                trans=0,
                google=0,
                config=0,
                sched=0,
                filter=0,
                doip=0,
                gif=0,
                stats=0,
                eight=0,
                help=0,
                custom=0,
            )
            conn.execute(ins)
            return increment_usage(guild, command)