def process_override(reply, config): """ This process is for moderators of ToR to force u/transcribersofreddit to mark a post as complete and award flair when the bot refutes a `done` claim. The comment containing "!override" must be in response to the bot's comment saying that it cannot find the transcript. :param reply: the comment reply object from the moderator. :param config: the global config object. :return: None. """ # don't remove this check, it's not covered like other admin_commands # because it's used in reply to people, not as a PM if not from_moderator(reply, config): reply.reply(_(random.choice(config.no_gifs))) logging.info(f'{reply.author.name} just tried to override. Lolno.') return # okay, so the parent of the reply should be the bot's comment # saying it can't find it. In that case, we need the parent's # parent. That should be the comment with the `done` call in it. reply_parent = config.r.comment(id=clean_id(reply.parent_id)) parents_parent = config.r.comment(id=clean_id(reply_parent.parent_id)) if 'done' in parents_parent.body.lower(): logging.info( f'Starting validation override for post {parents_parent.fullname}, ' f'approved by {reply.author.name}') process_done(parents_parent, config, override=True)
def process_override(reply, r, tor, config): """ This process is for moderators of ToR to force u/transcribersofreddit to mark a post as complete and award flair when the bot refutes a `done` claim. The comment containing "!override" must be in response to the bot's comment saying that it cannot find the transcript. :param reply: the comment reply object from the moderator. :param r: the active Reddit instance. :param tor: the TranscribersOfReddit subreddit object. :param config: the global config object. :return: None. """ # first we verify that this comment comes from a moderator and that # we can work on it. if not from_moderator(reply, config): reply.reply(_(random.choice(config.no_gifs))) logging.info('{} just tried to override. Lolno.'.format( reply.author.name)) return # okay, so the parent of the reply should be the bot's comment # saying it can't find it. In that case, we need the parent's # parent. That should be the comment with the `done` call in it. reply_parent = r.comment(id=clean_id(reply.parent_id)) parents_parent = r.comment(id=clean_id(reply_parent.parent_id)) if 'done' in parents_parent.body.lower(): logging.info('Starting validation override for post {}' ', approved by {}'.format(parents_parent.fullname, reply.author.name)) process_done(parents_parent, r, tor, config, override=True)
def process_reply(reply, config): # noinspection PyUnresolvedReferences try: if any([regex.search(reply.body) for regex in MOD_SUPPORT_PHRASES]): process_mod_intervention(reply, config) reply.mark_read() return r_body = reply.body.lower() # cache that thing if 'i accept' in r_body: process_coc(reply, config) reply.mark_read() return if 'claim' in r_body: process_claim(reply, config) reply.mark_read() return if ('done' in r_body or 'deno' in r_body # we <3 u/Lornescri ): alt_text = True if 'done' not in r_body else False process_done(reply, config, alt_text_trigger=alt_text) reply.mark_read() return if 'thank' in r_body: # trigger on "thanks" and "thank you" process_thanks(reply, config) reply.mark_read() return if '!override' in r_body: process_override(reply, config) reply.mark_read() return # If we made it this far, it's something we can't process automatically forward_to_slack(reply, config) reply.mark_read() # no spamming the slack channel :) except (RedditClientException, AttributeError) as e: logging.warning(e) logging.warning( f"Unable to process comment {reply.submission.shortlink} " f"by {reply.author}") # the only way we should hit this is if somebody comments and then # deletes their comment before the bot finished processing. It's # uncommon, but common enough that this is necessary. pass
def process_reply(reply, config): # noinspection PyUnresolvedReferences try: if any([regex.search(reply.body) for regex in MOD_SUPPORT_PHRASES]): process_mod_intervention(reply, config) reply.mark_read() return if 'i accept' in reply.body.lower(): process_coc(reply, config) reply.mark_read() return if 'claim' in reply.body.lower(): process_claim(reply, config) reply.mark_read() return if 'done' in reply.body.lower(): process_done(reply, config) reply.mark_read() return if 'thank' in reply.body.lower(): # trigger on "thanks" and "thank you" process_thanks(reply, config) reply.mark_read() return if '!override' in reply.body.lower(): process_override(reply, config) reply.mark_read() return # If we made it this far, it's something we can't process automatically forward_to_slack(reply, config) reply.mark_read() # no spamming the slack channel :) except (AttributeError, RedditClientException): # the only way we should hit this is if somebody comments and then # deletes their comment before the bot finished processing. It's # uncommon, but common enough that this is necessary. pass
def process_override(user: Redditor, blossom_submission: Dict, parent_id: str, cfg): """ This process is for moderators of ToR to force u/transcribersofreddit to mark a post as complete and award flair when the bot refutes a `done` claim. The comment containing "!override" must be in response to the bot's comment saying that it cannot find the transcript. :param user: The user requesting the override :param blossom_submission: The relevant Submission of Blossom :param parent_id: The ID of the parent comment of the override :param cfg: the global config object. """ # TODO: turn this into a decorator # don't remove this check, it's not covered like other admin_commands # because it's used in reply to people, not as a PM if not is_moderator(user.name, cfg): logging.info(f"{user.name} just tried to override. Lolno.") return _(random.choice(cfg.no_gifs)), None # okay, so the parent of the reply should be the bot's comment # saying it can't find it. In that case, we need the parent's # parent. That should be the comment with the `done` call in it. reply_parent = cfg.r.comment(id=clean_id(parent_id)) grandparent = cfg.r.comment(id=clean_id(reply_parent.parent_id)) if grandparent.body.lower() in (CLAIM_PHRASES + DONE_PHRASES): logging.info( f"Starting validation override for post {grandparent.fullname}, " f"approved by {user.name}") return process_done(grandparent.author, blossom_submission, grandparent, cfg, override=True) return "Cannot process - no target comment found.", None
blossom_submission = get_blossom_submission(submission, cfg) if "i accept" in r_body: message, flair = process_coc(username, reply.context, blossom_submission, cfg) elif check_for_phrase(r_body, UNCLAIM_PHRASES): message, flair = process_unclaim(username, blossom_submission, submission, cfg) elif check_for_phrase(r_body, CLAIM_PHRASES): message, flair = process_claim(username, blossom_submission, cfg) elif check_for_phrase(r_body, DONE_PHRASES): alt_text = "done" not in r_body message, flair = process_done( reply.author, blossom_submission, reply, cfg, alt_text_trigger=alt_text, ) elif "!override" in r_body: message, flair = process_override(reply.author, blossom_submission, reply.parent_id, cfg) elif "!debug" in r_body: message, flair = process_debug(reply.author, blossom_submission, cfg) else: # If we made it this far, it's something we can't process automatically forward_to_slack(reply, cfg) if message: send_reddit_reply(reply, message)
def check_inbox(config): """ Goes through all the unread messages in the inbox. It has two loops within this section, each one dealing with a different type of mail. Also deliberately leaves mail which does not fit into either category so that it can be read manually at a later point. The first loop handles username mentions. The second loop sorts out and handles comments that include 'claim' and 'done'. :return: None. """ # Sort inbox, then act on it mentions = [] replies = [] # grab all of our messages and filter for item in config.r.inbox.unread(limit=None): if item.author.name == 'transcribot': item.mark_read() continue if item.subject == 'username mention': mentions.append(item) item.mark_read() if item.subject == 'comment reply': replies.append(item) # we don't mark as read here so that any comments that are not # ones we're looking for will eventually get emailed to me as # things I need to look at if 'reload' in item.subject.lower(): item.mark_read() reload_config(item, config) item.reply('Config reloaded!') continue if 'update' in item.subject.lower(): item.mark_read() update_and_restart(item, config) # there's no reason to do anything else here because the process # will terminate and respawn # ARE YOU ALIVE?! if item.subject.lower() == 'ping': item.mark_read() item.reply('Pong!') # sort them and create posts where necessary for mention in mentions: logging.info('Received mention! ID {}'.format(mention)) if not is_valid(mention.parent_id, config): # Do our check here to make sure we can actually work on this one and # that we haven't already posted about it. We use the full ID here # instead of the cleaned one, just in case. logging.info(id_already_handled_in_db.format(mention.parent_id)) continue # noinspection PyUnresolvedReferences try: process_mention(mention, config) except (AttributeError, praw.exceptions.ClientException): # apparently this crashes with an AttributeError if someone calls # the bot and immediately deletes their comment. This should fix # that. continue # comment replies for reply in replies: # noinspection PyUnresolvedReferences try: if 'i accept' in reply.body.lower(): process_coc(reply, config) reply.mark_read() return if 'claim' in reply.body.lower(): process_claim(reply, config) reply.mark_read() return if 'done' in reply.body.lower(): process_done(reply, config) reply.mark_read() return if '!override' in reply.body.lower(): process_override(reply, config) reply.mark_read() return except (AttributeError, praw.exceptions.ClientException): # the only way we should hit this is if somebody comments and then # deletes their comment before the bot finished processing. It's # uncommon, but common enough that this is necessary. continue