Example #1
0
def sharing_winners():
    """
    Pick winner from amongst all users who are eligible winners.

    This tool examines all participants in the newest sharing challenge, and
    prints ones that could win it. The newest challenge is picked automatically
    based on creation date, and everyone who has completed all todos is
    considered eligible to win.

    The winner is chosen based on the opening, closing, highest and lowest
    values of AEX index (Amsterdam Stock Exchange) from this week Tuesday. In
    order to make sure that the result is indeed deterministic, make sure that
    the stock has already closed for the day before calling the script:
    otherwise e.g. the closing price can still change.
    """
    tool = PartyTool(HEADER)
    challenge_id = tool.current_sharing_weekend()["id"]
    challenge = Challenge(HEADER, challenge_id)

    click.echo(challenge.completer_str())
    click.echo("")

    today = datetime.date.today()
    last_tuesday = today - datetime.timedelta(today.weekday() - 1)

    click.echo(challenge.winner_str(last_tuesday, "^AEX"))
Example #2
0
def party_members():
    """
    Show current party members.
    """
    tool = PartyTool(HEADER)
    members = tool.party_members()
    for member in members:
        print(u"{:<20}(@{})".format(member.displayname.replace("\n", " "),
                                    member.login_name))
Example #3
0
def participants(challenge_name):
    """
    Print list of everyone who completed CHALLENGE_NAME

    The given challenge name can be a substring of the whole name. If there are
    more than one matchin challenge, the newest one of them is returned.
    """
    tool = PartyTool(HEADER)
    challenge_id = tool.newest_matching_challenge([challenge_name], [])["id"]
    challenge = Challenge(HEADER, challenge_id)

    click.echo(challenge.completer_str())
Example #4
0
    def update_partymember_data(self):
        """
        Fetch current party member data from Habitica and update the database.

        If the database contains members that are not currently in the party,
        they are removed from the database.
        """
        self._logger.debug("Going to update partymember data in the DB.")
        partytool = PartyTool(self._header)
        partymembers = partytool.party_members()

        self.add_new_members(partymembers)
        self._logger.debug("Added new members")
        self.remove_old_members(partymembers)
        self._logger.debug("Removed outdated members")
Example #5
0
    def __init__(self, header, challenge_id):
        """
        Create a class for a challenge.

        :header: Header to use with API
        :challenge_id: The ID of the represented challenge
        """
        self.id = challenge_id  # pylint: disable=invalid-name
        self._header = header
        self._full_data = utils.get_dict_from_api(
            header,
            "https://habitica.com/api/v3/challenges/{}".format(challenge_id))
        self._party_tool = PartyTool(header)
        self._participants = None
        self._completers = None
Example #6
0
def party_birthdays():
    """
    Update party birthdays in the birthday calendar and print them.

    The birthdays are stored in the Google calendar whose ID is specified as
    BIRTHDAYS in conf/calendars.py.
    """
    tool = PartyTool(HEADER)
    members = tool.party_members()
    for member in members:
        bday = member.habitica_birthday
        result = tool.ensure_birthday(calendars.BIRTHDAYS, member)
        output = u"{:<20} {}.{}.{}\t{}".format(member.login_name, bday.day,
                                               bday.month, bday.year,
                                               result[1])
        click.echo(output)
Example #7
0
def pick_winner(challenge_name, stock_timestamp, stock_name):
    """
    Print participants and random-selected winner for a challenge.
    """
    tool = PartyTool(HEADER)
    challenge_id = tool.newest_matching_challenge([challenge_name], [])["id"]
    challenge = Challenge(HEADER, challenge_id)

    click.echo(challenge.completer_str())
    click.echo("")

    if not stock_timestamp:
        stock_date = datetime.date.today()
    else:
        try:
            stock_date = datetime.datetime.strptime(stock_timestamp, "%Y%m%d")
        except ValueError:
            click.echo("Given stock_date does not seem to be a valid "
                       "timestamp. It must be given in ISO-8601 format as "
                       "`YYYYMMDD`.")
            sys.exit(1)

    click.echo(challenge.winner_str(stock_date, stock_name))
Example #8
0
class Challenge():
    """
    Data and operations for an existing Habitica challenge.
    """
    def __init__(self, header, challenge_id):
        """
        Create a class for a challenge.

        :header: Header to use with API
        :challenge_id: The ID of the represented challenge
        """
        self.id = challenge_id  # pylint: disable=invalid-name
        self._header = header
        self._full_data = utils.get_dict_from_api(
            header,
            "https://habitica.com/api/v3/challenges/{}".format(challenge_id))
        self._party_tool = PartyTool(header)
        self._participants = None
        self._completers = None

    @property
    def participants(self):
        """
        A list of all party members who have joined the challenge.
        """
        if self._participants is None:
            self._participants = self._party_tool.challenge_participants(
                self.id)
        return self._participants

    @property
    def completers(self):
        """
        A list of party members who have completed all challenge todo tasks.
        """
        if self._completers is None:
            self._completers = sorted(
                self._party_tool.eligible_winners(self.id, self.participants))
        return self._completers

    @property
    def name(self):
        """
        The name of the challenge.
        """
        return self._full_data["name"]

    @name.setter
    def name(self, name):
        """
        Rename the challenge.

        This method only affects the local copy of the challenge: the update()
        method needs to be called to send the changes to Habitica.
        """
        self._full_data["name"] = name

    @property
    def summary(self):
        """
        The challenge summary.
        """
        return self._full_data["summary"]

    @summary.setter
    def summary(self, summary):
        """
        Change the summary of the challenge.

        This method only affects the local copy of the challenge: the update()
        method needs to be called to send the changes to Habitica.
        """
        self._full_data["summary"] = summary

    @property
    def description(self):
        """
        The challenge description.
        """
        return self._full_data["description"]

    @description.setter
    def description(self, description):
        """
        Change the challenge description.

        This method only affects the local copy of the challenge: the update()
        method needs to be called to send the changes to Habitica.
        """
        self._full_data["description"] = description

    def update(self):
        """
        Update the name, description and summary of the challenge.
        """
        new_data = {
            "name": self.name,
            "description": self.description,
            "summary": self.summary
        }
        habrequest.put("https://habitica.com/api/v3/challenges/{}".format(
            self.id),
                       data=new_data,
                       headers=self._header)

    def completer_str(self):
        """
        Return a string listing all people who completed the challenge
        """
        if len(self.completers) == 0:
            return ("Nobody completed all tasks for challenge \"{}\"."
                    "".format(self.name))

        intro = ("The party members who completed all todo tasks for "
                 "challenge \"{}\" are:\n".format(self.name))
        completer_lines = ["- {}".format(member) for member in self.completers]
        return intro + "\n".join(completer_lines)

    def random_winner(self, date, stock):
        """
        Pick a winner for the challenge, based on the values of stock on a date

        :date: Date object representing the date from which to use the stock
               data.
        :stock: Stock to use, e.g. "^AEX". Make sure that the stock has already
                closed for the day used: otherwise the result might still
                change.
        :returns: The Member who won the challenge
        """
        randomizer = StockRandomizer(stock, date)
        winner_index = randomizer.pick_integer(0, len(self.completers) - 1)
        return self.completers[winner_index]

    def winner_str(self, date, stock):
        """
        Pick a winner as `winner` does, but return a string.

        The returned string states the date, stock and seed used to pick the
        winner, together with the name of the winner.

        :date: Date object representing the date from which to use the stock
               data.
        :stock: Stock to use, e.g. "^AEX". Make sure that the stock has already
                closed for the day used: otherwise the result might still
                change.
        :returns: A string describing the process.
        """
        randomizer = StockRandomizer(stock, date)
        winner = self.random_winner(date, stock)
        return ("Using stock data for {} from {} (seed {}).\n\n"
                "{} wins the challenge!".format(date, stock, randomizer.seed,
                                                winner))

    def award_winner(self, winner):
        """
        Award the given user as the winner for the challenge.

        :winner: UID of the winner
        """
        response = habrequest.post(
            "https://habitica.com/api/v3/challenges/{}/selectWinner/{}"
            "".format(self.id, winner),
            headers=self._header)
        response.raise_for_status()

    def clone(self):
        """
        Create a clone of this challenge and return its ID.
        """
        resp = habrequest.post(
            "https://habitica.com/api/v3/challenges/{}/clone"
            "".format(self.id),
            headers=self._header)
        resp.raise_for_status()
        return resp.json()["data"]["id"]

    def add_task(self, taskdata):
        """
        Add a new task to this challenge.

        :taskdata: A dict representing the new task, see
                   https://habitica.com/apidoc/#api-Task-CreateChallengeTasks
                   for keys and their values
        """
        resp = habrequest.post(
            "https://habitica.com/api/v3/tasks/challenge/{}".format(self.id),
            data=taskdata,
            headers=self._header)
        resp.raise_for_status()