Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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