Esempio n. 1
0
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))
Esempio n. 2
0
#!/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))
Esempio n. 3
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
Esempio n. 4
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