Пример #1
0
 def record_names(self, irc_c, msg):
     # msg.args is a string
     # "TARS = #channel :name1 name2 name3 name4"
     nicks = re.split(r"\s:?", msg.args.strip())
     nicks = nicks[2:]
     channel = nicks.pop(0)
     names = [{'nick': name} for name in nicks]
     # chatstaff names start with a punctuation
     for key, name in enumerate(names):
         if name['nick'][0] in '+%@&~':
             names[key] = {
                 'nick': name['nick'][1:],
                 'mode': name['nick'][0]
             }
         else:
             names[key] = {'nick': name['nick'], 'mode': None}
     # just need to log these names to the db now
     nameprint("Updating NAMES for {}: {}".format(
         nickColor(channel),
         ", ".join(nickColor(nick) for nick in sorted(nicks))))
     try:
         DB.sort_names(channel, names)
     except Exception as e:
         irc_c.RAW("PRIVMSG #tars NAMES error: " + str(e))
         raise
     # broadcast this info to whatever needs it
     emit_signal(irc_c, 'NAMES_RESPONSE', data=channel)
Пример #2
0
 def change_name(self, irc_c, msg):
     assert msg.kind == 'NICK'
     nameprint("{} changed their name to {}".format(msg.nick, msg.args))
     try:
         DB.rename_user(msg.nick, msg.args)
     except Exception as e:
         irc_c.RAW("PRIVMSG #tars NAMES error: " + str(e))
         raise
Пример #3
0
 def command(cls, irc_c, msg, cmd):
     if (defer.check(cmd, 'jarvis', 'Secretary_Helen')):
         return
     if len(cmd.args['root']) > 0 and cmd.args['root'][0][0] == '#':
         channel = cmd.args['root'][0]
         irc_c.JOIN(channel)
         msg.reply("Joining {}".format(channel))
         irc_c.PRIVMSG(channel, "Joining by request of {}".format(msg.nick))
         DB.join_channel(channel)
     else:
         msg.reply("You'll need to specify a valid channel.")
Пример #4
0
 def command(cls, irc_c, msg, cmd):
     cmd.expandargs(["message m"])
     if (defer.check(cmd, 'jarvis', 'Secretary_Helen')):
         return
     if 'message' in cmd:
         leavemsg = " ".join(cmd['message'])
     else:
         leavemsg = None
     if len(cmd.args['root']) > 0:
         channel = cmd.args['root'][0]
     else:
         channel = msg.raw_channel
     irc_c.PART(channel, message=leavemsg)
     DB.leave_channel(channel)
Пример #5
0
 def get_series_metadata(url, soup, **kwargs):
     """Gets metadata for generic series pages that match assumptions"""
     reply = kwargs.get('reply', lambda x: None)
     # parse the html
     titles = soup.select(
         ".content-panel:nth-of-type(1) > ul:not(:first-of-type) li")
     # <li><a href="/scp-xxx">SCP-xxx</a> - Title</li>
     for title in titles:
         # take the scp number from the URL, not the URL link
         # take the scp name from the text
         # if ANYTHING is unexpected, cancel and throw
         title = str(title)
         # sort out the scp-number
         pattern = re.compile(
             r"""
             <li>                  # start of the "title"
             (.+?                  # anything before the link
             href="/(.+?)"         # page url
             >)(.+?)</a>           # page's literal title
             (?:                   # start post-link group
               .+?-\s?             # anything after link & before title
               (.*?)               # page's meta title
             )?                    # end post-link group; select if present
             </li>                 # end of the "title"
         """, re.VERBOSE)
         match = pattern.search(title)
         if not match:
             reply("Unknown link format: {}".format(title))
             continue
         # TODO if newpage in class then article does not exist
         if "class=\"newpage\"" in match.group(1):
             # article doesn't exist
             # DB.remove_article()
             continue
         num = match.group(2)
         meta_title = match.group(4)
         if meta_title in ("[ACCESS DENIED]", ""):
             meta_title = None
         if meta_title is None:
             if num.lower() != match.group(3).lower():
                 meta_title = match.group(3)
                 reply("Assuming title '{}' for {}".format(meta_title, num))
             else:
                 reply("{} has no title".format(num))
                 # don't add title but also don't delete
         # then add these numbers and names to the DB
         # if "<" in meta_title: print(num, meta_title)
         DB.add_article_title(num, num, meta_title, False)
     DB.commit()
Пример #6
0
 def get_attribution_metadata(url, soup, **kwargs):
     """Gets attribution metadata"""
     reply = kwargs.get('reply', lambda x: None)
     # parse the html
     titles = soup.select(".wiki-content-table tr:not(:first-child)")
     # pages = dict of key url and value actions[]
     pages = defaultdict(lambda: defaultdict(list))
     # actions to take for each type of metadata
     actions = {
         'author':
         lambda url, values: DB.set_authors(url,
                                            [v['name'] for v in values]),
         'rewrite':
         lambda url, values: None,
         'translator':
         lambda url, values: None,
         'maintainer':
         lambda url, values: None
     }
     for title in titles:
         title = str(title)
         pattern = re.compile(
             r"""
             <tr>\s*
             <td>(.*?)</td>\s*      # affected page url
             <td>(.*?)</td>\s*      # name
             <td>(.*?)</td>\s*      # metadata type
             <td>(.*?)</td>\s*      # date
             </tr>
         """, re.VERBOSE)
         match = pattern.search(title)
         if not match:
             reply("Unknown attribute format: {}".format(title))
             continue
         pages[match.group(1)][match.group(3)].append({
             'name': match.group(2),
             'date': match.group(4)
         })
     for url, page in pages.items():
         if ':' in url:
             # we don't store other categories
             continue
         for type_ in page:
             try:
                 actions[type_](url, page[type_])
             except Exception as e:
                 reply(str(e))
     DB.commit()
Пример #7
0
 def get_gib_sentence(cls,
                      attempts=0,
                      limit=7500,
                      minlength=0,
                      patterns=None):
     print("Getting a gib sentence")
     # messages = []
     # for channel in cls.channels:
     #     print("Iterating channels")
     #     for user in cls.users:
     #         print("Iterating users")
     #         messages.extend(DB.get_messages(channel, user))
     messages = DB.get_messages(
         cls.channels,
         minlength=40,
         limit=limit,
         senders=None if cls.users == [None] else cls.users,
         patterns=patterns)
     print("messages found: {}".format(len(messages)))
     if len(messages) == 0:
         raise AttributeError
     for decr in range(0, cls.size):
         print("Making model from messages, size {}".format(cls.size -
                                                            decr))
         cls.model = cls.make_model(messages, decrement=decr)
         print("Making sentence")
         sentence = cls.model.make_short_sentence(400,
                                                  minlength,
                                                  tries=200,
                                                  force_result=False)
         if sentence is not None:
             break
         print("Sentence is None")
     if not cls.nocache and sentence in DB.get_gibs():
         print("Sentence already sent, {} attempts remaining".format(
             cls.ATTEMPT_LIMIT - attempts))
         try:
             if attempts < cls.ATTEMPT_LIMIT:
                 sentence = cls.get_gib_sentence(attempts + 1, limit,
                                                 minlength, patterns)
             else:
                 raise RecursionError
         except RecursionError:
             raise MyFaultError("I didn't find any gibs for that selection "
                                "that haven't already been said.")
     if sentence is not None:
         DB.add_gib(sentence)
     return sentence
Пример #8
0
 def roulette(cls, roulette_type):
     """Get a random image or video link"""
     # take all the messages in the channel, filtered for links
     messages = DB.get_messages(cls.channels,
                                senders=cls.users,
                                patterns=[_URL_PATT])
     if len(messages) == 0:
         raise MyFaultError("I didn't find any URLs in the "
                            "selection criteria.")
     # then reduce strings containing urls to urls
     urls = [
         re.search(_URL_PATT, message, re.IGNORECASE).group(0)
         for message in messages
     ]
     # make urls unique
     urls = list(set(urls))
     # then filter by either images or videos
     if roulette_type == 'image':
         urls = [url for url in urls if _IMG_PATT.search(url)]
         if len(urls) == 0:
             raise MyFaultError("I didn't find any images.")
     if roulette_type in ['video', 'youtube', 'yt']:
         urls = [url for url in urls if _YT_PATT.search(url)]
         if len(urls) == 0:
             raise MyFaultError("I didn't find any video links.")
     return urls
Пример #9
0
 def get_wiki_data_for(cls, urls, **kwargs):
     print("Getting wiki data!")
     reply = kwargs.get('reply', lambda x: None)
     # get the wiki data for this article
     # we're taking all of root, so url is a list
     for urls in chunks(urls, 10):
         print(urls)
         articles = SCPWiki.get_meta({'pages': urls})
         for url, article in articles.items():
             prop_print("Updating {} in the database".format(url))
             DB.add_article(article, commit=False)
             if 'metadata' in article['tags']:
                 # TODO use list from above
                 continue  # skip for now
                 propagate.get_metadata(url, reply=reply)
     DB.commit()
Пример #10
0
 def check(cls, cmd, *bots):
     """Check whether the given bots are in the channel"""
     # bots should be a list of bot names?
     defer.get_users(cmd.context, cmd.channel)
     if cmd.pinged: return False
     if cmd.force: return False
     members = DB.get_channel_members(cmd.channel)
     return set(members) & set(bots)
Пример #11
0
 def command(cls, irc_c, msg, cmd):
     cmd.expandargs(["add a",
                     "remove r",
                     "list l"])
     if len(cmd.args['root']) > 0:
         nick = cmd.args['root'][0]
     else:
         nick = msg.sender
     # 1. Check if this is the right nick
     # get the user ID
     user_id = DB.get_user_id(nick)
     if user_id is None:
         msg.reply("I don't know anyone called '{}'.".format(nick))
         return
     # 2. Add new aliases
     if 'add' in cmd:
         if nick.lower() != msg.sender.lower() and not defer.controller(cmd):
             raise CommandError("You can't add an alias for someone else.")
         aliases = cmd['add']
         # db has add_alias, but that needs user ID
         for alias in aliases:
             if alias.lower() == msg.sender.lower():
                 continue
             if DB.add_alias(user_id, alias, 1):
                 msg.reply("{} already has the alias {}!".format(nick,alias))
         msg.reply("Added aliases to {}: {}".format(nick, ", ".join(aliases)))
         irc_c.PRIVMSG(CONFIG.home, "{} added alias {}".format(nick,alias))
     if 'remove' in cmd:
         if nick.lower() != msg.sender.lower() and not defer.controller(cmd):
             raise CommandError("You can't remove an alias from someone else.")
         aliases = cmd['remove']
         # db has add_alias, but that needs user ID
         for alias in aliases:
             if not DB.remove_alias(user_id, alias, 1):
                 msg.reply("{} didn't have the alias {}!".format(nick,alias))
         msg.reply("Removed aliases from {}: {}".format(nick, ", ".join(aliases)))
     if 'list' in cmd:
         # get all aliases associated with the user
         aliases = DB.get_aliases(user_id)
         msg.reply("I've seen {} go by the names: {}"
                   .format(nick if nick != msg.sender else "you",
                           ", ".join(aliases)))
     if not any(['add' in cmd,'remove' in cmd,'list' in cmd]):
         raise CommandError("Add or remove aliases to a nick with --add "
                            "and --remove. See all nicks with --list")
Пример #12
0
 def command(cls, irc_c, msg, cmd):
     if len(cmd.args['root']) < 1:
         raise CommandError("Specify a page's URL whose shortest search "
                            "term you want to find.")
     pages = [DB.get_article_info(p_id)['title']
              for p_id in DB.get_articles([])]
     try:
         title = DB.get_article_info(
             DB.get_articles(
                 [{'type': 'url', 'term': cmd.args['root'][0]}]
             )[0])['title']
     except IndexError:
         raise MyFaultError("I couldn't find the page with that URL.")
     single_string = shortest.get_substring(title, pages)
     print("Single string:", single_string)
     helen_style = shortest.get_multi_substring(title, pages)
     if single_string is None and helen_style is None:
         raise MyFaultError("There's no unique search for {} (\"{}\")"
                            .format(cmd.args['root'][0], title))
     msg.reply("Shortest search for \x02{}\x0F · {}"
               .format(cmd.args['root'][0],
                       shortest.pick_answer(single_string, helen_style)))
Пример #13
0
 def command(cls, irc_c, msg, cmd):
     if(defer.check(cmd, 'jarvis', 'Secretary_Helen')): return
     if len(cmd.args['root']) > 1 or not all(map(isint, cmd.args['root'])):
         raise CommandError("Specify the number of the article you want "
                            "(or none to see the choices)")
     elif len(cmd.args['root']) == 0:
         number = 0
     else:
         number = int(cmd.args['root'][0])
     page_ids = DB.get_showmore_list(msg.raw_channel)
     if len(page_ids) == 0:
         raise MyFaultError("I have nothing to show more of.")
     if number > len(page_ids):
         raise MyFaultError("I only have {} results for the last search."
                            .format(len(page_ids)))
     pages = [DB.get_article_info(p_id) for p_id in page_ids]
     if number == 0:
         msg.reply("{} saved results (use ..sm to choose): {}".format(
             len(pages), showmore.parse_multiple_titles(pages)))
     else:
         msg.reply("{}/{} · {}".format(
             number, len(page_ids), showmore.parse_title(pages[number-1])))
Пример #14
0
 def log(self, irc_c, msg):
     chname = "private" if msg.raw_channel is None else msg.raw_channel
     if msg.kind == 'PRIVMSG':
         print("[{}] {} <{}> {}".format(time.strftime("%H:%M:%S"),
                                        parse.nickColor(chname),
                                        parse.nickColor(msg.nick),
                                        msg.message))
     elif msg.kind == 'NICK':
         print("[{}] {} changed their name to {}".format(
             time.strftime("%H:%M:%S"), parse.nickColor(msg.nick),
             parse.nickColor(msg.args)))
     else:
         print("[{}] {} {} {}".format(
             time.strftime("%H:%M:%S"), parse.nickColor(msg.nick),
             "joined" if msg.kind == 'JOIN' else "left",
             parse.nickColor(chname)))
     try:
         if not gimmick(msg.message):
             DB.log_message(msg)
     except:
         irc_c.RAW("PRIVMSG #tars A logging error has occurred.")
         raise
Пример #15
0
 def debug(self, irc_c, msg):
     msg = parse.output(msg)
     if not msg:
         return
     print("[{}] --> {}: {}".format(time.strftime('%H:%M:%S'),
                                    parse.nickColor(msg['channel']),
                                    msg['message']))
     if "IDENTIFY" in msg['message']: return
     msg = {
         'channel':
         msg['channel'] if msg['channel'].startswith('#') else None,
         'sender': CONFIG.nick,
         'kind': "PRIVMSG",
         'message': msg['message'],
         'nick': CONFIG.nick,
         'timestamp': int(time.time())
     }
     try:
         DB.log_message(msg)
     except:
         irc_c.RAW("PRIVMSG #tars A logging error has occurred.")
         raise
Пример #16
0
 def command(irc_c, msg, cmd):
     if defer.check(cmd, 'Secretary_Helen'):
         return
     cmd.expandargs(["first f",
                     "count c"])
     # have to account for .seen -f name
     if 'first' in cmd:
         cmd.args['root'].extend(cmd.args['first'])
     if 'count' in cmd:
         cmd.args['root'].extend(cmd.args['count'])
     if len(cmd.args['root']) < 1:
         raise CommandError("Specify a user and I'll tell you when I last "
                            "saw them")
     nick = cmd.args['root'][0]
     messages = DB.get_messages_from_user(nick, msg.raw_channel)
     if len(messages) == 0:
         raise MyFaultError("I've never seen {} in this channel."
                            .format(nick))
     if 'count' in cmd:
         msg.reply("I've seen {} {} times in this channel."
                   .format(nick, len(messages)))
         return
     if 'first' in cmd:
         message = messages[0]
         response = "I first saw {} {} saying: {}"
     else:
         if nick == msg.sender:
             msg.reply("I can see you right now, {}.".format(msg.sender))
             return
         message = messages[-1]
         response = "I last saw {} {} saying: {}"
     response = response.format(
         nick if nick == message['sender']
         else "{} as {}".format(nick, message['sender']),
         pd.from_timestamp(message['timestamp']).diff_for_humans(),
         gib.obfuscate(message['message'],
                       DB.get_channel_members(msg.raw_channel)))
     msg.reply(response)
Пример #17
0
 def command(cls, irc_c, msg, cmd):
     if not defer.controller(cmd):
         raise CommandError("I'm afriad I can't let you do that.")
         return
     if cls.has_refactored:
         raise CommandError("Already refactored once this reload.")
     if 'callback' in cmd:
         print(cmd['callback'])
         if cmd['callback'][0] == "msg.reply":
             callback = msg.reply
         else:
             raise CommandError("Unknown callback")
     else:
         callback = None
     try:
         if 'sql' in cmd:
             DB.issue(" ".join(cmd['sql']), callback=callback)
         else:
             refactor.refactor_database(irc_c)
             cls.has_refactored = True
     except:
         msg.reply("Refactoring failed.")
         raise
     msg.reply("Refactoring succeeded.")
Пример #18
0
 def command(cls, irc_c, msg, cmd):
     try:
         skip = int(cmd.args['root'][0])
     except ValueError:
         skip = 0
     # subtract 1 because ^ = no skips
     skip = skip - 1
     if skip < 0:
         raise CommandError("Chevron count cannot be less than 0")
     # put a chevron limit here eventually, probably
     try:
         limit = int(cmd.args['root'][1])
     except (IndexError, ValueError):
         limit = 10
     if limit > 50:
         raise CommandError("Chevron limit cannot be greater than 50")
     if limit < 1:
         raise CommandError("Chevron limit cannot be less than 1")
     limit = 50 if limit > 50 else limit
     msg.reply("CHEVRON - skip {} - limit {}".format(skip, limit))
     messages = DB.get_messages_to_command_limit(msg.raw_channel, limit)
Пример #19
0
 def command(cls, irc_c, msg, cmd):
     cmd.expandargs(["obfuscate o", "colour color c"])
     if not defer.controller(cmd):
         raise CommandError("I'm afriad I can't let you do that.")
         return
     if len(cmd.args['root']) == 0:
         raise CommandError("Must specify a recipient and message")
     if len(cmd.args['root']) == 1:
         raise CommandError("Must specify a message")
     if cmd.args['root'][0][0] == '/' or cmd.args['root'][1][0] == '/':
         # This is an IRC command
         say.issue_raw(irc_c, msg, cmd)
     else:
         message = " ".join(cmd.args['root'][1:])
         if 'obfuscate' in cmd and msg.raw_channel is not None:
             message = gib.obfuscate(message,
                                     DB.get_aliases(None) + ["ops"])
         if 'colour' in cmd:
             print(nickColor(message))
             msg.reply("Printed that to console")
         irc_c.PRIVMSG(cmd.args['root'][0], message)
         if not cmd.args['root'][0] == msg.raw_channel:
             msg.reply("Saying that to {}".format(cmd.args['root'][0]))
Пример #20
0
    def command(cls, irc_c, msg, cmd):
        if (defer.check(cmd, 'jarvis')): return
        cmd.expandargs([
            "no-cache n", "user u author a", "channel c", "size s",
            "roulette r", "regex x", "minlength length l", "me", "help h"
        ])
        if 'help' in cmd:
            msg.reply("Usage: .gib [--channel #channel] [--user user] "
                      "[--no-cache]")
            return
        channels = [msg.raw_channel]
        users = []
        # root has 1 num, 1 string, 1 string startswith #
        for arg in cmd.args['root']:
            if arg.startswith('#'):
                raise CommandError("Try .gib -c {}".format(arg))
            else:
                raise CommandError("Try .gib -u {}".format(arg))
        if 'channel' in cmd:
            if len(cmd['channel']) == 0:
                raise CommandError("When using the --channel/-c filter, "
                                   "at least one channel must be specified")
            if cmd['channel'][0] == "all":
                if defer.controller(cmd):
                    channels = DB.get_all_channels()
                    msg.reply("Gibbing from all channels I'm in:")
                else:
                    msg.reply("Gibbing from all channels you're in:")
                    # get all channels this user is in
                    raise MyFaultError("This isn't implemented yet.")
            else:
                for channel in cmd['channel']:
                    if not channel.startswith('#'):
                        raise CommandError("Channel names must start with #.")
                channels = cmd['channel']
        elif msg.raw_channel is None:
            raise CommandError("Specify a channel to gib from with "
                               "--channel/-c")
        if 'user' in cmd:
            if len(cmd['user']) == 0:
                raise CommandError("When using the --user/-u filter, "
                                   "at least one user must be specified")
            users = cmd['user']
        if 'size' in cmd:
            try:
                cls.size = int(cmd['size'][0])
            except ValueError:
                raise CommandError("Sizes must be numbers")
        else:
            cls.size = 3
        # ignore gib cache?
        if 'no-cache' in cmd:
            cls.nocache = True
        else:
            cls.nocache = False
        if 'limit' in cmd:
            try:
                limit = int(cmd['limit'][0])
            except ValueError:
                raise CommandError(
                    "When using --limit, the limit must be an int")
            if limit < 200:
                raise CommandError("When using --limit, the limit cannot be "
                                   "lower than 200")
        else:
            limit = CONFIG['gib']['limit']
            if not limit:
                limit = 5000
        if 'roulette' in cmd:
            if len(cmd['roulette']) == 0:
                raise CommandError("When using roulette mode, you must "
                                   "specify a roulette type")
            roulette_type = cmd['roulette'][0]
            if roulette_type not in ['video', 'image', 'youtube', 'yt']:
                raise CommandError("The roulette type must be either "
                                   "'image' or one of 'video','youtube','yt'")
            limit = None
        # can only gib a channel both the user and the bot are in
        for channel in channels:
            if channel is msg.raw_channel:
                continue
            if msg.raw_channel is not None \
               and cmd['channel'][0] != 'all' \
               and not all(x in DB.get_channel_members(channel)
                           for x in [msg.sender, CONFIG.nick]):
                raise CommandError("Both you and the bot must be in a channel "
                                   "in order to gib it.")
            if msg.raw_channel is not None \
               and channel != msg.raw_channel \
               and not defer.controller(cmd):
                raise CommandError("You can only gib the current channel (or "
                                   "any channel from PMs)")
        # Run a check to see if we need to reevaluate the model or not
        if cls.channels == channels and cls.users == users \
           and not cls.nocache:
            print("Reusing Markov model")
        else:
            cls.model = None
            cls.channels = channels
            if len(cls.channels) == 0: cls.channels = [msg.raw_channel]
            cls.users = users
            if len(cls.users) == 0: cls.users = [None]
        # are we gibbing or rouletting?
        if 'roulette' in cmd:
            urls = cls.roulette(roulette_type)
            msg.reply("{} {} · ({} link{} found)".format(
                emojize(":game_die:"), random.choice(urls), len(urls),
                ("s" if len(urls) > 1 else "")))
            return
        if 'regex' in cmd:
            if len(cmd['regex']) == 0:
                raise CommandError("When using the regex filter, you must "
                                   "specify a regex")
            patterns = cmd['regex']
            for pattern in patterns:
                try:
                    re.compile(pattern)
                except re.error as e:
                    raise CommandError("'{}' isn't a valid regular "
                                       "expression: {}".format(pattern, e))
        else:
            patterns = []
        if 'me' in cmd:
            patterns.append(r"\u0001ACTION ")
        if 'minlength' in cmd:
            if len(cmd['minlength']) == 0:
                raise CommandError("When using the minimum length modifier "
                                   "(--length/-l), you must specify a "
                                   "minimum length")
            minlength = cmd['minlength'][0]
            if not isint(minlength):
                raise CommandError("When using the minimum length modifier "
                                   "(--length/-l), the minimum length must be "
                                   "an integer")
            minlength = int(minlength)
        else:
            minlength = 0
        # gibbing:
        try:
            sentence = cls.get_gib_sentence(limit=limit,
                                            minlength=minlength,
                                            patterns=patterns)
            if sentence is None:
                raise AttributeError
        except (RuntimeError, AttributeError):
            raise MyFaultError(
                "Looks like {} spoken enough in {} just yet.{}".format(
                    ("you haven't" if msg.sender in users and len(users) == 1
                     else "nobody has" if len(users) == 0 else "{} hasn't".
                     format(users[0]) if len(users) == 1 else "they haven't"),
                    (channels[0] if len(channels) == 1
                     and channels[0] == msg.raw_channel else "that channel"
                     if len(channels) == 1 else "those channels"),
                    " ({} messages)".format(
                        len(cls.model.to_dict()['parsed_sentences']) if cls.
                        model is not None else 0)))
        # first: remove a ping at the beginning of the sentence
        pattern = r"^(\S+[:,]\s+)(.*)$"
        match = re.match(pattern, sentence)
        if match:
            sentence = match.group(2).strip()
        # second: modify any words that match the names of channel members
        sentence = gib.obfuscate(sentence,
                                 DB.get_channel_members(msg.raw_channel))
        # match any unmatched pairs
        sentence = gib.bracketify(sentence, (r"\"\b", "\""),
                                  (r"\b[.!?]*\"", "\""))
        sentence = gib.bracketify(sentence, (r"`\b", "`"), (r"\b[.!?]*`", "`"))
        sentence = gib.bracketify(sentence, (r"\(", "("), (r"\)", ")"))
        sentence = gib.bracketify(sentence, (r"\[", "["), (r"\}", "]"))
        sentence = gib.bracketify(sentence, (r"\{", "{"), (r"\}", "}"))

        cmd.command = cmd.command.lower()
        if "oo" in cmd.command:
            sentence = re.sub(r"[aeiou]", "oob", sentence)
        elif "o" in cmd.command:
            sentence = re.sub(r"[aeiou]", "ob", sentence)
        if cmd.command.startswith("b") and cmd.command.endswith("g"):
            sentence = sentence.upper()
        msg.reply(sentence)
Пример #21
0
 def autojoin(self, irc_c, msg):
     if "Password accepted" in msg.message and CONFIG.channels.db:
         for channel in DB.get_autojoins():
             irc_c.JOIN(channel)
             nsprint("Joining " + str(channel))
Пример #22
0
 def part_names(self, irc_c, msg):
     # make sure the names are always up to date
     for channel in DB.get_all_channels():
         defer.get_users(irc_c, channel)
Пример #23
0
    def command(cls, irc_c, msg, cmd):
        # Check that we are actually able to do this
        # (might have to move to end for defer check)
        if (defer.check(cmd, 'jarvis', 'Secretary_Helen')):
            return
        # Parse the command itself
        search.expandargs(cmd)
        # check to see if there are any arguments
        if len(cmd.args) == 1 and len(cmd.args['root']) == 0:
            raise CommandError("Must specify at least one search term")
        # fullname is deprecated for tars
        if 'fullname' in cmd:
            raise CommandError("TARS does not support fullname search - "
                               "wrap your search in quotemarks instead")
        # Set the return mode of the output
        selection = {
            'ignorepromoted': 'ignorepromoted' in cmd,
            'order': 'fuzzy',
            'limit': None,
            'offset': 0
        }
        # order, limit, offset
        if 'order' in cmd:
            if len(cmd['order']) != 1:
                raise CommandError("When using the order argument "
                                   "(--order/-o), exactly one order type must "
                                   "be specified")
            if cmd['order'][0] in ['recent', 'recommend', 'random', 'fuzzy', 'none']:
                if cmd['order'] == 'none':
                    selection['order'] = None
                else:
                    selection['order'] = cmd['order'][0]
            else:
                raise CommandError("Selection return order ('{}') must be "
                                   "one of: recent, recommend, random, "
                                   "fuzzy, none".format(cmd['order'][0]))
        if 'limit' in cmd:
            if len(cmd['limit']) != 1:
                raise CommandError("When using the limit argument "
                                   "(--limit/-l), exactly one limit must "
                                   "be specified")
            if isint(cmd['limit'][0]):
                if int(cmd['limit'][0]) > 0:
                    selection['limit'] = int(cmd['limit'][0])
                elif int(cmd['limit'][0]) == 0:
                    selection['limit'] = None
                else:
                    raise CommandError("When using the limit argument "
                                       "(--limit/-l), the limit must be at "
                                       "least 0")
            else:
                raise CommandError("When using the limit argument "
                                   "(--limit/-l), the limit must be an integer")
        if 'offset' in cmd:
            if len(cmd['offset']) != 1:
                raise CommandError("When using the offset argument "
                                   "(--offset/-f), exactly one offset must "
                                   "be specified")
            if isint(cmd['offset'][0]):
                if int(cmd['offset'][0]) >= 0:
                    selection['offset'] = int(cmd['offset'][0])
                else:
                    raise CommandError("When using the offset argument "
                                       "(--offset/-f), the offset must be at "
                                       "least 0")
            else:
                raise CommandError("When using the offset argument "
                                   "(--offset/-f), the offset must be an integer")
        if 'random' in cmd:
            selection['order'] = 'random'
            selection['limit'] = 1
        if 'recommend' in cmd:
            selection['order'] = 'recommend'
            selection['limit'] = 1
        if 'newest' in cmd:
            selection['order'] = 'recent'
            selection['limit'] = 1
        # What are we searching for?
        searches = []
        strings = []
        if len(cmd.args['root']) > 0:
            strings = cmd.args['root']
            searches.extend([{'term': s, 'type': None} for s in strings])
        # Add any regexes
        regexes = []
        if 'regex' in cmd:
            if len(cmd['regex']) == 0:
                raise CommandError(
                    "When using the regular expression filter "
                    "(--regex/-x), at least one regex must "
                    "be specified"
                )
            for regex in cmd['regex']:
                try:
                    re.compile(regex)
                except re.error as e:
                    raise CommandError(
                        "'{}' isn't a valid regular expression: {}"
                        .format(regex, e)
                    )
                regexes.append(regex)
                # don't append the compiled - SQL doesn't like that
            searches.extend([{'term': r, 'type': 'regex'} for r in regexes])
        # Set the tags
        tags = {'include': [], 'exclude': []}
        if 'tags' in cmd:
            if len(cmd['tags']) == 0:
                raise CommandError(
                    "When using the tag filter (--tag/-t), at "
                    "least one tag must be specified"
                )
            for tag in cmd['tags']:
                if tag[0] == "-":
                    tags['exclude'].append(tag[1:])
                    continue
                if tag[0] == "+":
                    tags['include'].append(tag[1:])
                    continue
                tags['include'].append(tag)
            searches.append({'term': tags, 'type': 'tags'})
        # Set the author
        authors = {'include': [], 'exclude': []}
        if 'author' in cmd:
            if len(cmd['author']) == 0:
                raise CommandError(
                    "When using the author filter "
                    "(--author/-a), at least one author must "
                    "be specified"
                )
            for author in cmd['author']:
                if author[0] == "-":
                    authors['exclude'].append(author[1:])
                    continue
                if author[0] == "+":
                    authors['include'].append(author[1:])
                    continue
                authors['include'].append(author)
            searches.append({'term': authors, 'type': 'author'})
        # Set the rating
        # Cases to account for: modifiers, range, combination
        ratings = MinMax()
        if 'rating' in cmd:
            if len(cmd['rating']) == 0:
                raise CommandError(
                    "When using the rating filter "
                    "(--rating/-r), at least one rating must "
                    "be specified"
                )
            for rating in cmd['rating']:
                if ".." in rating:
                    rating = rating.split("..")
                    if len(rating) > 2:
                        raise CommandError("Too many ratings in range")
                    try:
                        rating = [int(x) for x in rating]
                    except ValueError:
                        raise CommandError(
                            "Ratings in a range must be plain numbers"
                        )
                    try:
                        ratings >= min(rating)
                        ratings <= max(rating)
                    except MinMaxError as e:
                        raise CommandError(str(e).format("rating"))
                elif rating[0] in [">", "<", "="]:
                    pattern = r"^(?P<comp>[<>=]{1,2})(?P<value>[0-9]+)"
                    match = re.search(pattern, rating)
                    if match:
                        try:
                            rating = int(match.group('value'))
                        except ValueError:
                            raise CommandError("Invalid rating comparison")
                        comp = match.group('comp')
                        try:
                            if comp == ">=":
                                ratings >= rating
                            elif comp == "<=":
                                ratings <= rating
                            elif comp == "<":
                                ratings < rating
                            elif comp == ">":
                                ratings > rating
                            elif comp == "=":
                                ratings >= rating
                                ratings <= rating
                            else:
                                raise CommandError(
                                    "Unknown operator in rating comparison"
                                )
                        except MinMaxError as e:
                            raise CommandError(str(e).format("rating"))
                    else:
                        raise CommandError("Invalid rating comparison")
                else:
                    try:
                        rating = int(rating)
                    except ValueError:
                        raise CommandError(
                            "Rating must be a range, comparison, or number"
                        )
                    # Assume =, assign both
                    try:
                        ratings >= rating
                        ratings <= rating
                    except MinMaxError as e:
                        raise CommandError(str(e).format("rating"))
            searches.append({'term': ratings, 'type': 'rating'})
        # Set created date
        # Cases to handle: absolute, relative, range (which can be both)
        createds = MinMax()
        if 'created' in cmd:
            if len(cmd['created']) == 0:
                raise CommandError(
                    "When using the date of creation filter "
                    "(--created/-c), at least one date must "
                    "be specified"
                )
            created = cmd['created']
            # created is a list of date selectors - ranges, abs and rels
            # but ALL dates are ranges!
            created = [DateRange(c) for c in created]
            # created is now a list of DateRanges with min and max
            try:
                for key, selector in enumerate(created):
                    if selector.max is not None:
                        createds <= selector.max
                    if selector.min is not None:
                        createds >= selector.min
            except MinMaxError as e:
                raise CommandError(str(e).format("date"))
            searches.append({'term': createds, 'type': 'date'})
        # Set category
        categories = {'include': [], 'exclude': []}
        if 'category' in cmd:
            if len(cmd['category']) == 0:
                raise CommandError(
                    "When using the category filter "
                    "(--category/-y), at least one category "
                    "must be specified"
                )
            for category in cmd['category']:
                if category[0] == "-":
                    categories['exclude'].append(category[1:])
                    continue
                if category[0] == "+":
                    categories['include'].append(category[1:])
                    continue
                categories['include'].append(category)
            searches.append({'term': categories, 'type': 'category'})
        # Set parent page
        parents = None
        if 'parent' in cmd:
            if len(cmd['parent']) != 1:
                raise CommandError(
                    "When using the parent page filter "
                    "(--parent/-p), exactly one parent URL "
                    "must be specified"
                )
            parents = cmd['parent'][0]
            searches.append({'term': parents, 'type': 'parent'})
        # FINAL BIT - summarise commands
        if 'verbose' in cmd:
            verbose = "Searching for articles "
            if len(strings) > 0:
                verbose += (
                    "containing \"{}\"; ".format("\", \"".join(strings))
                )
            if len(regexes) > 0:
                verbose += "matching the regex /{}/; ".format(
                    "/ & /".join(regexes)
                )
            if parents is not None:
                verbose += ("whose parent page is '{}'; ".format(parents))
            if len(categories['include']) == 1:
                verbose += (
                    "in the category '" + categories['include'][0] + "'; "
                )
            elif len(categories['include']) > 1:
                verbose += (
                    "in the categories '" + "', '".join(categories) + "; "
                )
            if len(categories['exclude']) == 1:
                verbose += (
                    "not in the category '" + categories['exclude'][0] + "'; "
                )
            elif len(categories['exclude']) > 1:
                verbose += (
                    "not in the categories '" + "', '".join(categories) + "; "
                )
            if len(tags['include']) > 0:
                verbose += (
                    "with the tags '" + "', '".join(tags['include']) + "'; "
                )
            if len(tags['exclude']) > 0:
                verbose += (
                    "without the tags '" + "', '".join(tags['exclude']) + "'; "
                )
            if len(authors['include']) > 0:
                verbose += ("by " + " & ".join(authors['include']) + "; ")
            if len(authors['exclude']) > 0:
                verbose += ("not by " + " or ".join(authors['exclude']) + "; ")
            if ratings['max'] is not None and ratings['min'] is not None:
                if ratings['max'] == ratings['min']:
                    verbose += (
                        "with a rating of " + str(ratings['max']) + "; "
                    )
                else:
                    verbose += (
                        "with a rating between " + str(ratings['min']) +
                        " and " + str(ratings['max']) + "; "
                    )
            elif ratings['max'] is not None:
                verbose += (
                    "with a rating less than " + str(ratings['max'] + 1) + "; "
                )
            elif ratings['min'] is not None:
                verbose += (
                    "with a rating greater than " + str(ratings['min'] - 1) +
                    "; "
                )
            if createds['min'] is not None and createds['max'] is not None:
                verbose += (
                    "created between " + createds['min'].to_datetime_string() +
                    " and " + createds['max'].to_datetime_string() + "; "
                )
            elif createds['max'] is not None:
                verbose += (
                    "created before " + createds['max'].to_datetime_string() +
                    "; "
                )
            elif createds['min'] is not None:
                verbose += (
                    "created after " + createds['min'].to_datetime_string() +
                    "; "
                )
            if verbose.endswith("; "):
                verbose = verbose[:-2]
            msg.reply(verbose)
            pprint(searches)

        page_ids = DB.get_articles(searches)
        pages = [DB.get_article_info(p_id) for p_id in page_ids]
        pages = search.order(pages, search_term=strings, **selection)

        if len(pages) >= 50:
            msg.reply("{} results found - you're going to have to be more "
                      "specific!".format(len(pages)))
            return
        if len(pages) > 3:
            msg.reply("{} results (use ..sm to choose): {}".format(
                len(pages), showmore.parse_multiple_titles(pages)))
            DB.set_showmore_list(msg.raw_channel, [p['id'] for p in pages])
            return
        if len(pages) == 0:
            # check if there's no args other than --verbose
            if set(cmd.args).issubset({'root', 'verbose'}):
                # google only takes 10 args
                url = google_search(
                    '"' + '" "'.join(cmd.args['root'][:10]) + '"', num=1
                )[0]
                if url is None:
                    msg.reply("No matches found.")
                    return
                #pprint.pprint(url)
                if url['title'].endswith(" - SCP Foundation"):
                    url['title'] = url['title'][:-17]
                msg.reply(
                    "No matches found. Did you mean \x02{}\x0F? {}"
                    .format(url['title'], url['link'])
                )
            else:
                msg.reply("No matches found.")
            return
        for page in pages:
            msg.reply(gib.obfuscate(showmore.parse_title(page),
                                    DB.get_channel_members(msg.raw_channel)))
Пример #24
0
    def command(cls, irc_c, msg, cmd):
        """Record and broadcast messages"""
        if not defer.controller(cmd):
            raise CommandError("You're not authorised to do that")
        cmd.expandargs(["output o", "format f", "restrict-channel-name"])
        # get the action - start, stop or status
        if len(cmd.args['root']) == 0:
            raise CommandError("Usage: .record [start|stop|status|page] "
                               "[--output location] [--format format]")
        if len(cmd.args['root']) > 1:
            raise CommandError("Only one action can be taken at a time.")
        action = cmd.args['root'][0]
        if action == 'page':
            msg.reply(
                "Output page: http://topia.wikidot.com/tars:recording-output")
            return
        if action == 'status':
            if msg.raw_channel in cls.recording_channels():
                msg.reply("Currently recording in this channel. "
                          "Use `.record stop` to stop the recording.")
            else:
                msg.reply("Not currently recording in this channel.")
            if defer.controller(cmd) and msg.raw_channel is None:
                # if a controller asks in pm, show all channels
                msg.reply("Currently recording in: {}".format(", ".join(
                    [s['channel'] for s in cls.settings if s['recording']])))
            return
        elif action == 'start':
            if msg.raw_channel is None:
                raise CommandError("You can't record PMs.")
            if msg.raw_channel in cls.recording_channels():
                raise CommandError("Already recording in {}".format(
                    msg.raw_channel))
            else:
                msg.reply("Starting recording messages in {}".format(
                    msg.raw_channel))
                if 'restrict-channel-name' in cmd:
                    msg.reply("I will hide the channel name from the output.")
        elif action == 'stop':
            if msg.raw_channel not in cls.recording_channels():
                raise CommandError("Not recording in {}".format(
                    msg.raw_channel))
            else:
                msg.reply("Stopping recording in {}".format(msg.raw_channel))
                if 'restrict-channel-name' in cmd:
                    msg.reply("I will hide the channel name from the output.")
        else:
            raise CommandError("Action must be one of start, stop, status")
        # get arguments and save to vars
        output_location = None
        if 'output' in cmd:
            if cmd['output'][0] not in ['topia', 'here', 'both']:
                raise CommandError(
                    "Output location must be topia, here or both")
            output_location = cmd['output'][0]
        output_format = None
        if 'format' in cmd:
            if cmd['format'][0] not in ['json', 'txt', 'ftml']:
                raise CommandError("Format type must be json, txt or ftml")
            output_format = cmd['format'][0]

        # after everything else, set this channel as recording or not
        if action == 'start':
            # get the most recent message id in this channel
            start_id = DB.get_most_recent_message(msg.raw_channel)
            # add this channel to the settings list
            cls.settings.append({
                'channel': msg.raw_channel,
                'recording': True,
                'location': output_location,
                'format': output_format,
                'start_id': start_id,
                'hide': 'restrict-channel-name' in cmd
            })
        if action == 'stop':
            sett = [
                s for s in cls.settings if s['channel'] == msg.raw_channel
            ][0]
            end_id = DB.get_most_recent_message(msg.raw_channel)
            messages = DB.get_messages_between(msg.raw_channel,
                                               sett['start_id'], end_id)
            if sett['location'] in ['topia', None]:
                msg.reply("Uploading {} messages to topia...".format(
                    len(messages)))
                # get page content
                page = Topia.get_page({'page': "tars:recording-output"})
                content = page['content']
                content += "\r\n\r\n====\r\n\r\n"
                content += "+ Recording on {} from {}".format(
                    datetime.today().strftime('%Y-%m-%d'),
                    sett['channel'] if not sett['hide'] else "[REDACTED]")
                content += "\r\n\r\n"
                for message in messages:
                    if message['kind'] == 'PRIVMSG':
                        content += "||~ {} ||~ ##{}|{}## || {} ||".format(
                            (datetime.fromtimestamp(
                                message['timestamp']).strftime("%H:%M:%S")),
                            nickColor(message['sender'],
                                      True), message['sender'],
                            message['message'].replace("||", "@@||@@"))
                    elif message['kind'] == 'NICK':
                        content += "||~ {} ||||~ ##{}|{}## → ##{}|{}## ||".format(
                            (datetime.fromtimestamp(
                                message['timestamp']).strftime("%H:%M:%S")),
                            nickColor(message['sender'],
                                      True), message['sender'],
                            nickColor(message['message'],
                                      True), message['message'])
                    elif message['kind'] in ['JOIN', 'PART', 'QUIT']:
                        content += "||~ {} ||||~ {} ##{}|{}## {} ||".format(
                            (datetime.fromtimestamp(
                                message['timestamp']).strftime("%H:%M:%S")),
                            "→" if message['kind'] == 'JOIN' else "←",
                            nickColor(message['sender'],
                                      True), message['sender'],
                            "joined" if message['kind'] == 'JOIN' else "left")
                    else:
                        content += "|||||| Error code {} ||".format(
                            message['id'])
                    content += "\r\n"
                content += "\r\n"
                okchars = string.printable + "→←"
                content = "".join(filter(lambda x: x in okchars, content))
                # then format for wikidot
                Topia.save_page({
                    'page': "tars:recording-output",
                    'content': content,
                    'revision_comment': "New recording",
                    'notify_watchers': "true"
                })
                msg.reply(
                    "Done! http://topia.wikidot.com/tars:recording-output")
            else:
                raise MyFaultError("Unknown location")
            cls.settings.remove(sett)
Пример #25
0
    def command(cls, irc_c, msg, cmd):
        """Ping everyone in the channel"""
        cmd.expandargs([
            "message msg m",  # message to be PM'd
            "target t",  # channel op level target
            "channel c",  # channel to get names from
            "help h",
        ])

        # TODO remove this check in the argparse refactor
        if len(cmd.args['root']) > 0 or 'help' in cmd:
            raise CommandError("Usage: ..pingall [--target level] [--message "
                               "message]. If -m is not set, ping will happen "
                               "in this channel. If -m is set, message will "
                               "be sent to users in PM.")

        # TODO extend this to channel operator
        if not defer.controller(cmd):
            raise CommandError("You're not authorised to do that")

        cmd.expandargs(["channel c"])
        if 'channel' in cmd:
            if not defer.controller(cmd):
                raise MyFaultError("You're not authorised to extract the "
                                   "nicks of another channel")
            channel = cmd['channel'][0]
        else:
            channel = msg.raw_channel
        if 'target' in cmd:
            if len(cmd['target']) != 1:
                raise CommandError("Specify a target as a channel user mode "
                                   "symbol: one of +, %, @, &, ~")
            if not cmd['target'][0] in '+%@&~' and len(cmd['target'][0]) == 1:
                raise CommandError("When using the --target/-t argument, the "
                                   "target must be a channel user mode: one "
                                   "of +, %, @, &, ~")
        # Issue a fresh NAMES request and await the response
        defer.get_users(irc_c, channel)
        try:
            response = await_signal(irc_c, 'NAMES_RESPONSE', timeout=5.0)
            # returned data is the channel name
            assert response == channel
        except (TimeoutError, AssertionError):
            # response to success/failure is the same, so doesn't matter
            pass
        finally:
            members = DB.get_occupants(channel, True, levels=True)
        if 'target' in cmd:
            modes = '+%@&~'
            members = [
                nick for nick, mode in members if mode is not None
                and modes.find(mode) >= modes.find(cmd['target'][0])
            ]
        else:
            members = [nick for nick, mode in members]
        if 'message' in cmd:
            message = " ".join(cmd.args['message'])
            for member in members:
                irc_c.PRIVMSG(
                    member,
                    "{} (from {} in {})".format(" ".join(cmd.args['root']),
                                                msg.sender, msg.raw_channel))
            msg.reply("Message sent to selected users.")
        else:
            msg.reply("{}: ping!".format(", ".join(members)))
Пример #26
0
    def command(cls, irc_c, msg, cmd):
        # Recieves text in msg.message
        message = cmd.unping

        ##### ping matches #####

        if cmd.pinged:
            if any(x in message.lower() for x in [
                    "f**k you",
                    "piss off",
                    "f**k off",
            ]):
                msg.reply("{}: no u".format(msg.nick))
                return

        ##### ping-optional text matches #####

        if message.startswith("?? "):
            # CROM compatibility
            getattr(commands.COMMANDS, 'search').command(irc_c, msg, cmd)
        if message.lower() == "{}!".format(CONFIG.nick.lower()):
            msg.reply("{}!".format(msg.nick))
            return
        if strip(message.lower()) in [
                strip("{}{}".format(g, CONFIG.nick.lower())) for g in greets
        ]:
            if msg.sender == 'XilasCrowe':
                msg.reply("toast")
                return
            msg.reply(greet(msg.nick))
            return
        if CONFIG.nick == "TARS" and matches_any_of(message, [
                "what does tars stand for?",
                "is tars an acronym?",
        ]) and "TARS" in message.upper():
            msg.reply(acronym())
            return
        if CONFIG.nick == "TARS" and matches_any_of(message, [
                "is tars a bot?",
                "tars are you a bot?",
        ]) and "TARS" in message.upper():
            msg.reply("Yep.")
            return
        if CONFIG.nick == "TARS" and matches_any_of(message, [
                "is tars a person?",
                "tars are you a person?",
        ]) and "TARS" in message.upper():
            msg.reply("Nope. I'm a bot.")
            return
        if CONFIG.nick == "TARS" and matches_any_of(message, [
                "what is your iq",
        ]) and "TARS" in message.upper():
            msg.reply("big")
            return

        ##### regex matches #####

        # give url for reddit links
        match = re.search(r"(?:^|\s)/?r/(\S*)", message, re.IGNORECASE)
        if match:
            msg.reply("https://www.reddit.com/r/{}".format(match.group(1)))
            return
        # tell me about new acronyms
        match = re.search(
            r"(\s+|(?:\s*[{0}]+\s*))".join([
                r"([{{0}}]*)\b({})(\S*)\b([{{0}}]*)".format(l)
                for l in CONFIG['IRC']['nick']
            ]).format(re.escape(string.punctuation)), message,
            re.IGNORECASE | re.VERBOSE)
        if match:
            raw_acronym = "".join(match.groups())
            submatches = list(chunks(list(match.groups()), 5))
            # the match is made up of 5 repeating parts:
            # 0. punctation before word
            # 1. first letter of word
            # 2. rest of word
            # 3. punctuation after word
            # 4. stuff between this word and the next word
            # for the last word (submatch), however, 4 is not present
            submatches[-1].append("")
            with open(CONFIG['converse']['acronyms'], 'r+') as acro:
                existing_acronyms = [strip(line.rstrip('\n')) for line in acro]
            if strip(raw_acronym) not in existing_acronyms:
                for submatch in submatches:
                    submatch[1] = submatch[1].upper()
                bold_acronym = "".join([
                    "{}\x02{}\x0F{}{}{}".format(*submatch)
                    for submatch in submatches
                ])
                msg.reply(bold_acronym)
                if msg.raw_channel != CONFIG['channels']['home']:
                    defer.report(cmd, bold_acronym)
                with open(CONFIG['converse']['acronyms'], 'a') as acro:
                    acro.write(raw_acronym)
                    acro.write("\n")
                return

        ##### custom matches #####

        if (msg.sender == "Jazstar" and "slime" in msg.message
                and "XilasCrowe" in DB.get_channel_members(msg.raw_channel)):
            msg.reply("Oy xilas I heard you like slime!")
            return

        # after all attempts, must indicate failure if pinged
        if cmd.pinged:
            return 1
Пример #27
0
 def controller(cls, cmd):
     """Limit this command only to controllers."""
     return cmd.sender in DB.get_controllers()
Пример #28
0
 def command(cls, irc_c, msg, cmd):
     cmd.expandargs(["table tables t",
                     "user users u"])
     # No argument given - show the db structure
     if len(cmd.args) == 1:
         msg.reply("https://raw.githubusercontent.com/"
                   "rossjrw/tars/master/database.png")
         return
     # Table - print a list of tables, or a given table
     if 'table' in cmd:
         if len(cmd['table']) > 0:
             # print a specific table
             msg.reply("Printing contents of table {} to console."
                       .format(cmd['table'][0]))
             DB.print_one_table(cmd['table'][0])
         else:
             # print a list of all tables
             tables = DB.get_all_tables()
             msg.reply("Printed a list of tables to console. {} total."
                       .format(len(tables)))
             print(" ".join(tables))
     # Users - print a list of users, or from a given channel
     if 'user' in cmd:
         users = DB.get_all_users()
         if len(users) == 0:
             msg.reply("There are no users.")
         else:
             msg.reply("Printed a list of users to console. {} total."
                       .format(len(users)))
             print(" ".join([nickColor(u) for u in users]))
     if 'id' in cmd:
         # we want to find the id of something
         if len(cmd.args['root']) != 2:
             search = msg.sender
         else:
             search = cmd.args['root'][1]
         id, type = DB.get_generic_id(search)
         if id:
             if type == 'user' and search == msg.sender:
                 msg.reply("{}, your ID is {}.".format(msg.sender, id))
             elif search == "TARS":
                 msg.reply("My ID is {}.".format(id))
             else:
                 msg.reply("{}'s ID is {}.".format(search, id))
         else:
             if type == 'channel':
                 msg.reply("I don't know the channel '{}'."
                          .format(search))
             else:
                 msg.reply("I don't know anything called '{}'."
                           .format(search))
     if 'alias' in cmd:
         search = cmd.args['root'][1] if len(cmd.args['root']) > 1 \
                                      else msg.sender
         aliases = DB.get_aliases(search)
         # should be None or a list of lists
         if aliases is None:
             msg.reply("I don't know anyone with the alias '{}'."
                       .format(search))
         else:
             msg.reply("I know {} users with the alias '{}'."
                       .format(len(aliases), search))
             for i,group in enumerate(aliases):
                 msg.reply("\x02{}.\x0F {}"
                           .format(i+1, ", ".join(group)))
     if 'occ' in cmd:
         if len(cmd.args['root']) < 2:
             raise CommandError("Specify a channel to get the occupants of")
         msg.reply("Printing occupants of {} to console"
                   .format(cmd.args['root'][1]))
         users = DB.get_occupants(cmd.args['root'][1], True)
         if isinstance(users[0], int):
             pprint(users)
         else:
             pprint([nickColor(user) for user in users])
     if 'sql' in cmd:
         if not defer.controller(cmd):
             raise CommandError("I'm afriad I can't let you do that.")
         try:
             DB.print_selection(" ".join(cmd['sql']), 'str' in cmd)
             msg.reply("Printing that selection to console")
         except:
             msg.reply("There was a problem with the selection")
             raise