Example #1
0
    def post(self):
        api_assert(self.body['data'], 400, 'empty data')

        try:
            ap_datas = []

            router_mac = Mac.correct(self.body['apMac'])
            signal = Signal(band='2.4', channel=self.body['band'])
            created_at = Time(int(self.body['time']))

            for item in self.body['data']:
                device_mac = Mac.correct(item['clientMac'])
                rssis = {}
                if item.get('rss1') is not None:
                    rssis['1'] = RSSI(float(item['rss1']))
                if item.get('rss2') is not None:
                    rssis['2'] = RSSI(float(item['rss2']))
                if item.get('rss3') is not None:
                    rssis['3'] = RSSI(float(item['rss3']))

                if len(rssis) > 0:
                    ap_datas.append(
                        APData(router_mac=router_mac,
                               device_mac=device_mac,
                               created_at=created_at,
                               rssis=rssis,
                               signal=signal))

            for ap_data in ap_datas:
                self.ap_data_dao.save(ap_data)
        except DBException as e:
            raise APIError(500, e.message)
        return 'ok'
Example #2
0
    def put(self, id):
        job = waker().scheduler.get_job(id)
        if(not job):
            api_assert(False, log_message="no such alarm.")
            return

        mod_args = {}
        for key in ["sound_id", "level", "repeat"]:
            if(key in self.body):
                mod_args[key] = self.body[key]
            else:
                mod_args[key] = job.kwargs[key]
        mc = music_controller()
        if not mc.exist(mod_args["sound_id"]):
            api_assert(False, log_message="such sound_id is not exists.")
            return
        mod_day_of_week = get_dayofweek_list_from_job(job)
        if("day_of_week" in self.body):
            mod_day_of_week = self.body["day_of_week"]
        mod_day_of_week = ",".join(mod_day_of_week)

        d = job.next_run_time.time()
        if("time" in self.body):
            d = datetime.strptime(self.body["time"], TIME_FORMAT)
        
        mod_trigger = CronTrigger(hour=d.hour, minute=d.minute, second=d.second, day_of_week=mod_day_of_week)
        job.modify(kwargs=mod_args)
        job.reschedule(mod_trigger)
    def post(self):
        """Decline or accept invite

        * `id`: ID of game you want to respond to invite for
        * `decision`: Either "Accept" or "Decline"
        """
        attrs = dict(self.body)

        with db_session:
            game = GameEntity.get(id=attrs['id'])
            me = PlayerEntity[self.get_current_user()]
            api_assert(
                game is not None,
                400,
                log_message="No such game {} exists!".format(attrs['id'])
            )
            player_invites = get_player_invitations(me.username)
            api_assert(
                attrs['id'] in player_invites,
                400,
                log_message="This game is not in your list of invitations!"
            )

            if attrs['decision'] == "Accept":
                game.accepted_players.add(me)
                return "You successfully joined game {}!".format(attrs['id'])
            elif attrs['decision'] == "Decline":
                game.cancelled = True
                return "You declined and the game ({}) has been cancelled!".format(
                    attrs['id']
                )
Example #4
0
    def post(self):
        """Decline or accept invite

        * `id`: ID of game you want to respond to invite for
        * `decision`: Either "Accept" or "Decline"
        """
        attrs = dict(self.body)

        with db_session:
            game = GameEntity.get(id=attrs['id'])
            me = PlayerEntity[self.get_current_user()]
            api_assert(game is not None,
                       400,
                       log_message="No such game {} exists!".format(
                           attrs['id']))
            player_invites = get_player_invitations(me.username)
            api_assert(
                attrs['id'] in player_invites,
                400,
                log_message="This game is not in your list of invitations!")

            if attrs['decision'] == "Accept":
                game.accepted_players.add(me)
                return "You successfully joined game {}!".format(attrs['id'])
            elif attrs['decision'] == "Decline":
                game.cancelled = True
                return "You declined and the game ({}) has been cancelled!".format(
                    attrs['id'])
Example #5
0
File: musics.py Project: 106-/waker
 def wrap(self, id):
     mc = music_controller()
     if not mc.exist(id):
         api_assert(False,
                    status_code=404,
                    log_message="no such sound_id.")
     return func(self, id)
Example #6
0
    def delete(self):
        """DELETE to remove yourself from current game"""
        # Get player and the game_id he's in
        player_name = self.get_current_user()
        player = Player(self.db_conn, "name", player_name)
        game_id = player["current_game_id"]
        api_assert(game_id,
                   409,
                   log_message="You are not currently in a game.")

        with DBLock():
            # Get game
            game = Game(self.db_conn, "game_id", game_id)

            # Get remaining set of players
            rem_players = list(set(game["players"]) - {player_name})

            # Set new gamemaster
            if not rem_players:
                game["gamemaster"] = None
            # If gamemaster is leaving, assign to a random player
            elif game["gamemaster"] == player_name:
                game["gamemaster"] = choice(rem_players)

            # Set remaining players in game and add players' balls to game's
            #   unclaimed set
            game["players"] = rem_players
            game["unclaimed_balls"] += player["balls"]

            # Set the player's game_id to None and his list of balls to empty
            player["current_game_id"] = None
            player["balls"] = []

        return {"game_id": game_id}
Example #7
0
def join_room(db, room_name, password, player_name):
    """Join room ``room_name``

    Updates ``current_players`` entry for room ``room_name`` with
    player ``player_name`` to the database.

    :raises APIError: If a room with ``room_name`` does not exist;
        or if the password is incorrect for room ``room_name``, or if player
        ``player_name`` does not exist
    """
    # Ensure that the following preconditions are met:
    #   * Correct password to room is give if required
    #   * The player is not already in a room
    room = get_room(db, room_name)
    api_assert(password == room['password'], 403,
               log_message="Bad password for room `{}`.".format(room_name))
    player = get_player(db, player_name)
    api_assert(
        player_name not in room["current_players"],
        409,
        log_message="Player `{}` already in room `{}`".format(
            player_name, room_name)
    )
    # If they are met, add the player to the room
    room["current_players"] += [player_name]
    player["current_room"] = room_name
Example #8
0
    def post(self):
        """
        post new alarm schedule. returns job id.

        ### input
        * `time`: colon(":") splitted time. (i.e. 09:30:00) this value means when alarm go off. 
        * `day_of_week`: list of "day of week".  
        * `sound_id`: random 32byte hexadecimal string. you can get filename->sound_id correspondence from /api/musics/. if not set this value, waker may choose music randomly from same "level".
        * `level`: type of alarm. (i.e. "alarm","notify","warning")
        * `repeat`: number of repeat sound. 0 means "repeats indefinitely".
        ### output
        job id.
        """

        d = datetime.strptime(self.body["time"], TIME_FORMAT)

        day_of_week = ",".join(self.body["day_of_week"])

        sound_id = None
        if("sound_id" in self.body):
            sound_id = self.body["sound_id"]
            mc = music_controller()
            if not mc.exist(sound_id):
                api_assert(False, log_message="such sound_id is not exists.")
                return

        level = self.body["level"]
        repeat = self.body["repeat"]
        job = waker().scheduler.add_job(waker.alarm_go_off, "cron", hour=d.hour, minute=d.minute, second=d.second, day_of_week=day_of_week, kwargs={"repeat":repeat, "level":level, "sound_id":sound_id})
        return job.id
Example #9
0
    def get(self):
        """
        GET to receive list of players in current room

        * `players` array includes ALL players (including owner)
        * `owner` field is useful for highlighting the room owner in the UI
        """
        player_name = self.get_current_user()
        # The reason we don't use get_player in a case like
        #   this, is because this is an authenticated method,
        #   so a player with the name of the current user
        #   SHOULD exist; if he doesn't, then that indicates
        #   a problem on our side (if that happens, the user
        #   will see a 500 Internal Server Error) which
        #   is arguably appropriate in this case.
        player = Player(self.db_conn, "name", player_name)
        room_name = player["current_room"]
        api_assert(room_name, 400, log_message="You are not currently in"
                   " a room.")

        # Again, same thing here; if the player has joined
        #   a room, the room name must exist, otherwise, it
        #   indicates a failure somewhere earlier down the line.
        room = Room(self.db_conn, "name", room_name)
        return {
            "players": room["current_players"],
            "owner": room["owner"]
        }
Example #10
0
    def post(self):
        """
        POST the required credentials to get back a cookie

        * `username`: Username
        * `password`: Password
        """
        api_assert(self.body['username'],
                   400,
                   log_message="Username field is empty!")

        with db_session:
            player = PlayerEntity.get(username=self.body['username'])
            api_assert(player is not None,
                       400,
                       log_message="No such player {}".format(
                           self.body['username']))

        password = self.body['password']
        # Check if the given password hashed with the player's known
        #   salt matches the stored password
        password_match = bcrypt.hashpw(
            password.encode(),
            player.salt.encode()) == player.password.encode()
        if password_match:
            self.set_secure_cookie(
                "user", self.body['username'],
                self.settings['app_config'].session_timeout_days)
            return {"username": player.username}
        else:
            raise APIError(400, log_message="Bad username/password combo")
Example #11
0
    def delete(self):
        """DELETE to remove yourself from current game"""
        # Get player and the game_id he's in
        player_name = self.get_current_user()
        player = Player(self.db_conn, "name", player_name)
        game_id = player["current_game_id"]
        api_assert(game_id, 409,
                   log_message="You are not currently in a game.")

        with DBLock():
            # Get game
            game = Game(self.db_conn, "game_id", game_id)

            # Get remaining set of players
            rem_players = list(set(game["players"]) - {player_name})

            # Set new gamemaster
            if not rem_players:
                game["gamemaster"] = None
            # If gamemaster is leaving, assign to a random player
            elif game["gamemaster"] == player_name:
                game["gamemaster"] = choice(rem_players)

            # Set remaining players in game and add players' balls to game's
            #   unclaimed set
            game["players"] = rem_players
            game["unclaimed_balls"] += player["balls"]

            # Set the player's game_id to None and his list of balls to empty
            player["current_game_id"] = None
            player["balls"] = []

        return {"game_id": game_id}
Example #12
0
 def get(self, id):
     job = waker().scheduler.get_job(id)
     if(not job):
         api_assert(False, log_message="no such rule.")
         return
     job_dict = make_cronobj_from_job(job)
     return job_dict
Example #13
0
    def post(self):
        """
        (Game host only) POST to finalize game
        """
        attrs = dict(self.body)

        with db_session:
            game = GameEntity.get(id=attrs['id'])
            api_assert(game is not None,
                       400,
                       log_message="No such game {} exists!".format(
                           attrs['id']))

            api_assert(game.host.username == self.get_current_user(),
                       403,
                       log_message="Only the host of this game may edit it!")

            api_assert(game.cancelled is not True, 400,
                       "This game has been cancelled. :(")

            api_assert(
                len(game.accepted_players) == len(
                    [p for t in game.teams for p in t.users]), 400,
                "Not everyone has accepted invites for this game yet!")

            team_names = [team.name for team in game.teams]
            team_a = TeamEntity[team_names[0]]
            team_b = TeamEntity[team_names[1]]

            # Make sure final_score has legit team names
            final_score = attrs['final_score']
            for team_name, score in final_score.iteritems():
                api_assert(team_name in team_names, 400,
                           "{} is not part of this game!".format(team_name))

            # Set wins, losses and ties
            if final_score[team_a.name] > final_score[team_b.name]:
                team_a.wins += 1
                team_b.losses += 1
            elif final_score[team_a.name] < final_score[team_b.name]:
                team_b.wins += 1
                team_a.losses += 1
            else:
                team_a.ties += 1
                team_b.ties += 1

            # Calculate new points_ratio
            for team1, team2 in [(team_a, team_b), (team_b, team_a)]:
                total_games = team1.wins + team1.losses + team1.ties
                team1.points_ratio = (
                    (team1.points_ratio * max(total_games, 0)) +
                    (final_score[team1.name] /
                     final_score[team2.name])) / total_games

            # Set final score
            game.final_score = json.dumps(final_score)

            return "Game results recorded with final score: {}".format(
                json.dumps(final_score))
Example #14
0
 def delete(self, id):
     """
     delete scheduled alarm.
     """
     job = waker().scheduler.get_job(id)
     if (not job):
         api_assert(False, log_message="no such alarm.")
         return
     job.remove()
Example #15
0
 def get(self):
     try:
         result = yield self.api_client.update_cache()
     except AssertionError as e:
         api_assert(False, 403, e.message)
     except Exception as e:
         self.error(e)
     else:
         self.success(result)
Example #16
0
    def post(self):
        """
        POST the required parameters to register the pocketing/unpocketing of a ball

        * `ball`: The ball that was pocketed/unpocketed
        """
        gamemaster = self.get_current_user()
        ball = self.body['ball']
        game_id = get_player(self.db_conn, gamemaster)["current_game_id"]
        game = Game(self.db_conn, "game_id", game_id)

        res = {"game_id": game_id}

        # Authenticate
        api_assert(
            game["gamemaster"] == gamemaster,
            401,
            log_message="You are not the gamemaster of the current game"
        )

        # If ball is already sunk, retable it
        if ball not in get_balls_on_table(self.db_conn, game_id):
            game = Game(self.db_conn, "game_id", game_id)
            # Look for ball in game's set of unclaimed balls
            if ball in game["orig_unclaimed_balls"]:
                game["unclaimed_balls"] += [ball]
            # If it's not there, look for it from each player's set
            else:
                for pname in game["players"]:
                    p = Player(self.db_conn, "name", pname)
                    if ball in p["orig_balls"]:
                        p["balls"] += [ball]
                        break
            res['message'] = "Ball {} was retabled.".format(ball)
            return res

        # Otherwise, sink the ball
        # Look for it in players' first
        for pname in Game(self.db_conn, "game_id", game_id)["players"]:
            p = get_player(self.db_conn, pname)
            if ball in p["balls"]:
                p["balls"] = list(set(p["balls"]) - {ball})
                break
        else:
            # Remove ball from unclaimed
            g = Game(self.db_conn, "game_id", game_id)
            uballs = list(game["unclaimed_balls"])
            uballs.remove(ball)
            game["unclaimed_balls"] = uballs

        res["message"] = "Ball {} was sunk.".format(ball)
        return res
Example #17
0
    def get(self):
        from_city = self.get_argument('from_city', None)
        to_city = self.get_argument('to_city', None)
        direction = "{0} - {1}".format(from_city, to_city)

        try:
            result = yield self.api_client.get_flights_hash(direction)
        except AssertionError as e:
            api_assert(False, 403, e.message)
        except Exception as e:
            self.error(e)
        else:
            self.success(result)
Example #18
0
    def delete(self):
        """
        DELETE to end the game; this endpoint should only be triggered if
            GameState indicates there is a winner.
        """
        player_name = self.get_current_user()
        player = get_player(self.db_conn, player_name)
        game_id = player["current_game_id"]
        api_assert(game_id, 400, log_message="You are not currently in"
                   " a game.")
        game = get_game(self.db_conn, game_id)

        with DBLock():
            is_gamemaster = game["gamemaster"] == player_name
            gamemaster_has_closed = game["gamemaster"] is None

            winner_name = get_game_winner(self.db_conn, game_id)
            # If there is no current winner, return an error
            if not winner_name:
                raise APIError(
                    409,
                    log_message="The game currently has no winner."
                )
            # Otherwise, clean up everything
            else:
                # We want the gamemaster to FIRST to do the cleanup
                if is_gamemaster:
                    # Record the win for the player who won
                    winner = get_player(self.db_conn, winner_name)
                    winner["games_won"] += [game_id]
                    game["winner"] = winner_name
                    # Remove all players from game
                    for pname in game["players"]:
                        p = get_player(self.db_conn, pname)
                        p["balls"] = []
                        p["orig_balls"] = []
                    # Clear the game's "current" attributes
                    game["players"] = []
                    game["gamemaster"] = None
                    # Remove the gamemaster's current_game_id
                    player["current_game_id"] = None
                # Then the remainder of the players can truly leave the game
                #   so they have a chance to query who the winner was from GameState
                #   before having their current_game_id set to None
                elif gamemaster_has_closed:
                    player["current_game_id"] = None

                return "Game {} was completed; {} was the winner.".format(
                        game_id,
                        winner_name
                )
Example #19
0
    def post(self):
        """
        POST the required parameters to register the pocketing/unpocketing of a ball

        * `ball`: The ball that was pocketed/unpocketed
        """
        gamemaster = self.get_current_user()
        ball = self.body['ball']
        game_id = get_player(self.db_conn, gamemaster)["current_game_id"]
        game = Game(self.db_conn, "game_id", game_id)

        res = {"game_id": game_id}

        # Authenticate
        api_assert(
            game["gamemaster"] == gamemaster,
            401,
            log_message="You are not the gamemaster of the current game")

        # If ball is already sunk, retable it
        if ball not in get_balls_on_table(self.db_conn, game_id):
            game = Game(self.db_conn, "game_id", game_id)
            # Look for ball in game's set of unclaimed balls
            if ball in game["orig_unclaimed_balls"]:
                game["unclaimed_balls"] += [ball]
            # If it's not there, look for it from each player's set
            else:
                for pname in game["players"]:
                    p = Player(self.db_conn, "name", pname)
                    if ball in p["orig_balls"]:
                        p["balls"] += [ball]
                        break
            res['message'] = "Ball {} was retabled.".format(ball)
            return res

        # Otherwise, sink the ball
        # Look for it in players' first
        for pname in Game(self.db_conn, "game_id", game_id)["players"]:
            p = get_player(self.db_conn, pname)
            if ball in p["balls"]:
                p["balls"] = list(set(p["balls"]) - {ball})
                break
        else:
            # Remove ball from unclaimed
            g = Game(self.db_conn, "game_id", game_id)
            uballs = list(game["unclaimed_balls"])
            uballs.remove(ball)
            game["unclaimed_balls"] = uballs

        res["message"] = "Ball {} was sunk.".format(ball)
        return res
    def post(self):
        """
        Does matchmaking by finding a rival team for the provided `team_name`,
        creates a new game with the two teams and returns the game_id
        for that game
        """
        team_name = self.body['team_name']
        with db_session:
            myteam = TeamEntity.get(name=team_name)
            api_assert(
                PlayerEntity[self.get_current_user()] in myteam.users,
                403,
                log_message="You can only matchmake for teams that you are"
                            " a part of!"
            )
            overall_rankings = get_team_rankings(myteam)
            myranking = overall_rankings[myteam.name]

            ranking_vals = overall_rankings.values()
            rankings_by_ranking = invert_dict_nonunique(overall_rankings)

            who_you_verse_index = None
            print(overall_rankings)
            while (who_you_verse_index not in ranking_vals):
                print(who_you_verse_index)
                from time import sleep
                sleep(0.4)
                if len(rankings_by_ranking) == 1:
                    who_you_verse_index = myranking
                else:
                    who_you_verse_index = choice(
                        [rval for rval in ranking_vals
                         if rval != myranking and
                         abs(rval - myranking) <= 10]
                    )

            rival_team_name = rankings_by_ranking[who_you_verse_index][0]
            if rival_team_name == myteam.name:
                rival_team_name = rankings_by_ranking[who_you_verse_index][1]
            rival_team = TeamEntity[rival_team_name]

            game = GameEntity(
                teams=[myteam, rival_team],
                host=PlayerEntity[self.get_current_user()],
                accepted_players=[PlayerEntity[self.get_current_user()]]
            )
            commit()

            return {"game_id": game.id}
Example #21
0
    def delete(self):
        """
        DELETE to end the game; this endpoint should only be triggered if
            GameState indicates there is a winner.
        """
        player_name = self.get_current_user()
        player = get_player(self.db_conn, player_name)
        game_id = player["current_game_id"]
        api_assert(game_id,
                   400,
                   log_message="You are not currently in"
                   " a game.")
        game = get_game(self.db_conn, game_id)

        with DBLock():
            is_gamemaster = game["gamemaster"] == player_name
            gamemaster_has_closed = game["gamemaster"] is None

            winner_name = get_game_winner(self.db_conn, game_id)
            # If there is no current winner, return an error
            if not winner_name:
                raise APIError(409,
                               log_message="The game currently has no winner.")
            # Otherwise, clean up everything
            else:
                # We want the gamemaster to FIRST to do the cleanup
                if is_gamemaster:
                    # Record the win for the player who won
                    winner = get_player(self.db_conn, winner_name)
                    winner["games_won"] += [game_id]
                    game["winner"] = winner_name
                    # Remove all players from game
                    for pname in game["players"]:
                        p = get_player(self.db_conn, pname)
                        p["balls"] = []
                        p["orig_balls"] = []
                    # Clear the game's "current" attributes
                    game["players"] = []
                    game["gamemaster"] = None
                    # Remove the gamemaster's current_game_id
                    player["current_game_id"] = None
                # Then the remainder of the players can truly leave the game
                #   so they have a chance to query who the winner was from GameState
                #   before having their current_game_id set to None
                elif gamemaster_has_closed:
                    player["current_game_id"] = None

                return "Game {} was completed; {} was the winner.".format(
                    game_id, winner_name)
def get_team_rankings(myteam, filter_for_matchmaking=True):
    team_name = myteam.name
    sport_name = myteam.sport.name
    if myteam is None:
        raise APIError(
            400,
            log_message="Team with name {} does not exist!"
            .format(team_name)
        )

    ### Figure out rival team

    # Find teams that are of the same sport and also
    # that they don't contain any players from myteam
    sport_teams = select(team for team in TeamEntity
                         if team.sport.name == sport_name)[:]
    print sport_teams, [[player.username for player in team.users] for team in sport_teams ]

    if filter_for_matchmaking:
        myteam_names = [player.username for player in myteam.users]
        print myteam_names
        sport_teams = [team for team in sport_teams if all(
            player.username not in myteam_names for player in team.users
        )]
        print sport_teams
        sport_teams.append(myteam)
        num_teams = len(sport_teams)
        api_assert(
            num_teams > 1,
            409,
            "There are no other teams with all different people!"
        )

    overall_rankings = defaultdict(lambda: 0)

    teams_wlratio = sorted([
        (team, float(team.wins) / (team.losses or 1))
        for team in sport_teams
    ], key=lambda t: t[1], reverse=True)
    for i, (team, wlratio) in enumerate(teams_wlratio):
        overall_rankings[team.name] += i
    teams_pointsratio = sorted([
        (team, team.points_ratio) for team in sport_teams
    ], key=lambda t: t[1], reverse=True)
    for i, (team, points_ratio) in enumerate(teams_pointsratio):
        overall_rankings[team.name] += i

    return overall_rankings
Example #23
0
    def post(self):
        """
        post new alarm schedule. returns job id.

        ### input
        * `time`: ISO8601 formatted string. this value means when alarm go off. if not set, alarm will go off immediately.
        * `sound_id`: random 32byte hexadecimal string. you can get filename->sound_id correspondence from /api/musics/. if not set this value, waker may choose music randomly from same "level".
        * `level`: type of alarm. (i.e. "alarm","notify","warning")
        * `repeat`: number of repeat sound. 0 means "repeats indefinitely".
        ### output
        job id.
        """
        d = None
        if ("time" in self.body):
            d = iso8601.parse_date(self.body["time"])
            if d < datetime.datetime.now(tz=TIMEZONE):
                api_assert(False,
                           log_message="time must be later than present.")
                return

        sound_id = None
        if ("sound_id" in self.body):
            sound_id = self.body["sound_id"]
            mc = music_controller()
            if not mc.exist(sound_id):
                api_assert(False, log_message="such sound_id is not exists.")
                return

        level = self.body["level"]
        repeat = self.body["repeat"]
        job = None
        if (d):
            job = waker().scheduler.add_job(waker.alarm_go_off,
                                            "date",
                                            run_date=d,
                                            kwargs={
                                                "repeat": repeat,
                                                "level": level,
                                                "sound_id": sound_id
                                            })
        else:
            job = waker().scheduler.add_job(waker.alarm_go_off,
                                            kwargs={
                                                "repeat": repeat,
                                                "level": level,
                                                "sound_id": sound_id
                                            })
        return job.id
Example #24
0
    def put(self):
        """
        PUT the required parameters to permanently register a new player

        * `username`
        * `first`: First name
        * `last`: Last name
        * `password`: Password for future logins
        * `gender`: M/F
        * `birthday`: e.g., "1993-05-16"
        * `city`
        * `country`
        * `bio`
        """
        attrs = dict(self.body)

        # Set salt and password
        salt = bcrypt.gensalt(rounds=12)
        attrs['password'] = bcrypt.hashpw(
            password=attrs['password'].encode(),
            salt=salt
        ).decode()
        attrs['salt'] = salt.decode()

        # Create player
        with db_session:
            api_assert(
                attrs['username'],
                400,
                log_message="Provided username is empty!"
            )
            if PlayerEntity.get(username=attrs['username']):
                raise APIError(
                    409,
                    log_message="Player with username {} already exists!"
                    .format(attrs['username'])
                )
            player = PlayerEntity(**attrs)

        # Log the user in
        self.set_secure_cookie(
            "user",
            attrs['username'],
            self.settings['app_config'].session_timeout_days
        )

        return {"username": player.username}
Example #25
0
    def post(self):
        """
        Does matchmaking by finding a rival team for the provided `team_name`,
        creates a new game with the two teams and returns the game_id
        for that game
        """
        team_name = self.body['team_name']
        with db_session:
            myteam = TeamEntity.get(name=team_name)
            api_assert(
                PlayerEntity[self.get_current_user()] in myteam.users,
                403,
                log_message="You can only matchmake for teams that you are"
                " a part of!")
            overall_rankings = get_team_rankings(myteam)
            myranking = overall_rankings[myteam.name]

            ranking_vals = overall_rankings.values()
            rankings_by_ranking = invert_dict_nonunique(overall_rankings)

            who_you_verse_index = None
            print(overall_rankings)
            while (who_you_verse_index not in ranking_vals):
                print(who_you_verse_index)
                from time import sleep
                sleep(0.4)
                if len(rankings_by_ranking) == 1:
                    who_you_verse_index = myranking
                else:
                    who_you_verse_index = choice([
                        rval for rval in ranking_vals
                        if rval != myranking and abs(rval - myranking) <= 10
                    ])

            rival_team_name = rankings_by_ranking[who_you_verse_index][0]
            if rival_team_name == myteam.name:
                rival_team_name = rankings_by_ranking[who_you_verse_index][1]
            rival_team = TeamEntity[rival_team_name]

            game = GameEntity(
                teams=[myteam, rival_team],
                host=PlayerEntity[self.get_current_user()],
                accepted_players=[PlayerEntity[self.get_current_user()]])
            commit()

            return {"game_id": game.id}
Example #26
0
def get_team_rankings(myteam, filter_for_matchmaking=True):
    team_name = myteam.name
    sport_name = myteam.sport.name
    if myteam is None:
        raise APIError(
            400,
            log_message="Team with name {} does not exist!".format(team_name))

    ### Figure out rival team

    # Find teams that are of the same sport and also
    # that they don't contain any players from myteam
    sport_teams = select(team for team in TeamEntity
                         if team.sport.name == sport_name)[:]
    print sport_teams, [[player.username for player in team.users]
                        for team in sport_teams]

    if filter_for_matchmaking:
        myteam_names = [player.username for player in myteam.users]
        print myteam_names
        sport_teams = [
            team for team in sport_teams if all(
                player.username not in myteam_names for player in team.users)
        ]
        print sport_teams
        sport_teams.append(myteam)
        num_teams = len(sport_teams)
        api_assert(num_teams > 1, 409,
                   "There are no other teams with all different people!")

    overall_rankings = defaultdict(lambda: 0)

    teams_wlratio = sorted([(team, float(team.wins) / (team.losses or 1))
                            for team in sport_teams],
                           key=lambda t: t[1],
                           reverse=True)
    for i, (team, wlratio) in enumerate(teams_wlratio):
        overall_rankings[team.name] += i
    teams_pointsratio = sorted([(team, team.points_ratio)
                                for team in sport_teams],
                               key=lambda t: t[1],
                               reverse=True)
    for i, (team, points_ratio) in enumerate(teams_pointsratio):
        overall_rankings[team.name] += i

    return overall_rankings
Example #27
0
    def get(self):
        """
        GET to receive list of players in current game

        * `players` array includes ALL players (including gamemaster)
        * `gamemaster` field is useful for highlighting the gamemaster in the UI
        """
        player_name = self.get_current_user()
        player = Player(self.db_conn, "name", player_name)
        game_id = player["current_game_id"]
        api_assert(game_id,
                   400,
                   log_message="You are not currently in"
                   " a game.")

        game = Game(self.db_conn, "game_id", game_id)
        return {"players": game["players"], "gamemaster": game["gamemaster"]}
Example #28
0
    def get(self, id):
        """
        get scheduled alarm.

        * `time`: ISO8601 formatted string. this value means when alarm go off. 
        * `id`: random 32byte hexadecimal string.
        * `sound_id`: random 32byte hexadecimal string.
        * `level`: type of alarm. (i.e. "alarm","notify","warning")
        * `repeat`: number of repeat sound. 0 means "repeats indefinitely".
        """
        job = waker().scheduler.get_job(id)
        if (not job):
            api_assert(False, log_message="no such alarm.")
            return
        job_dict = {"id": job.id, "time": job.next_run_time.isoformat()}
        job_dict.update(job.kwargs)
        return job_dict
Example #29
0
    def get(self):
        """
        GET to receive list of players in current game

        * `players` array includes ALL players (including gamemaster)
        * `gamemaster` field is useful for highlighting the gamemaster in the UI
        """
        player_name = self.get_current_user()
        player = Player(self.db_conn, "name", player_name)
        game_id = player["current_game_id"]
        api_assert(game_id, 400, log_message="You are not currently in"
                   " a game.")

        game = Game(self.db_conn, "game_id", game_id)
        return {
            "players": game["players"],
            "gamemaster": game["gamemaster"]
        }
Example #30
0
    def get(self):
        """
        GET to receive state of current_game

        `winner`: Potential winner of the game, or empty string
        `balls_on_table`: Array of balls still on the table
        """
        player_name = self.get_current_user()
        player = Player(self.db_conn, "name", player_name)
        game_id = player["current_game_id"]
        api_assert(game_id, 400, log_message="You are not currently in"
                   " a game.")

        res = {}
        res["balls_on_table"] = get_balls_on_table(self.db_conn, game_id)
        res["winner"] = get_game_winner(self.db_conn, game_id)

        return res
Example #31
0
    def get(self, game_id):
        """GET game with game_id"""
        with db_session:
            game = GameEntity.get(id=game_id)
            api_assert(game is not None,
                       400,
                       log_message="No such game {} exists!".format(game_id))
            game_dict = game.to_dict(with_collections=True)
        if not game_dict["location"]:
            game_dict["location"] = ""
        if not game_dict["date"]:
            game_dict["date"] = ""
        if not game_dict["cancelled"]:
            game_dict["cancelled"] = False
        if not game_dict["final_score"]:
            game_dict["final_score"] = ""

        return game_dict
    def put(self):
        """
        PUT to create a team

        * `name`
        * `usernames`: list of players in team (INCLUDING YOURSELF!!)
        * `sport`: One of "Basketball" or "Soccer"
        """
        attrs = dict(self.body)

        with db_session:
            if TeamEntity.get(name=attrs['name']):
                raise APIError(
                    409,
                    log_message="Team with name {} already exists!"
                    .format(attrs['name'])
                )

            # Add team mates
            players = []
            for pname in attrs["usernames"]:
                player = PlayerEntity.get(username=pname)
                api_assert(
                    player is not None,
                    400,
                    log_message="No player exists with name {}!".format(pname)
                )
                players.append(player)

            # Get sport
            sport = SportEntity[attrs['sport']]

            # Create team
            team = TeamEntity(
                name=attrs['name'],
                users=players,
                sport=sport,
                wins=0,
                losses=0,
                ties=0,
                points_ratio=0.0
            )

            return {'name': team.name}
Example #33
0
def assert_non_tenant(db, player_name):
    """Assert that player ``player_name`` is not already in a room

    :type  player_name: str
    :raises APIError: If ``player_name`` is already in a room.
    """
    player = get_player(db, player_name)
    player_room = player["current_room"]
    api_assert(
        not player_room,
        409,
        log_message=(
            "{} is already in a room: `{}`. Leave current room"
            " to join a new one.".format(
                player_name,
                player_room
            )
        )
    )
Example #34
0
def create_room(db, room_name, password, owner):
    """Create a new room ``room_name``

    Adds entry for room ``room_name`` to the database.
    :raises APIError: If a room with `room_name` has already
        been created.
    """
    api_assert(not db["rooms"].find_one(name=room_name), 409,
               log_message="Room with name `{}` already exists.".format(
                   room_name))

    db["rooms"].insert(
        {
            "name": room_name,
            "password": password,
            "owner": owner,
            "current_players": ""
        }
    )
    def post(self):
        """(Game host only) Update date and location of game

        * `date`: Must be in YYYY-MM-DD format
        * `location`
        * `id`: ID of game to change
        """
        attrs = dict(self.body)

        with db_session:
            game = GameEntity.get(id=attrs['id'])
            api_assert(
                game is not None,
                400,
                log_message="No such game {} exists!".format(attrs['id'])
            )

            api_assert(
                game.host.username == self.get_current_user(),
                403,
                log_message="Only the host of this game may edit it!"
            )

            try:
                validate_date_text(attrs['date'])
            except ValueError as err:
                raise APIError(
                    400,
                    log_message=str(err)
                )

            game.location = attrs['location']
            game.date = attrs['date']
            commit()

            game_dict = {k: v for k, v in game.to_dict().items() if k in [
                "id",
                "date",
                "location"
            ]}
            game_dict["date"] = str(game_dict["date"])

            return game_dict
Example #36
0
    def get(self):
        """
        GET to receive state of current_game

        `winner`: Potential winner of the game, or empty string
        `balls_on_table`: Array of balls still on the table
        """
        player_name = self.get_current_user()
        player = Player(self.db_conn, "name", player_name)
        game_id = player["current_game_id"]
        api_assert(game_id,
                   400,
                   log_message="You are not currently in"
                   " a game.")

        res = {}
        res["balls_on_table"] = get_balls_on_table(self.db_conn, game_id)
        res["winner"] = get_game_winner(self.db_conn, game_id)

        return res
    def get(self, game_id):
        """GET game with game_id"""
        with db_session:
            game = GameEntity.get(id=game_id)
            api_assert(
                game is not None,
                400,
                log_message="No such game {} exists!".format(game_id)
            )
            game_dict = game.to_dict(with_collections=True)
        if not game_dict["location"]:
            game_dict["location"] = ""
        if not game_dict["date"]:
            game_dict["date"] = ""
        if not game_dict["cancelled"]:
            game_dict["cancelled"] = False
        if not game_dict["final_score"]:
            game_dict["final_score"] = ""

        return game_dict
    def post(self):
        """
        POST the required credentials to get back a cookie

        * `username`: Username
        * `password`: Password
        """
        api_assert(
            self.body['username'],
            400,
            log_message="Username field is empty!"
        )

        with db_session:
            player = PlayerEntity.get(username=self.body['username'])
            api_assert(
                player is not None,
                400,
                log_message="No such player {}".format(self.body['username'])
            )

        password = self.body['password']
        # Check if the given password hashed with the player's known
        #   salt matches the stored password
        password_match = bcrypt.hashpw(
            password.encode(),
            player.salt.encode()
        ) == player.password.encode()
        if password_match:
            self.set_secure_cookie(
                "user",
                self.body['username'],
                self.settings['app_config'].session_timeout_days
            )
            return {"username": player.username}
        else:
            raise APIError(
                400,
                log_message="Bad username/password combo"
            )
Example #39
0
    def put(self):
        """
        PUT to create a team

        * `name`
        * `usernames`: list of players in team (INCLUDING YOURSELF!!)
        * `sport`: One of "Basketball" or "Soccer"
        """
        attrs = dict(self.body)

        with db_session:
            if TeamEntity.get(name=attrs['name']):
                raise APIError(
                    409,
                    log_message="Team with name {} already exists!".format(
                        attrs['name']))

            # Add team mates
            players = []
            for pname in attrs["usernames"]:
                player = PlayerEntity.get(username=pname)
                api_assert(
                    player is not None,
                    400,
                    log_message="No player exists with name {}!".format(pname))
                players.append(player)

            # Get sport
            sport = SportEntity[attrs['sport']]

            # Create team
            team = TeamEntity(name=attrs['name'],
                              users=players,
                              sport=sport,
                              wins=0,
                              losses=0,
                              ties=0,
                              points_ratio=0.0)

            return {'name': team.name}
Example #40
0
 def put(self, id):
     """
     modify alarm schedule. values that do not change are not necessary.
     
     ### input
     * `time`: ISO8601 formatted string. this value means when alarm go off. 
     * `sound_id`: random 32byte hexadecimal string.
     * `level`: type of alarm. (i.e. "alarm","notify","warning")
     * `repeat`: number of repeat sound. 0 means "repeats indefinitely".
     """
     job = waker().scheduler.get_job(id)
     if (not job):
         api_assert(False, log_message="no such alarm.")
         return
     mod_args = {}
     for key in ["sound_id", "level", "repeat"]:
         if (key in self.body):
             mod_args[key] = self.body[key]
         else:
             mod_args[key] = job.kwargs[key]
     mc = music_controller()
     if not mc.exist(mod_args["sound_id"]):
         api_assert(False, log_message="such sound_id is not exists.")
         return
     mod_time = job.next_run_time
     if ("time" in self.body):
         mod_time = iso8601.parse_date(self.body["time"])
         if mod_time < datetime.datetime.now(tz=TIMEZONE):
             api_assert(False,
                        log_message="time must be later than present.")
             return
     job.modify(next_run_time=mod_time, kwargs=mod_args)
Example #41
0
    def post(self):
        """(Game host only) Update date and location of game

        * `date`: Must be in YYYY-MM-DD format
        * `location`
        * `id`: ID of game to change
        """
        attrs = dict(self.body)

        with db_session:
            game = GameEntity.get(id=attrs['id'])
            api_assert(game is not None,
                       400,
                       log_message="No such game {} exists!".format(
                           attrs['id']))

            api_assert(game.host.username == self.get_current_user(),
                       403,
                       log_message="Only the host of this game may edit it!")

            try:
                validate_date_text(attrs['date'])
            except ValueError as err:
                raise APIError(400, log_message=str(err))

            game.location = attrs['location']
            game.date = attrs['date']
            commit()

            game_dict = {
                k: v
                for k, v in game.to_dict().items()
                if k in ["id", "date", "location"]
            }
            game_dict["date"] = str(game_dict["date"])

            return game_dict
Example #42
0
    def post(self):
        """
        POST the required parameters to permanently register a new player

        * `username`: Username of the player
        * `password`: Password for future logins
        """
        player_name = self.body["username"]
        password = self.body["password"]

        with DBLock():
            # Check if a player with the given name already exists
            player_exists = self.db_conn['players'].find_one(name=player_name)
            api_assert(not player_exists, 409,
                       log_message="{} is already registered.".format(player_name))
            # Create a new user/write to DB
            salt = bcrypt.gensalt(rounds=12)
            self.db_conn['players'].insert(
                {
                    "name": player_name,
                    "current_game_id": "",
                    "current_room": "",
                    "balls": "",
                    "salt": salt,
                    "password": bcrypt.hashpw(str(password), salt),
                    "games_won": ""
                }
            )
        # We also do the step of logging the player in after registration
        self.set_secure_cookie(
            "user",
            player_name,
            options.session_timeout_days
        )

        return {"username": player_name}
    def post(self):
        """
        (Game host only) POST to finalize game
        """
        attrs = dict(self.body)

        with db_session:
            game = GameEntity.get(id=attrs['id'])
            api_assert(
                game is not None,
                400,
                log_message="No such game {} exists!".format(attrs['id'])
            )

            api_assert(
                game.host.username == self.get_current_user(),
                403,
                log_message="Only the host of this game may edit it!"
            )

            api_assert(
                game.cancelled is not True,
                400,
                "This game has been cancelled. :("
            )

            api_assert(
                len(game.accepted_players) ==
                len([p for t in game.teams for p in t.users]),
                400,
                "Not everyone has accepted invites for this game yet!"
            )

            team_names = [team.name for team in game.teams]
            team_a = TeamEntity[team_names[0]]
            team_b = TeamEntity[team_names[1]]

            # Make sure final_score has legit team names
            final_score = attrs['final_score']
            for team_name, score in final_score.iteritems():
                api_assert(
                    team_name in team_names,
                    400,
                    "{} is not part of this game!".format(team_name)
                )

            # Set wins, losses and ties
            if final_score[team_a.name] > final_score[team_b.name]:
                team_a.wins += 1
                team_b.losses += 1
            elif final_score[team_a.name] < final_score[team_b.name]:
                team_b.wins += 1
                team_a.losses += 1
            else:
                team_a.ties += 1
                team_b.ties += 1

            # Calculate new points_ratio
            for team1, team2 in [(team_a, team_b), (team_b, team_a)]:
                total_games = team1.wins + team1.losses + team1.ties
                team1.points_ratio = (
                    (
                        team1.points_ratio * max(total_games, 0)
                    ) + (
                        final_score[team1.name] / final_score[team2.name]
                    )
                ) / total_games

            # Set final score
            game.final_score = json.dumps(final_score)

            return "Game results recorded with final score: {}".format(
                json.dumps(final_score)
            )
    def test_api_assert(self):
        """Test exceptions.api_assert"""
        with pytest.raises(exceptions.APIError):
            exceptions.api_assert(False, 400)

        exceptions.api_assert(True, 400)
Example #45
0
    def post(self):
        """POST the required parameter to create a new game;
            only the owner of a room can make this request

        * `nbpp`: Number of balls per player
        """
        game_id = uuid.uuid4().hex
        gamemaster = self.get_current_user()
        player = get_player(self.db_conn, gamemaster)
        room_name = player["current_room"]
        room = get_room(self.db_conn, room_name)
        api_assert(room["owner"] == gamemaster, 403,
                   log_message="You must own a room to create a game.")

        player_names = room["current_players"]
        nplayers = len(player_names)
        nbpp = self.body["nbpp"]

        # Make sure values make sense
        api_assert(nplayers <= nbpp * nplayers <= TOTAL_NUM_BALLS, 400,
                   log_message=("Your math seems to be a little off; "
                                "please pick a `number of balls per player` "
                                "such that each player has at least one ball "
                                "and there are enough to go around for "
                                "everyone.")
                   )

        # Create set of 15 balls, shuffle, and then match to players
        balls = generate_balls(TOTAL_NUM_BALLS)
        shuffle(balls)

        players = {}
        for i in xrange(nplayers):
            _balls = []
            for i in xrange(nbpp):
                _balls.append(balls.pop())
            pname = player_names.pop()
            players[pname] = _balls

        unclaimed_balls = balls[:]

        # Create game
        self.db_conn["games"].insert(
            {
                "game_id": game_id,
                "players": stringify_list(players.keys()),
                "orig_players": stringify_list(players.keys()),
                "unclaimed_balls": stringify_list(unclaimed_balls),
                "orig_unclaimed_balls": stringify_list(unclaimed_balls),
                "gamemaster": gamemaster,
                "winner": None
            }
        )
        # Assign each player their set of balls, set game, leave room
        for name, balls in players.iteritems():
            p = get_player(self.db_conn, name)
            p["current_game_id"] = game_id
            p["balls"] = balls
            p["orig_balls"] = balls
            p["current_room"] = None
        # The room can be deleted
        self.db_conn["rooms"].delete(name=room_name)

        return {"game_id": game_id}