def get_user(self, user_id): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif user_id is None: raise ServiceException("No user_id passed in", 400) if self.user.user_id != user_id and not self.dao.in_same_ladder(self.user.user_id, user_id): raise ServiceException("You are only allowed to access profile information for users who are playing in the same ladder as you", 403) return self.dao.get_user(user_id)
def update_player(self, ladder_id, user_id, player_dict): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif not self.user.admin: raise ServiceException("Only admins can update players", 403) elif ladder_id is None: raise ServiceException("No ladder_id passed in", 400) elif user_id is None: raise ServiceException("No user_id passed in", 400) elif player_dict is None: raise ServiceException("No player passed in", 400) ladder = self.dao.get_ladder(ladder_id) if ladder is None: raise ServiceException(f"No ladder with ID: {ladder_id}", 404) elif not ladder.is_open(): raise ServiceException("You can only update borrowed points after the ladder has started", 403) new_borrowed_points = player_dict.get("borrowed_points") if new_borrowed_points is None: raise ServiceException("New player has no borrowed points", 400) other_players_borrowed_points = [player.borrowed_points for player in self.dao.get_players(ladder_id)] if new_borrowed_points not in other_players_borrowed_points: raise ServiceException("You must assign a value that is already assigned to another player in the ladder", 400) self.dao.update_borrowed_points(ladder_id, user_id, new_borrowed_points) return self.get_players(ladder_id)
def delete_match(self, match_id): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif not self.user.admin: raise ServiceException("Only admins can delete matches", 403) elif match_id is None: raise ServiceException("Null match_id param", 400) match = self.dao.get_match(match_id) if match is not None: self.dao.update_earned_points(match.ladder_id, match.winner_id, -match.winner_points) self.dao.update_earned_points(match.ladder_id, match.loser_id, -match.loser_points) self.dao.delete_match(match_id)
def handle(self, event): try: if event is None or "resource" not in event or "httpMethod" not in event: raise ServiceException("Invalid request. No 'resource', or 'httpMethod' found in the event", 400) resource, method = event["resource"], event["httpMethod"] # These will be used to specify which endpoint was being hit print(f"Received a {method} on {resource}") path_params = event.get("pathParameters", {}) if event.get("pathParameters") is not None else {} # This will be used to get IDs and other parameters from the URL query_params = event.get("queryStringParameters", {}) if event.get("queryStringParameters") is not None else {} # This will be used to get IDs and other parameters from the URL try: body = json.loads(event["body"]) # This will be used for most POSTs and PUTs except (TypeError, KeyError, ValueError): body = None self.manager.validate_token(self.get_token(event)) if resource == "/users/{user_id}" and method == "GET": response_body = self.manager.get_user(path_params.get("user_id")) elif resource == "/users/{user_id}" and method == "PUT": response_body = self.manager.update_user(path_params.get("user_id"), body) elif resource == "/ladders" and method == "GET": response_body = self.manager.get_ladders() elif resource == "/ladders/{ladder_id}/players" and method == "GET": response_body = self.manager.get_players(int(path_params.get("ladder_id"))) elif resource == "/ladders/{ladder_id}/players" and method == "POST": response_body = self.manager.add_player_to_ladder(int(path_params.get("ladder_id")), query_params.get("code")) elif resource == "/ladders/{ladder_id}/players" and method == "PUT": response_body = self.manager.update_player_order(int(path_params.get("ladder_id")), query_params.get("generate_borrowed_points") == "true", body) elif resource == "/ladders/{ladder_id}/players/{user_id}" and method == "PUT": response_body = self.manager.update_player(int(path_params.get("ladder_id")), path_params.get("user_id"), body) elif resource == "/ladders/{ladder_id}/players/{user_id}/matches" and method == "GET": response_body = self.manager.get_matches(int(path_params.get("ladder_id")), path_params.get("user_id")) elif resource == "/ladders/{ladder_id}/matches" and method == "POST": response_body = self.manager.report_match(int(path_params.get("ladder_id")), body) elif resource == "/ladders/{ladder_id}/matches/{match_id}" and method == "PUT": response_body = self.manager.update_match_scores(int(path_params.get("match_id")), body) elif resource == "/ladders/{ladder_id}/matches/{match_id}" and method == "DELETE": self.manager.delete_match(int(path_params.get("match_id"))) response_body = {} else: raise ServiceException("Invalid path: '{} {}'".format(resource, method)) return format_response(response_body) except ServiceException as e: return format_response({"error": e.error_message}, e.status_code)
def update_user(self, user_id, user): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif user_id is None: raise ServiceException("No user_id passed in", 400) elif user is None: raise ServiceException("No user passed in to update", 400) if self.user.user_id != user_id: raise ServiceException("You are only allowed to update your own profile information", 403) # Update the logged in user with all editable information self.user.name = user.get("name") self.user.email = user.get("email") self.user.phone_number = user.get("phone_number") self.user.photo_url = user.get("photo_url") self.user.availability_text = user.get("availability_text") self.dao.update_user(self.user) return self.dao.get_user(user_id)
def add_player_to_ladder(self, ladder_id, code): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif ladder_id is None: raise ServiceException("Null ladder_id param", 400) # Look up ladder if self.dao.get_ladder(ladder_id) is None: raise ServiceException("No ladder with id: '{}'".format(ladder_id), 404) # Look up ladder code real_code = self.dao.get_ladder_code(ladder_id) # If sure that if a code exists, that it matches if real_code is not None and real_code != code: raise ServiceException("The code provided does not match the code of the ladder. If you believe this in error, please contact the ladder's sponsor.", 400) # Create the new player, tying the user to the ladder self.dao.create_player(ladder_id, self.user.user_id) # Return the new list of players in that ladder (which should include the new player) return self.dao.get_players(ladder_id)
def update_match_scores(self, match_id, match_dict): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif not self.user.admin: raise ServiceException("Only admins can update matches", 403) elif match_id is None: raise ServiceException("Null match_id param", 400) elif match_dict is None: raise ServiceException("Null match param", 400) original_match = self.dao.get_match(match_id) if original_match is None: raise ServiceException(f"No match with ID: {match_id}", 404) updated_match = match_from_dict(match_dict) winner_score_diff, loser_score_diff = self.get_score_diff(original_match, updated_match) original_match.winner_set1_score = updated_match.winner_set1_score original_match.loser_set1_score = updated_match.loser_set1_score original_match.winner_set2_score = updated_match.winner_set2_score original_match.loser_set2_score = updated_match.loser_set2_score original_match.winner_set3_score = updated_match.winner_set3_score original_match.loser_set3_score = updated_match.loser_set3_score # Make sure the winner doesn't drop below the min amount. If so, correct the diff new_winner_points = max(original_match.winner_points + winner_score_diff, Match.MIN_WINNER_POINTS) winner_score_diff = new_winner_points - original_match.winner_points original_match.winner_points += winner_score_diff original_match.loser_points += loser_score_diff self.dao.update_match(original_match) self.dao.update_earned_points(original_match.ladder_id, original_match.winner_id, winner_score_diff) self.dao.update_earned_points(original_match.ladder_id, original_match.loser_id, loser_score_diff) return self.transform_matches([original_match], original_match.ladder_id)[0]
def update_player_order(self, ladder_id, generate_borrowed_points: bool, player_dicts): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif not self.user.admin: raise ServiceException("Only admins can update player orders", 403) elif ladder_id is None: raise ServiceException("No ladder_id passed in", 400) elif player_dicts is None: raise ServiceException("No players passed in", 400) ladder = self.dao.get_ladder(ladder_id) if ladder is None: raise ServiceException(f"No ladder with ID: {ladder_id}", 404) elif ladder.is_open(): raise ServiceException("You can only update player order before the ladder has started", 403) user_ids_with_order = [[player_dict["user"]["user_id"], i + 1] for i, player_dict in enumerate(reversed(player_dicts))] self.dao.update_player_order(ladder_id, user_ids_with_order) if generate_borrowed_points: user_ids_with_borrowed_points = [[user_id, order * ladder.weeks_for_borrowed_points] for user_id, order in user_ids_with_order] self.dao.update_all_borrowed_points(ladder_id, user_ids_with_borrowed_points) return self.dao.get_players(ladder_id)
def report_match(self, ladder_id, match_dict): if self.user is None: raise ServiceException("Unable to authenticate", 401) elif ladder_id is None: raise ServiceException("Null ladder_id param", 400) elif match_dict is None: raise ServiceException("Null match param", 400) # Look up ladder ladder = self.dao.get_ladder(ladder_id) if ladder is None: raise ServiceException("No ladder with id: '{}'".format(ladder_id), 404) # Check that the ladder is currently active if not ladder.is_open(): raise ServiceException("This ladder is not currently open. You can only report matches between the ladder's start and end dates", 400) # Deserialize and validate that the rest of the match is set up properly (valid set scores and players) match = match_from_dict(match_dict) # Set match date to right now (to avoid issues with device times being changed) match.match_date = datetime.now(timezone("US/Mountain")) # Look up players in ladder winner = self.dao.get_player(ladder_id, match.winner_id) if winner is None: raise ServiceException("No user with id: '{}'".format(match.winner_id), 400) loser = self.dao.get_player(ladder_id, match.loser_id) if loser is None: raise ServiceException("No user with id: '{}'".format(match.loser_id), 400) if ladder.distance_penalty_on and abs(winner.ranking - loser.ranking) > ManagerImpl.INVALID_RANKING_DISTANCE: raise ServiceException("Players are too far apart in the rankings to challenge one another", 400) # Get all matches for this ladder (to enforce some of the rules below) ladder_matches = self.dao.get_matches(ladder_id) # Find out if either player has already played a match today if len([m for m in ladder_matches if m.has_players(match.winner_id) and m.played_today()]) > 0: raise ServiceException("Reported winner has already played a match today. Only one match can be played each day.", 400) if len([m for m in ladder_matches if m.has_players(match.loser_id) and m.played_today()]) > 0: raise ServiceException("Reported loser has already played a match today. Only one match can be played each day.", 400) # Find out if the players have already played the maximum amount of times matches_between_players = [m for m in ladder_matches if m.has_players(match.winner_id, match.loser_id)] if len(matches_between_players) >= ManagerImpl.MAX_MATCHES_BETWEEN_PLAYERS: raise ServiceException("Players have already played {} times.".format(ManagerImpl.MAX_MATCHES_BETWEEN_PLAYERS), 400) # Update the scores of the players match.winner_points, match.loser_points = match.calculate_scores(winner.ranking, loser.ranking, ladder.distance_penalty_on) print("---MATCH_REPORTING--- {} ({}) vs {} ({}): {}-{}, {}-{}, {}-{}. Winner Score: {}. Loser Score: {}".format( winner.user.name, winner.ranking, loser.user.name, loser.ranking, match.winner_set1_score, match.loser_set1_score, match.winner_set2_score, match.loser_set2_score, match.winner_set3_score, match.loser_set3_score, match.winner_points, match.loser_points )) self.dao.update_earned_points(match.ladder_id, match.winner_id, match.winner_points) self.dao.update_earned_points(match.ladder_id, match.loser_id, match.loser_points) # Save the match to the database (which will assign it a new match_id) match = self.dao.create_match(match) # Attach winners and losers to the match return self.transform_matches([match], ladder_id)[0]