def getThreadsFromTitleLine(line, subreddit, r): """Gets the threads from the title line, returns them in the order NOMINATIONS, VOTE, PROMOTIONS if any of them were not found, None is returned instead """ return (RedditUtils.findThread(line, "NOMINATE", subreddit, r), RedditUtils.findThread( line, "VOTE", subreddit, r), RedditUtils.findThread(line, "PROMOTIONS", subreddit, r))
#!/usr/bin/python import RedditUtils import time username = '******' password = '******' start = time.time() r = RedditUtils.RedditUtils(username, password) r.getThreads() r.updateSubscriberCount() print("Exec time: " + str(time.time() - start))
def step3(self, state, input, subreddit): """PotW Step 3 - Re-interpret promotions.""" r = self.r while True: message = "" removeIdxs = [] # remove those only after doing the other changes so that the indices dont get mixed up for line in input: if not line.strip(): continue parts = line.split(")") num = 0 try: num = int(parts[0]) except: message += "* Couldn't understand entry: " + line + "\n" continue num-=1 # CONVERT TO INTERNAL REPRESENTATION if num >= len(state["finalWinnerInfo"]) or num < 0: message += "* The entry id has to be one of the numbers in the last message in: " + line + "\n" continue if len(parts) < 2: message += "* The entry here lacks a command verb: " + line + "\n" continue # get the verb cmd = parts[1].lower().strip() if cmd.startswith("remove"): removeIdxs.append(num) elif cmd.startswith("change "): rankNameLower = cmd[len("change "):].lower().strip() newRank = RankUtils.getRankByName(rankNameLower) if newRank is None: message += "Couldn't find the rank " + \ rankNameLower + " in [{}]".format(num) continue state["finalWinnerInfo"][num]["promoteTo"] = newRank if state["finalWinnerInfo"][num]["promoteTo"] != state["finalWinnerInfo"][num]["currentRank"]: state["finalWinnerInfo"][num]["willBePromoted"] = True else: state["finalWinnerInfo"][num]["willBePromoted"] = False logging.info("Changed to newRank.") else: message += "* Warning: Did not understand the command '{}'".format(cmd) removeIdxs = sorted(removeIdxs, reverse=True) for idx in removeIdxs: del state["finalWinnerInfo"][idx] logging.info("Removed {}".format(idx)) message += "\n\n" message += formatFinalWinnerInfo(state["finalWinnerInfo"]) message += "\n\n" message += InfoMessages.promotionsCorrected self.messageHandler.dispatchOutput(message) message = "" inpt = self.waitForNewInstructions() if inpt is not None and len(inpt) > 0 and inpt[0].lower().startswith("okay"): break input = inpt message="Notes (If there's anything in this section, please heed the message):" # get the nominations nominationsThread = state["nominationsThread"] nominations = [] for comment in nominationsThread.comments: if not comment.is_root: message += "* Ignored [comment]({}) because it was not a root comment in the nominations thread.\n\n".format(comment.permalink) continue if comment.author is None or comment.author.name is None: message += "* Ignored deleted [comment]({}) in the nominations thread.\n\n".format(comment.permalink) continue if comment.banned_by is not None: message += "* Ignored removed [comment]({}) in the nominations thread.\n\n".format(comment.permalink) continue winnerInfo = RedditUtils.findFirstLinkedObject(comment.body, subreddit, r) if winnerInfo is None: message += "* Couldn't find the thread/comment referenced by the [nomination entry]({}). **Please handle this manually LATER. DON'T Forget.\n\n** ".format( comment.permalink) continue if winnerInfo[2].author is None: message += "* The comment linked to by this [nomination entry]({}) appears to have been deleted. **Please handle this manually LATER. DON'T Forget.\n\n** ".format( comment.permalink) continue # get the user from the nomination comment username = "" match = re.search(r'\/u\/(.*?)\s', comment.body, re.IGNORECASE) if match is None: message += ("* The user in [this]({}) nomination comment didn't specify a username. Better double-check" + " that they at least got the permalink right and didn't accidentially link the thread. " + "If they did mess up, remove the entry from the bots nominations in the next step and add it to the vote thread after the bot has finished. **DON'T Forget**\n\n** ").format(comment.permalink) username = winnerInfo[2].author.name else: username = match.group(1).strip() # ensure that they are both the same - reddit usernames are case # insensitive if username.lower() != winnerInfo[2].author.name.lower(): message += "This [nomination entry]{}'s link doesn't match the user they nominated. **Please handle this manually LATER (after the bot has finished). DON'T Forget.\n\n** ".format(comment.permalink) continue nominations.append({"name": winnerInfo[2].author.name, "reason": winnerInfo[ 0], "permalink": winnerInfo[1]}) state["nominations"] = nominations state["messageCarryover"] = message return state
def step2(self, state, input, subreddit): """Post of the Week Step 2 - Calculate Promotions""" if len(input) < 1 or len(input) > 2: state["error"] = "Your comment has a line number other than two or one. Please keep to the aforementioned syntax." return state if not input[0].lower().startswith("potw "): state["error"] = "Your comments first line must start with 'POTW '" return state potwIndices = input[0][len("POTW "):].split(" ") ecIndices = [] if len(input) == 2: if not input[1].lower().startswith("ec "): state["error"] = "Your comments second line must start with 'EC '" return state ecIndices = input[1][len("EC "):].split(" ") # important: user-facing indices are in [1,n+1], move them back to [0,n], also convert them to numbers try: potwIndices = [int(x)-1 for x in potwIndices] ecIndices = [int(x)-1 for x in ecIndices] # remove duplicates potwIndices = list(set(potwIndices)) ecIndices = list(set(ecIndices)) if any([x < 0 or x >= len(state["voteEntries"]) for x in potwIndices]): raise ValueError("") if any([x < 0 or x >= len(state["voteEntries"]) for x in ecIndices]): raise ValueError("") except: return {"error": "Some of the indices you provided were not numbers, or not within the required range."} if len(set(ecIndices) ^ set(potwIndices)) != len(ecIndices) + len(potwIndices): return {"error": "No post can win BOTH Exemplary Contribution and Post of the Week."} # Assemble the winners and candidates for the CPO position cpoCandidates = [] # list of (user, current_flair_css) winnersInfo = [] for idx,voteEntry in enumerate(state["voteEntries"]): # Do not check for winning-state in a misguided attempt at optimization here, need to go through it all to be # able to see if anyone's rank entitles them to a CPO promotion. winnerInfo = RedditUtils.findFirstLinkedObject(voteEntry.body, subreddit, self.r) if winnerInfo is None: state["error"] = "Couldn't find the thread/comment referenced by the vote entry {}\n\n".format(idx) return state linkText, linkURL, contributionObject = winnerInfo # get the user from the vote comment match = re.search(r'\/u\/(.*?)\s', voteEntry.body, re.IGNORECASE) if match is None: state["error"] = "Couldn't find the username from the vote comment for '{}'\n\n".format(voteEntry.body) return state # ensure that they are both the same username = match.group(1).strip() if contributionObject.author is None or username.lower() != contributionObject.author.name.lower(): state["error"] = ("Username in the voting thread doesn't match the username of the nominated object." + " Username: {}, Nominated Object: {}").format(username, idx) return state winnerUser = contributionObject.author # returns dict {"flair_css_class":?, "flair_text":?, "user":?} winnerFlair = self.r.get_flair(subreddit, winnerUser) winnerCurrentRank = RankUtils.getRankLevelFromFlair(winnerFlair["flair_css_class"]) # cpo possible at all? if winnerCurrentRank in RankUtils.cpoStepRanks: cpoCandidates.append((winnerUser, winnerFlair["flair_css_class"] if winnerFlair["flair_css_class"] is not None else "")) logging.info("CPO Candidate: " + winnerUser.name) if not idx in potwIndices+ecIndices: continue logging.info("{} - {} - {}".format(winnerUser.name, winnerCurrentRank, RankUtils.rankLevels[winnerCurrentRank]["name"])) winnersInfo.append({"user": winnerUser, "currentRank": winnerCurrentRank, "promotionKind": "potw" if idx in potwIndices else "ec", "comment": voteEntry, "text": winnerInfo[0]}) notes = "" message = "" finalWinnerInfo = [] # now that we have all the winners, lets see who gets promoted to what for wi in winnersInfo: # calculate the promotion of that person, to that end get his service # record username = wi["user"].name careerPotW = 0 careerDelphi = 0 total = 0 serviceRecord = self.r.get_wiki_page(subreddit, username) # check if the record exists. This combersome way currently seems to be # the only working one pageExists = False try: serviceRecord.content_md pageExists = True except: pageExists = False temporaryNoPromotion = False if serviceRecord is None or pageExists is False: if wi["currentRank"] >= RankUtils.serviceRecordThresholdRank: # Ensign ought to have a page ... notes += "* Person /u/{} ought to have a service record, but hasn't gotten one. Setting them to not promoted temporarily, **please review and, if applicable, change this**.\n".format(username) temporaryNoPromotion = True else: # split into lines lines = serviceRecord.content_md.split("\n") ret = RankUtils.analyzeServiceRecord(lines) if ret is None: notes += "* Couldn't read the [service record](https://reddit.com/r/DaystromInstitute/wiki/{}) of user /u/{}. Setting them to not promoted temporarily, **please review and, if applicable, change this**.\n".format(username, username) temporaryNoPromotion = True else: careerPotW, careerDelphi, total = ret logging.info("Analyzed the service record of /u/{}. They have {} PotW, {} DELPHI totalling {}".format(username, careerPotW, careerDelphi, total)) # check the next promotion total += 1 # if they were promoted careerPotW += 1 resDict = {"serviceRecord": serviceRecord, "user": wi["user"], "currentRank": RankUtils.rankLevels[wi["currentRank"]], "promotionKind": wi["promotionKind"], "comment": wi["comment"], "text": wi["text"]} res = None newRank = wi["currentRank"] if temporaryNoPromotion: res = (False, "") elif wi["currentRank"] < 3: # crewman, cpo and citizen get autopromoted to ensign on PotW res = (True, "") newRank = RankUtils.stepFinishRank # ensign elif wi["currentRank"] < len(RankUtils.rankLevels) - 1: nextRank = RankUtils.rankLevels[wi["currentRank"] + 1] res = nextRank["advanceFunction"](total, careerPotW, careerDelphi) newRank = newRank + 1 else: res = (False, "") resDict["willBePromoted"] = res[0] resDict["promoteAftermessage"] = res[1] resDict["promoteTo"] = RankUtils.rankLevels[newRank] finalWinnerInfo.append(resDict) # format this for the message message += "\n\n" message += formatFinalWinnerInfo(finalWinnerInfo) message += "\nPlease note: \n\n" message += notes message += "\n" + InfoMessages.step2 self.messageHandler.dispatchOutput(message) # put it into the state state["finalWinnerInfo"] = finalWinnerInfo state["cpoCandidates"] = cpoCandidates state["reminders"].append(notes) return state