Beispiel #1
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, should_spawn_thread=False, **kwargs)
     self.public_namespace.db = dataloader.datafile(DB_FILE, load_as='db')
     self.public_namespace.db.execute(CREATE_UPTIMES_TABLE_SQL)
     self.public_namespace.db.patch('uptimes', COLUMNS, commit=True)
     self.run = 0
     self.spawn_process()
Beispiel #2
0
 def __init__(self, **kwargs):
     super().__init__(**kwargs)
     self.public_namespace.active_emoji_messages = dict(
     )  # dict associating messages to their reaction name, for assigning emojis
     self.public_namespace.active_perm_messages = dict(
     )  # dict associating users to their command/reaction name, for assigning perms
     try:
         self.public_namespace.commandersfile = dataloader.datafile(
             self.config[COMMANDERS])
     except FileNotFoundError:
         print(
             "The %s file is either missing or corrupted; unable to load" %
             self.config[COMMANDERS])
         self.public_namespace.commandersfile = dataloader.newdatafile(
             self.config[COMMANDERS])
     if not isinstance(self.public_namespace.commandersfile.content, dict):
         self.public_namespace.commandersfile.content = {
             REACTIONS: dict(),
             COMMANDS: dict(),
             PACKAGES: dict()
         }
     self.public_namespace.commandersfile.save(
     )  # create & save file, in case it didn't exist before
     # commanders is a 3-dimensional dictionary; command_type -> command_name -> {'owner':user_id, 'maintainers':[list of user_ids]}
     self.public_namespace.commanders = self.public_namespace.commandersfile.content
     self.public_namespace.OWNER = OWNER
     self.public_namespace.MAINTAINERS = MAINTAINERS
     self.public_namespace.DEFAULT_OWNER_ID = DEFAULT_OWNER_ID
     self.public_namespace.REACTIONS = REACTIONS
     self.public_namespace.COMMANDS = COMMANDS
     self.public_namespace.PACKAGES = PACKAGES
     self.public_namespace.PLUGINS = PLUGINS
     self.public_namespace.is_commander = self.is_commander
Beispiel #3
0
 def add_data(self, name, content_from=DEFAULT):
     '''(str, str) -> None
     Adds configuration data to Bot's data dict. It expects that data_config
     contains an entry for 'name' which points to a file that it can extract
     content from. content_from may be specified to get data other than the
     default.'''
     data_file = dataloader.datafile(self.data_config[name])
     self.data[name] = data_file.content[content_from]
Beispiel #4
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.public_namespace.database = self.public_namespace.db = dataloader.datafile(self.config['database'])
     # set up db if not already setup
     self.public_namespace.db.execute('CREATE TABLE IF NOT EXISTS filters (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL)')
     # create columns if not exist
     self.public_namespace.db.patch('filters', COLUMNS, commit=True)
     # set up constants
     self.public_namespace.DELETE = DELETE
     self.public_namespace.PIN = PIN
     self.public_namespace.PIPE = PIPE
     self.public_namespace.NOTHING = NOTHING
     self.public_namespace.FILTER_ACTIONS = FILTER_ACTIONS
Beispiel #5
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, should_spawn_thread=False, **kwargs)

        self.public_namespace.database = self.public_namespace.db = dataloader.datafile(
            self.config['database'])
        # create table if not exists
        self.public_namespace.db.execute(CREATE_TABLE_SQL)
        # create new columns if not exist
        self.public_namespace.db.patch('reminders',
                                       COLUMNS_TO_PATCH,
                                       commit=True)
        self.this_run = 0
        self.spawn_process()
Beispiel #6
0
 def __init__(self, config, log, checks, stop_queue):
     '''(str, Logger, fun) -> Bot
     config: a string which is the loaction of the base config file
     log: a Logger for dumping info
     checks: a function which checks reddit/forum/twitter for new stuff'''
     super().__init__()
     if not config:
         # TODO: raise some kind of exception
         pass
     self.data_config = dataloader.datafile(config).content[DEFAULT]
     self.log = log
     # TODO(14flash): Plugin refactor, where we won't need a doCheck() func anymore
     self.checks = checks
     self.data = dict()
     self.commands = list()
     self.reaction_add_commands = list()
     self.reaction_remove_commands = list()
     self.plugins = list()
     self.stop_queue=stop_queue
Beispiel #7
0
 def action(self, message):
     quotedMessage = eval(
         dataloader.datafile(
             self.saveloc + "/" +
             re.search(r'(\d{18})', message.content).group(1) +
             ".txt").content[0])
     em = embed.create_embed(author={
         "name": quotedMessage["author"],
         "url": None,
         "icon_url": None
     },
                             footer={
                                 "text":
                                 "#" + quotedMessage["channel"] + " of " +
                                 quotedMessage["server"],
                                 "icon_url":
                                 None
                             },
                             description=quotedMessage["content"],
                             colour=0xffffff)
     yield from self.send_message(message.channel, embed=em)
Beispiel #8
0
    def generate_commanders(self, bot):
        commanders2 = dataloader.datafile(
            self.public_namespace.commandersfile.filename).content
        if not isinstance(commanders2, dict):
            commanders2 = dict()
            commanders2[self.public_namespace.COMMANDS] = dict()
            commanders2[self.public_namespace.REACTIONS] = dict()
            commanders2[self.public_namespace.PLUGINS] = dict()
            commanders2[self.public_namespace.PACKAGES] = dict()

        # ensure all commands are in commanders2
        if self.public_namespace.COMMANDS not in commanders2:
            commanders2[self.public_namespace.COMMANDS] = dict()
        for name in bot.commands:
            if name not in commanders2[self.public_namespace.COMMANDS]:
                commanders2[self.public_namespace.COMMANDS][name] = "missing"

        # ensure all reactions are in commanders2
        if self.public_namespace.REACTIONS not in commanders2:
            commanders2[self.public_namespace.REACTIONS] = dict()
        for name in bot.reactions:
            if name not in commanders2[self.public_namespace.REACTIONS]:
                commanders2[self.public_namespace.REACTIONS][name] = "missing"

        # ensure all plugins are in commanders2
        if self.public_namespace.PLUGINS not in commanders2:
            commanders2[self.public_namespace.PLUGINS] = dict()
        for name in bot.plugins:
            if name not in commanders2[self.public_namespace.PLUGINS]:
                commanders2[self.public_namespace.PLUGINS][name] = "missing"

        # ensure all packages are in commanders2
        if self.public_namespace.PACKAGES not in commanders2:
            commanders2[self.public_namespace.PACKAGES] = dict()
        for package in loader.sub_namespaces:
            if package not in commanders2[self.public_namespace.PACKAGES]:
                commanders2[
                    self.public_namespace.PACKAGES][package] = "missing"

        return commanders2
Beispiel #9
0
# this badly needs to be changed to OOP, because it's rly hurtful to understand right now
from libs import dataloader

timezones = dataloader.datafile("./data/timezones.csv")


class SimpleTime:
    ''' stores a time in an easy format '''
    def __init__(self, time):
        ''' (SimpleTime, str) -> None
        str must be a time in format (H)H:MM where HH and MM are valid positive integers
        Do I rly need to say what __init__ does? '''
        timeSplit = time.split(":")
        try:
            if "am" == timeSplit[0][-2:].lower():
                self.hour = int(timeSplit[0][:-2])
            elif "pm" == timeSplit[0][-2:].lower():
                self.hour = int(timeSplit[0][:-2])
                self.hour += 12
            else:
                self.hour = int(timeSplit[0])
        except:
            raise ValueError("Invalid time")
        try:
            if "am" == timeSplit[1][-2:].lower():
                self.minute = int(timeSplit[1][:-2])
            elif "pm" == timeSplit[1][-2:].lower():
                self.hour += 12
                self.minute = int(timeSplit[1][:-2])
            else:
                self.minute = int(timeSplit[1])
Beispiel #10
0
    def action(self, message, bot):
        try:
            # boolean variables to indicate what has to and will be done for loading
            is_reload = False
            is_download = True
            has_config = False
            config_loaded = False
            # if no attachment, try to reload add-on
            if len(message.attachments) == 0:
                is_reload = True
                is_download = False
            args = self.collect_args(message)
            # info from command
            addon_type = args.group(
                2).lower()  # either 'reactions', 'commands' or 'plugins'
            name = args.group(1) + '.py'  # name of add-on file
            addon_name = name[name.rfind('/') + 1:-len('.py')]
            package = name[name.find('/') + 1:name.rfind(
                '/'
            )]  # package; middle folder (<addon_type>/<middble folder>/<name>) or None

            # if add-on exists, reload it
            if os.path.exists(name):
                is_reload = True
            elif not is_download:
                yield from self.send_message(
                    message.channel,
                    "I can't load a non-existent " + addon_type[:-1])
                return
            elif package != None and not os.path.exists(
                    os.path.join(addon_type, package)):
                # if package doesn't exist, make it
                os.makedirs(package)

            # check/setup permissions
            '''Add-ons in the main folder of an add-on type have their own
            commander permissions (ie people who can modify the add-on)

            Add-ons in subfolders ("packages") have package-level commander
            permissions (ie all add-ons in a package share permissions) '''
            if package:
                type = self.public_namespace.PACKAGES
            else:
                type = addon_type
            if not is_reload and package == None:
                # add-on is new
                self.public_namespace.commanders[type][addon_name] = dict()
                self.public_namespace.commanders[type][addon_name][
                    self.public_namespace.OWNER] = message.author.id
                self.public_namespace.commanders[type][addon_name][
                    self.public_namespace.MAINTAINERS] = list()
            elif not is_reload and package not in self.public_namespace.commanders[
                    self.public_namespace.PACKAGES]:
                # new add-on is in a new package
                self.public_namespace.commanders[type][package] = dict()
                self.public_namespace.commanders[type][package][
                    self.public_namespace.OWNER] = message.author.id
                self.public_namespace.commanders[type][package][
                    self.public_namespace.MAINTAINERS] = list()
            elif not package and not (self.public_namespace.is_commander(
                    message.author.id, addon_name, type)
                                      or message.author.id in bot.ADMINS):
                # add-on already exists and user is missing permissions
                yield from self.send_message(
                    message.channel,
                    "`%s` add-on already exists and you do not have permissions to modify it."
                    % addon_name)
                return
            elif package and not (self.public_namespace.is_commander(
                    message.author.id, package, type)
                                  or message.author.id in bot.ADMINS):
                # add-on is in package and user is missing permissions for package
                yield from self.send_message(
                    message.channel,
                    "`%s` package already exists and you do not have permissions to modify it."
                    % package)
                return

            # download new file (if there's one to download)
            if is_download:
                # save file to temp location, for safety before file safety is verified
                index_pyfile = None
                # find python file attachment by file extension '.py'
                for i in range(len(message.attachments)):
                    if message.attachments[i]['filename'].endswith('.py'):
                        index_pyfile = i
                        break
                filename = TEMP_START + str(datetime.datetime.now().isoformat(
                )) + 'ID' + message.author.id + '.py'
                temp_file = dataloader.newdatafile(filename)
                temp_file.content = [
                    requests.get(message.attachments[index_pyfile]["url"]).text
                ]
                temp_file.save()
                # verification
                try:
                    verifyaddon.verify(filename, addon_type)
                except ImportError as e:
                    if '-v' in message.content:
                        yield from self.send_message(
                            message.channel,
                            "Your add-on failed to pass verification: \n" +
                            "```" + traceback.format_exc() + "```")
                    else:
                        yield from self.send_message(
                            message.channel,
                            "Your add-on failed to pass verification: \n" +
                            "`" + str(e) + "`")
                    return
                # save file to non-temp location
                file = dataloader.newdatafile(name)
                file.content = temp_file.content
                file.save()
                if len(message.attachments) >= 2:
                    has_config = True
                    # save config file
                    index_config = None
                    # find config file
                    for i in range(len(message.attachments)):
                        if message.attachments[i]['filename'].endswith(
                                '.config'):
                            index_config = i
                            break
                    if index_config == None:
                        config_loaded = False
                    else:
                        config_file = dataloader.newdatafile(
                            name[:-len('.py')] + '.config')
                        config_file.content = [
                            requests.get(
                                message.attachments[index_config]["url"]).text
                        ]
                        config_file.save()
                        config_loaded = True
                if addon_type == PLUGIN and config_loaded == False and not os.path.exists(
                        name[:-len('.py')] + '.config'):
                    # config file is required for plugins, so load default
                    config_file = dataloader.newdatafile(name[:-len('.py')] +
                                                         '.config')
                    config_file.content = dataloader.datafile(
                        DEFAULT_PLUGIN_CONFIG, load_as='text').content
                    config_file.save(save_as='text')
                    config_loaded = True

            # load add-on
            py_filename = name[name.rfind('/') + 1:]
            cmd_name = py_filename[:-len('.py')]
            if addon_type == COMMAND:
                bot.load_command(py_filename,
                                 cmd_name,
                                 package=package,
                                 reload=is_reload)
            elif addon_type == REACTION:
                bot.load_reaction(py_filename,
                                  cmd_name,
                                  package=package,
                                  reload=is_reload)
            elif addon_type == PLUGIN:
                bot.load_plugin(py_filename,
                                cmd_name,
                                package=package,
                                reload=is_reload)
            else:
                bot.load_addon(py_filename,
                               cmd_name,
                               package=package,
                               reload=is_reload)
            yield from self.send_message(
                message.channel,
                self.get_response(name, is_reload, is_download, has_config,
                                  config_loaded))
        except:
            traceback.print_exc()
            yield from self.send_message(
                message.channel,
                'An unexpected error occurred. 🔥 Please 🔥 do 🔥 not 🔥 panic, 🔥 everything 🔥 is 🔥 under 🔥 control 🔥'
            )
Beispiel #11
0
 def __init__(self, **kwargs):
     super().__init__(**kwargs)
     self.karma_up_data = dataloader.datafile(self.public_namespace.config[KARMA_UP_LOC]).content
     self.karma_down_data = dataloader.datafile(self.public_namespace.config[KARMA_DOWN_LOC]).content
Beispiel #12
0
        tweet = qTwitter.get()
        yield from bot.send_message(
            bot.twitterchannel, "Idea Project tweeted this: " + tweet[1] +
            " (from: <" + tweet[0] + ">)")
    while not qReddit.empty():
        comment = qReddit.get()
        yield from bot.send_message(
            bot.redditchannel, "A comment has been posted here: " +
            comment[0] + " (direct link: <" + comment[1] + ">)")


if __name__ == '__main__':
    # main
    # init stuff
    loop = asyncio.get_event_loop()
    config = dataloader.datafile("./data/config.config")
    config.content = config.content["DEFAULT"]
    credentials = dataloader.datafile(config.content["credentialsloc"])
    credentials.content = credentials.content["DEFAULT"]
    channels = dataloader.datafile(config.content["channelsloc"])
    channels.content = channels.content["DEFAULT"]
    perms = dataloader.datafile(config.content["permissionsloc"])
    perms.content = perms.content["DEFAULT"]
    forumdiscorduser = dataloader.datafile(
        config.content["forumdiscorduserloc"])
    forumdiscorduser.content = forumdiscorduser.content["DEFAULT"]

    log = mainLogging()

    stop = Queue()
    bot = botlib.Bot("./data/config.config", log, doChecks, stop)
Beispiel #13
0
 def __init__(self, filename, **kwargs):
     super().__init__(**kwargs)
     self.pifile = dataloader.datafile(filename)
Beispiel #14
0
 def action(self, message):
     args = self.collect_args(message)
     op_flag = ''
     msg_content = None
     # determine operation
     operation = args.group(1).lower() if args.group(1) is not None else ''
     if operation in todo_rm_words:
         op_flag = 'remove'
     elif operation in todo_add_words:
         op_flag = 'add'
     elif operation in todo_list_words:
         op_flag = 'list'
     else:
         if args.group(2):
             op_flag = 'add'
         else:
             op_flag = 'list'
     # determine if public list
     list_name = message.author.id
     task = args.group(2).strip() if args.group(2) is not None else ''
     if args.group(2):
         list_args = self.collect_list(args.group(2))
         if list_args and not is_id_like(list_args.group(1)):
             list_name = list_args.group(1)
             task = args.group(2).replace(list_args.group(0), '')
     elif op_flag == 'add' or op_flag == 'remove':
         yield from self.send_message(
             message.channel, 'Please specify the task to %s' % op_flag)
         return
     # load files if they don't already exist
     if list_name not in todoFiles:
         try:
             todoFiles[list_name] = dataloader.datafile(self.saveloc +
                                                        list_name + ".txt")
         except FileNotFoundError:
             todoFiles[list_name] = dataloader.newdatafile(self.saveloc +
                                                           list_name +
                                                           ".txt")
     # add task
     if op_flag == 'add':
         # TODO: check for permissions to edit list_name before adding task
         index = self.get_index_for_task(task, todoFiles[list_name])
         if index != -1 and re.match(r'^\d+$', task) != None:
             msg_content = "I'm sorry, `%s` already exists" % task
         else:
             todoFiles[list_name].content.append(task)
             msg_content = "Task added"
     # remove task
     if op_flag == 'remove':
         # TODO: check for permissions to edit list_name before removing task
         index = self.get_index_for_task(task, todoFiles[list_name])
         if index == -1 or index >= len(todoFiles[list_name].content):
             msg_content = "I'm sorry, I can't find `%s`." % task
         else:
             del (todoFiles[list_name].content[index])
             todoFiles[list_name].save()
             msg_content = "Task deleted"
     # always list tasks after everything
     list_display_name = list_name if list_name != message.author.id else 'Todo'
     if re.search(r'\s-p', message.content,
                  re.I) != None or list_name != message.author.id:
         yield from self.send_message(message.channel,
                                      msg_content,
                                      embed=embed.create_embed(
                                          title=list_display_name,
                                          description=self.todo2string(
                                              todoFiles[list_name]),
                                          colour=0xffffff))
     else:
         yield from self.send_message(message.author,
                                      msg_content,
                                      embed=embed.create_embed(
                                          title=list_display_name,
                                          description=self.todo2string(
                                              todoFiles[list_name]),
                                          colour=0xffffff))
     # save file
     todoFiles[list_name].save()
     # remove file from memory if empty, to save some memory
     if len(todoFiles[list_name].content) == 0:
         del (todoFiles[list_name])
Beispiel #15
0
 def __init__(self, **kwargs):
     super().__init__(**kwargs)
     self.invalid_message = INVALID_MESSAGE
     self.invalid_messages = dataloader.datafile(INVALID_MESSAGES_LOC).content