def __info(self, author, subject, text): try: limit = 10 #first find a limit if it exists match = self.limit_match.search(subject) if match: limit = int(match.group(1)) #we must figure out the case if self.list_command.search(subject): return self.__info_list(author, subject, text) elif self.channel_command.search(subject): return self.__info_channels(author, subject, text, limit) elif self.user_command.search(subject): return self.__info_user(author, subject, text, limit) else: return Actions.send_message(self.praw, author, u'Message text not recognized', u'Message w/ \n' u'subject: {}\n'.format(subject) + u'and body: {}\n'.format(text) + u'not recognized, please consult documentation or help.') except Exception as e: logging.exception(e) Actions.send_message(self.praw, author, u'Re: {}'.format(subject), u'An error occured processing the following text, please file a bug report with' u' /u/arghdos: \n{}'.format(text))
def update_mods(self, author=None): """ Update the internal mod-list (who can execute queries) :param author: if specified, the bot will respond to this user to let them know success/failure :return: None """ try: mlist = [mod.name for mod in Actions.get_mods(self.praw, self.sub)] if mlist is None or not len(mlist): return False # only update if it's valid self.mod_list = mlist self.last_mod_update = datetime.datetime.now() if author is not None: Actions.send_message(self.praw, author, u"RE: Modlist update", u"Success!") return True except Exception, e: if author is not None: Actions.send_message(self.praw, author, u"RE: Modlist update", u"Error encountered, please try again later.") logging.error(u"Could not update moderator list!") self.log_error() if __debug__: logging.exception(e) return False
def __info_user(self, author, subject, text, limit): # check that we have text lines = [l.strip() for l in self.line_splitter.split(text) if l is not None and len(l.strip())] if not len(lines): Actions.send_message(self.praw, author, u"RE: info user", u"No users specified in text: \n{}".format(text)) return False invalid_users = [] valid_users = [] #now go through the lines and make sure they're all usernames for line in lines: match = self.user_name_match.search(line) if not match: invalid_users.append(line) else: valid_users.append(match.group(1)) if not len(valid_users): if len(invalid_users): message = u'The following were not recognized as usernames: \n{}'.format(u', '.join(invalid_users)) else: message = u"No users specified in text: ".format(text) Actions.send_message(self.praw, author, u"RE: info user", message) return False valid_users = list(set(valid_users)) return_string = self.__create_table((u'Date', u'Link', u'Submitter', u'Channel', u'Domain', u'Deleted', u'Exception')) #with our list of usernames, query DB for submissions with DataBaseWrapper(self.owner.database_file, False) as db: for user in valid_users: #val is (short_url, channel_id, domain, date_added, processed, exception val = db.get_reddit(submitter=user, return_channel_id=True, return_domain=True, return_processed=True, return_exception=True, sort_by_new=True, limit=limit, return_dateadded=True) if val is not None and len(val): for submission in val: return_string += self.__table_entry(( str(submission[3]), u'http://redd.it/{}'.format(submission[0][submission[0].index('t3_')+ 3:]), user, submission[1], submission[2], u'True' if submission[4] == 1 else u'False', u'True' if submission[5] == 0 and submission[4] == 1 else u'False')) else: return_string += self.__table_entry((u'Not Found', user, u'N/A', u'N/A', u'N/A', u'N/A')) if invalid_users: return_string += u'\n\n' return_string += u"The following were not recognized as users:\n" return_string += u'\n'.join(invalid_users) return_string += u'\n\n' return_string += u'Note: Deletions and Exceptions are processed every {:.1} day(s),'.format( self.policy.Historial_Scan_Period / (24.0 * 60.0 * 60.0)) + \ u' and thus may not be updated within that time window.' return Actions.send_message(self.praw, author, u'Re: User Info query', return_string)
def test_send_message(reddit, credentials): if a.send_message(reddit, credentials['ALTUSER'], "test", "testmessage"): print "Test Message Send: Passed" return True else: print "Test Message Send: Failed" return False
def process_message(self, message): """ Handles the processing of unread messages :param message: the message to process """ result = None # valid author check if message.author and any(name == message.author.name for name in self.mod_list) and not self.is_cached(message.id): subject = message.subject text = message.body # check that it matches one of the basic commands matches = [bc for bc in self.base_commands if bc.search(subject)] if len(matches) == 1: # take care of add /removes if matches[0] == self.add_command: self.__add_remove(message.author.name, subject, text, True) elif matches[0] == self.remove_command: self.__add_remove(message.author.name, subject, text, False) # update mods elif matches[0] == self.update_command: self.update_mods(message.author.name) # print query elif matches[0] == self.info_command: result = self.__info(message.author.name, subject, text) # help query elif matches[0] == self.help_command: Actions.send_message(self.praw, message.author.name, u"RE:{}".format(message.subject), self.doc_string) if len(matches) != 1: Actions.send_message(self.praw, message.author.name, u"RE:{}".format(message.subject), u"Sorry, I did not recognize your query. \n".format(text) + self.short_doc_string) self.message_cache.append(message.id) # don't need to see this again message.mark_read() return result
def __add_remove(self, author, subject, text, add): """ add/remove a list of entries from the black/whitelist :param author: the mod who initiated this query :param subject: the subject line of the message :param text: the text of the message :param add: a boolean indicating whether this is an addition or removal """ # get black/whitelist blacklist = None result = self.blist_command.search(subject) if result: blacklist = True result = self.wlist_command.search(subject) if result: blacklist = False if blacklist is None: Actions.send_message(self.praw, author, u"RE: Black/whitelist add/removal", \ u"Could not determine blacklist/whitelist from subject line \n" \ u"Subject: {}".format(subject)) return False force_flag = self.force.search(subject) is not None lines = [l.strip() for l in self.line_splitter.split(text) if l and len(l.strip())] matches = [self.quote_match.match(l) for l in lines] matches = [m for m in matches if m] if len(matches) and len(matches) == len(lines) - 1: url_list = False elif not len(matches) and any(self.url_regex.match(l) for l in lines): url_list = True else: Actions.send_message(self.praw, author, u"RE: {}list {}".format(u"black" if blacklist else u"white", \ u"addition" if add else u"removal"), \ u"Could not determine format of request. For an id list, the first line must " \ u"be a domain and all subsequent lines must be followed by comma separated ids in" \ u" quotes. For a url list, there must be no comma separated ids.") return False if add and not url_list: Actions.send_message(self.praw, author, u"RE: {}list {}".format(u"black" if blacklist else u"white", \ u"addition" if add else u"removal"), \ u"Addition of {}list entries by id is no longer supported. Please add by URL instead" .format(u"black" if blacklist else u"white")) return False blist = None if not url_list: # test the first line to get appropriate blacklist for b in self.blacklists: if b.check_domain(lines[0]): # store b blist = b break # now check that we have a blacklist and url_list defined if blist is None and not url_list: Actions.send_message(self.praw, author, u"RE: {}list {}".format(u"black" if blacklist else u"white", \ u"addition" if add else u"removal"), u"Could not determine valid domain from: \n{}".format(lines[0])) return False # check that if we do not have a url list, we indeed have a domain and other entries to add if not url_list and len(lines) == 1: Actions.send_message(self.praw, author, u"RE: {}list {}".format(u"black" if blacklist else u"white", \ u"addition" if add else u"removal"), u"Invalid format detected, must have at least one channel id to {}\ from {}list for domain {}".format(u"add" if add else u"remove", u"black" if blacklist else u"white", \ self.lines[0])) return False entries = lines if url_list else lines[1:] invalid_ids = [] invalid_urls = [] valid_ids = [] if not url_list: real_entries = [] # if we have an id list, we have to see if they're comma separated for entry in entries: val = self.quote_splitter(entry, force=force_flag) if isinstance(val, tuple): if force_flag: val = val[0] else: body = u"Warning: potential error(s) in ID list detected, **No action has been taken**. \n" \ u"Unescaped quotes or slashes (or simply malformed input) " \ u"has been found in the following entries: \n\n" body += u" \n".join(val[1]) body += u" \n \nIf these entries have been correctly parsed " \ u"(note: any escaped characters have not been processed), " \ u"please resubmit your last query with the --force flag in the subject line." body += u" \n \n**Parsed entries**: \n" body += u" \n".join(val[0]) Actions.send_message(self.praw, author, u"RE: {}list {}".format( u"black" if blacklist else u"white", u"addition" if add else u"removal"), body) return False if val: real_entries.extend([self.__unescape(v) for v in val]) else: Actions.send_message(self.praw, author, u"RE: {}list {}".format(u"black" if blacklist else u"white" \ ), u"Cannot parse quoted identifiers: \n{}".format(entry)) # copy back entries = real_entries[:] else: real_entries = [] for entry in entries: if self.url_regex.match(entry):# and Actions.resolve_url(entry): real_entries.append(entry) else: invalid_urls.append(entry) entries = real_entries[:] if url_list: found = [False for u in entries] for blist in self.blacklists: this_list = [] for i, url in enumerate(entries): if blist.check_domain(url): found[i] = True this_list.append(url) if not len(this_list): continue if blacklist: if add: bad_urls, bad_ids, good_ids = blist.add_blacklist_urls(this_list, author) else: bad_urls, bad_ids, good_ids = blist.remove_blacklist_urls(this_list, author) else: if add: bad_urls, bad_ids, good_ids = blist.add_whitelist_urls(this_list, author) else: bad_urls, bad_ids, good_ids = blist.remove_whitelist_urls(this_list, author) invalid_urls += bad_urls invalid_ids += [(b, blist.domains[0]) for b in bad_ids] valid_ids += [(g, blist.domains[0]) for g in good_ids] invalid_urls += [url for i, url in enumerate(entries) if not found[i]] else: if blacklist: if add: #no longer accepted invalid_ids += entries #invalid += blist.add_blacklist(entries) else: invalid_ids += blist.add_blacklist(entries) else: if add: invalid_ids += blist.add_whitelist(entries) else: invalid_ids += blist.add_whitelist(entries) valid_ids = [(v, lines[0]) for v in entries if not v in invalid_ids] invalid_str = u"" if invalid_ids is not None and len(invalid_ids): if url_list: invalid_str += u"Failed to add the following ids: \n" invalid_str += u" \n".join([u"id = {},domain={}".format(inv[0], inv[1]) for inv in invalid_ids]) else: invalid_str += u"Failed to add the following ids: \n" invalid_str += u" \n".join([u"id = {}, domain={}".format(inv[0], lines[0]) for inv in invalid_ids]) if invalid_urls is not None and len(invalid_urls): invalid_str += u"Invalid urls detected: \n" invalid_str += u" \n".join(invalid_urls) retstr = u"" if valid_ids is not None and len(valid_ids): retstr = u"The following channels were successfully {} the {}list \n" \ u"{}".format(u"added to" if add else u"removed from the", u"black" \ if blacklist else u"white", u" \n".join([u"id = {}, domain={}".format(v[0], v[1]) for v in valid_ids])) if len(invalid_str): if len(retstr): retstr += u" \n" retstr += invalid_str return Actions.send_message(self.praw, author, u"RE: {}list {}".format(u"black" if blacklist else u"white", \ u"addition" if add else u"removal"), retstr)
def __info_channels(self, author, subject, text, limit): #we want to find #a table of: # submission, user, channel, domain, strike #check that we have text lines = [l.strip() for l in self.line_splitter.split(text) if l is not None and len(l.strip())] if not len(lines): Actions.send_message(self.praw, author, u"RE: info list", u"No valid channels specified in text: \n{}".format(text)) return False found_channels = [] valid_urls = [] invalid_urls = [] return_string = u"" for blacklist in self.blacklists: my_lines = [line for line in lines if blacklist.check_domain(line)] overlap = [x for x in my_lines if x in valid_urls] #if it's already matched, it's bad if overlap: invalid_urls.extend(overlap) valid_urls = [v for v in valid_urls if v not in overlap] my_lines = [line for line in my_lines if not line in overlap] if not len(my_lines): continue #if we have data, get the channel ids my_channel_info = [blacklist.data.channel_id(url=url) for url in my_lines] my_channel_ids = [] for i, info in enumerate(my_channel_info): if info is not None: if not (info[0], blacklist.domains[0]) in found_channels: found_channels.append((info[0], blacklist.domains[0])) my_channel_ids.append(info[0]) else: valid_urls.remove(my_lines[i]) invalid_urls.append(my_lines[i]) return_string += self.__create_table((u'Date', u'Link' , u'Submitter',u'Channel', u'Domain', u'Deleted', u'Exception')) #with our list of channel ids, query DB for submissions if my_channel_ids: with DataBaseWrapper(self.owner.database_file, False) as db: for id in my_channel_ids: #val is (short_url, date, processed, submitter, exception val = db.get_reddit(channel_id=id, domain=blacklist.domains[0], return_domain=False, return_channel_id=False, return_processed=True, return_submitter=True, return_exception=True, sort_by_new=True, limit=limit, return_dateadded=True) if val is not None and len(val): for submission in val: return_string += self.__table_entry(( str(submission[1]), u'http://redd.it/{}'.format(submission[0][submission[0].index('t3_')+ 3:]), submission[3], id, blacklist.domains[0], u'True' if submission[2] == 1 else u'False', u'True' if submission[4] == 0 and submission[2] == 1 else u'False')) else: return_string += self.__table_entry((u'Not Found', u'Not Found', id, blacklist.domains[0], u'N/A', u'N/A')) invalid_urls.extend([x for x in my_lines if x not in valid_urls]) if invalid_urls: return_string += u'\n\n' return_string += u"Channel data for the following urls could not be obtained:\n" return_string += u'\n'.join(invalid_urls) return_string += u'\n\n' return_string += u'Note: Deletions and Exceptions are processed every {:.1} day(s),'.format( self.policy.Historial_Scan_Period / (24.0 * 60.0 * 60.0)) + \ u' and thus may not be updated within that time window.' return Actions.send_message(self.praw, author, u'Re: Channel Info query', return_string)
def __info_list(self, author, subject, text): # check that we have text lines = [l.strip() for l in self.line_splitter.split(text) if l is not None and len(l.strip())] if not len(lines): Actions.send_message(self.praw, author, u"RE: info list", u"No channel info specified in text: \n{}".format(text)) return False blist = [] myfilter = [] return_subject = u'Re: Info list' return_domains = [] return_filters = [] urls = [] for line in lines: domain_match = re.search(r'^domain:\s*([^\n]+)$', line) if domain_match: potential_domain = domain_match.group(1).strip() # get domain found = False for b in self.blacklists: if b.check_domain(potential_domain): return_domains.append(potential_domain) blist.append(b) found = True break if not found: Actions.send_message(self.praw, author, u"RE: info list", u"{} not a valid domain."\ .format(potential_domain)) return False continue filter_match = re.search(r'^filter:\s*([^\n]+)$', line) if filter_match: the_filter = filter_match.group(1).strip() myfilter.append(the_filter) return_filters.append(the_filter) continue Actions.send_message(self.praw, author, u"RE: info list", u"Text not recognized: \n{}."\ .format(line)) return False if return_domains: return_subject += u' w/ domains: {}'.format(u', '.join(return_domains)) if return_filters: return_subject += u' w/ filters: {}'.format(u', '.join(return_filters)) #if no domain, check all if not blist: blist = self.blacklists results = [] for blacklist in blist: if myfilter: for filter in myfilter: b_chann = blacklist.get_blacklisted_channels(filter) w_chann = blacklist.get_whitelisted_channels(filter) if b_chann or w_chann: results.append(u'Channel results for domain {} w/ filter {}:'\ .format(blacklist.domains[0], filter)) if b_chann: results.append(u'Blacklisted channels:') results.extend([channel[0] for channel in b_chann]) if w_chann: results.append(u'Whitelisted channels:') results.extend([channel[0] for channel in w_chann]) else: b_chann = blacklist.get_blacklisted_channels('') w_chann = blacklist.get_whitelisted_channels('') if b_chann or w_chann: results.append(u'Channel results for domain {}:'\ .format(blacklist.domains[0])) if b_chann: results.append(u'Blacklisted channels:') results.extend([channel[0] for channel in b_chann]) if w_chann: results.append(u'Whitelisted channels:') results.extend([channel[0] for channel in w_chann]) if len(results): out_str = u" \n".join(results) else: out_str = u"No matches found!" Actions.send_message(self.praw, author, return_subject, out_str) return True