def activation_code_by_code_delete(code: str) -> Response: """ Delete an activation code based on a unique code. :param code: The activation code to delete. :return: A response object for the DELETE API request. """ existing_code: Code = ActivationCodeDao.get_activation_code(code=code) if existing_code is None: response = jsonify({ 'self': f'/v2/activation_code/{code}', 'deleted': False, 'error': 'there is no existing activation code with this code' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') jwt_email = jwt_claims.get('email') if existing_code.email == jwt_email: current_app.logger.info( f'User {jwt_username} is deleting activation code {existing_code.activation_code}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to delete activation code {existing_code.activation_code}.' ) response = jsonify({ 'self': f'/v2/activation_code/{code}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to delete activation code {existing_code.activation_code}.' }) response.status_code = 400 return response is_deleted = ActivationCodeDao.delete_code(activation_code=code) if is_deleted: response = jsonify({ 'self': f'/v2/activation_code/{code}', 'deleted': True }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/activation_code/{code}', 'deleted': False, 'error': 'failed to delete the activation code' }) response.status_code = 500 return response
def comment_with_id_delete(comment_id): """ Delete an existing comment. :param comment_id: The unique identifier for a comment. :return: A response object for the DELETE API request. """ existing_comment: Comment = CommentDao.get_comment_by_id( comment_id=comment_id) if existing_comment is None: response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'deleted': False, 'error': 'there is no existing comment with this id' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if existing_comment.username == jwt_username: current_app.logger.info( f'User {jwt_username} is deleting a comment with id {existing_comment.comment_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to delete a comment with id {existing_comment.comment_id}.' ) response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to delete a comment with id {existing_comment.comment_id}.' }) response.status_code = 400 return response is_deleted = CommentDao.delete_comment_by_id(comment_id=comment_id) if is_deleted: response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'deleted': False, 'error': 'failed to delete the comment' }) response.status_code = 500 return response
def user_memberships_by_username_put(username) -> Response: """ Update the team and group memberships of a user. :param username: Username that uniquely identifies a user. :return: A response object for the PUT API request. """ jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if username == jwt_username: current_app.logger.info( f'User {jwt_username} is updating their memberships.') else: current_app.logger.info( f'User {jwt_username} is not authorized to update the memberships of user {username}.' ) response = jsonify({ 'self': f'/v2/users/memberships/{username}', 'updated': False, 'error': f'User {jwt_username} is not authorized to update the memberships of user {username}.' }) response.status_code = 400 return response membership_data: dict = request.get_json() teams_joined = membership_data.get('teams_joined') teams_left = membership_data.get('teams_left') groups_joined = membership_data.get('groups_joined') groups_left = membership_data.get('groups_left') committed: bool = False try: committed = TeamMemberDao.update_user_memberships( username, teams_joined, teams_left, groups_joined, groups_left) except SQLAlchemyError as e: current_app.logger.error(str(e)) if committed: response = jsonify({ 'self': f'/v2/users/memberships/{username}', 'updated': True, }) response.status_code = 201 return response else: response = jsonify({ 'self': f'/v2/users/memberships/{username}', 'updated': False, 'error': "failed to update the user's memberships" }) response.status_code = 500 return response
def user_update_last_login_by_username_put(username) -> Response: """ Change the last login date of a user with a given username. :param username: Username that uniquely identifies a user. :return: A response object for the PUT API request. """ jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if username == jwt_username: current_app.logger.info(f'User {jwt_username} logged in.') else: current_app.logger.info( f'User {jwt_username} is not authorized to update the last login date of user {username}.' ) response = jsonify({ 'self': f'/v2/users/{username}/update_last_login', 'last_login_updated': False, 'error': f'User {jwt_username} is not authorized to update the last login date of user {username}.' }) response.status_code = 400 return response last_login_updated: bool = UserDao.update_user_last_login(username) if last_login_updated: response = jsonify({ 'self': f'/v2/users/{username}/update_last_login', 'last_login_updated': True }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/users/{username}/update_last_login', 'last_login_updated': False, 'error': 'an unexpected error occurred updating the users last login date' }) response.status_code = 500 return response
def comment_with_id_soft_delete(comment_id): """ Soft delete a comment based on a unique id. :param comment_id: Unique identifier for a comment. :return: A response object for the DELETE API request. """ existing_comment: Comment = CommentDao.get_comment_by_id( comment_id=comment_id) if existing_comment is None: response = jsonify({ 'self': f'/v2/comments/soft/{comment_id}', 'deleted': False, 'error': 'there is no existing comment with this id' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if existing_comment.username == jwt_username: current_app.logger.info( f'User {jwt_username} is soft deleting a comment with id {existing_comment.comment_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to soft delete a comment with id {existing_comment.comment_id}.' ) response = jsonify({ 'self': f'/v2/comments/soft/{comment_id}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to soft delete a comment with id ' f'{existing_comment.comment_id}.' }) response.status_code = 400 return response # Update the comment model to reflect the soft delete existing_comment.deleted = True existing_comment.deleted_date = datetime.now() existing_comment.deleted_app = 'saints-xctf-api' existing_comment.modified_date = datetime.now() existing_comment.modified_app = 'saints-xctf-api' is_deleted: bool = CommentDao.soft_delete_comment(existing_comment) if is_deleted: response = jsonify({ 'self': f'/v2/comments/soft/{comment_id}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/comments/soft/{comment_id}', 'deleted': False, 'error': 'failed to soft delete the comment' }) response.status_code = 500 return response
def comment_with_id_put(comment_id): """ Update an existing comment. :param comment_id: The unique identifier for a comment. :return: A response object for the PUT API request. """ old_comment: Comment = CommentDao.get_comment_by_id(comment_id=comment_id) if old_comment is None: response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'updated': False, 'comment': None, 'error': 'there is no existing comment with this id' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if old_comment.username == jwt_username: current_app.logger.info( f'User {jwt_username} is updating a comment with id {old_comment.comment_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to update a comment with id {old_comment.comment_id}.' ) response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'updated': False, 'comment': None, 'error': f'User {jwt_username} is not authorized to update a comment with id {old_comment.comment_id}.' }) response.status_code = 400 return response comment_data: dict = request.get_json() new_comment = Comment(comment_data) if old_comment != new_comment: new_comment.modified_date = datetime.now() new_comment.modified_app = 'saints-xctf-api' is_updated = CommentDao.update_comment(comment=new_comment) if is_updated: updated_comment: Comment = CommentDao.get_comment_by_id( comment_id=new_comment.comment_id) updated_comment_dict: dict = CommentData(updated_comment).__dict__ response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'updated': True, 'comment': updated_comment_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'updated': False, 'comment': None, 'error': 'the comment failed to update' }) response.status_code = 500 return response else: response = jsonify({ 'self': f'/v2/comments/{comment_id}', 'updated': False, 'comment': None, 'error': 'the comment submitted is equal to the existing comment with the same id' }) response.status_code = 400 return response
def log_feed_get(filter_by, bucket, limit, offset) -> Response: """ Get a list of exercise logs based on certain filters. :param filter_by: The filtering mechanism for the exercise logs. You can filter by user (username) or group (group_name). :param bucket: The bucket to filter by (either a username or a group name) :param limit: The maximum number of logs to return :param offset: The number of logs to skip from the results of this filter before returning :return: A response object for the GET API request. """ logs: ResultProxy = None count: int = 0 limit = int(limit) offset = int(offset) jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if filter_by == 'group' or filter_by == 'groups': logs = LogDao.get_group_log_feed(group_id=int(bucket), limit=limit, offset=offset) count = LogDao.get_group_log_feed_count(group_id=int(bucket)).first()['count'] elif filter_by == 'user' or filter_by == 'users' or filter_by == 'username': logs = LogDao.get_user_log_feed(username=bucket, limit=limit, offset=offset) count = LogDao.get_user_log_feed_count(username=bucket).first()['count'] elif filter_by == 'all': logs = LogDao.get_log_feed(limit=limit, offset=offset, username=jwt_username) count = LogDao.get_log_feed_count().first()['count'] pages = int((count - 1) / limit) + 1 # Generate LogFeed API URLs self_url = f'/v2/log_feed/{filter_by}/{bucket}/{limit}/{offset}' prev_offset = offset - limit if prev_offset >= 0: prev_url = f'/v2/log_feed/{filter_by}/{bucket}/{limit}/{prev_offset}' else: prev_url = None if logs is None or logs.rowcount == 0: response = jsonify({ 'self': self_url, 'next': None, 'prev': prev_url, 'logs': None, 'pages': 0, 'error': 'no logs found in this feed' }) response.status_code = 500 return response else: log_list = [] for log in logs: comments: list = CommentDao.get_comments_by_log_id(log.log_id) comments = [CommentData(comment).__dict__ for comment in comments] log_list.append({ 'log_id': log.log_id, 'username': log.username, 'first': log.first, 'last': log.last, 'name': log.name, 'location': log.location, 'date': str(log.date) if log.date is not None else None, 'type': log.type, 'distance': log.distance, 'metric': log.metric, 'miles': log.miles, 'time': str(log.time) if log.time is not None else None, 'pace': str(log.pace) if log.pace is not None else None, 'feel': log.feel, 'description': log.description, 'comments': comments }) next_url = f'/v2/log_feed/{filter_by}/{bucket}/{limit}/{offset + limit}' response = jsonify({ 'self': self_url, 'next': next_url, 'prev': prev_url, 'logs': log_list, 'pages': pages, }) response.status_code = 200 return response
def notification_by_id_delete(notification_id) -> Response: """ Hard delete an existing notification with a given unique ID. :param notification_id: Unique identifier for a user's notification. :return: A response object for the DELETE API request. """ existing_notification: Notification = NotificationDao.get_notification_by_id( notification_id=notification_id) if existing_notification is None: response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'deleted': False, 'error': 'There is no existing notification with this id.' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if existing_notification.username == jwt_username: current_app.logger.info( f'User {jwt_username} is deleting their notification with id {existing_notification.notification_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to delete a notification sent to {existing_notification.username}.' ) response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to delete a notification sent to ' f'{existing_notification.username}.' }) response.status_code = 400 return response is_deleted = NotificationDao.delete_notification_by_id( notification_id=notification_id) if is_deleted: response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'deleted': False, 'error': 'failed to delete the notification' }) response.status_code = 500 return response
def user_by_username_put(username) -> Response: """ Update an existing user with a given username. :param username: Username that uniquely identifies a user. :return: A response object for the PUT API request. """ old_user: User = UserDao.get_user_by_username(username=username) if old_user is None: response = jsonify({ 'self': f'/v2/users/{username}', 'updated': False, 'user': None, 'error': 'there is no existing user with this username' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if username == jwt_username: current_app.logger.info( f'User {jwt_username} is updating their user details.') else: current_app.logger.info( f'User {jwt_username} is not authorized to update user {username}.' ) response = jsonify({ 'self': f'/v2/users/{username}', 'updated': False, 'user': None, 'error': f'User {jwt_username} is not authorized to update user {username}.' }) response.status_code = 400 return response user_data: dict = request.get_json() new_user = User(user_data) if new_user != old_user: is_updated = UserDao.update_user(username, new_user) if is_updated: updated_user = UserDao.get_user_by_username(username) updated_user_dict: dict = UserData(updated_user).__dict__ if updated_user_dict.get('profilepic') is not None: try: updated_user_dict['profilepic'] = updated_user_dict[ 'profilepic'].decode('utf-8') except AttributeError: pass response = jsonify({ 'self': f'/v2/users/{username}', 'updated': True, 'user': updated_user_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/users/{username}', 'updated': False, 'user': None, 'error': 'the user failed to update' }) response.status_code = 500 return response else: response = jsonify({ 'self': f'/v2/users/{username}', 'updated': False, 'user': None, 'error': 'the user submitted is equal to the existing user with the same username' }) response.status_code = 400 return response
def logs_post() -> Response: """ Create a new exercise log. :return: A response object for the POST API request. """ log_data: dict = request.get_json() if log_data is None: response = jsonify({ 'self': f'/v2/logs', 'added': False, 'log': None, 'error': "the request body isn't populated" }) response.status_code = 400 return response log_to_add: Log = Log(log_data) jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if log_to_add.username == jwt_username: current_app.logger.info(f'User {jwt_username} is uploading a new exercise log.') else: current_app.logger.info( f'User {jwt_username} is not authorized to upload an exercise log for user {log_to_add.username}.' ) response = jsonify({ 'self': f'/v2/logs', 'added': False, 'log': None, 'error': f'User {jwt_username} is not authorized to upload an exercise log for user {log_to_add.username}.' }) response.status_code = 400 return response if None in [log_to_add.username, log_to_add.first, log_to_add.last, log_to_add.date, log_to_add.type, log_to_add.feel]: response = jsonify({ 'self': f'/v2/logs', 'added': False, 'log': None, 'error': "'username', 'first', 'last', 'date', 'type', and 'feel' are required fields" }) response.status_code = 400 return response # Compute pace and miles based on time, metric, and distance if log_to_add.distance and log_to_add.metric: log_to_add.miles = to_miles(log_to_add.metric, log_to_add.distance) log_to_add.pace = calculate_mile_pace(log_to_add.miles, log_to_add.time) log_to_add.time_created = datetime.now() log_to_add.created_date = datetime.now() log_to_add.created_app = 'saints-xctf-api' log_to_add.created_user = None log_to_add.modified_date = None log_to_add.modified_app = None log_to_add.modified_user = None log_to_add.deleted_date = None log_to_add.deleted_app = None log_to_add.deleted_user = None log_to_add.deleted = False log_added_successfully = LogDao.add_log(new_log=log_to_add) if log_added_successfully: log_added: Log = LogDao.get_log_by_id(log_id=log_to_add.log_id) log_dict: dict = LogData(log_added).__dict__ if log_dict.get('date') is not None: log_dict['date'] = str(log_dict['date']) if log_dict.get('time') is not None: log_dict['time'] = str(log_dict['time']) if log_dict.get('pace') is not None: log_dict['pace'] = str(log_dict['pace']) response = jsonify({ 'self': '/v2/logs', 'added': True, 'log': log_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': '/v2/logs', 'added': False, 'log': None, 'error': 'failed to create a new log' }) response.status_code = 500 return response
def group_members_by_group_id_and_username_delete(group_id: str, username: str) -> Response: """ Soft delete a group membership. The membership is identified by a group's identifier and a user's username. :param group_id: Unique id which identifies a group within a team. :param username: Unique name for a user. :return: A response object for the DELETE API request. """ jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') group_member: GroupMember = GroupMemberDao.get_group_member( group_id=int(group_id), username=jwt_username) if group_member is not None and group_member.user == 'admin' and group_member.status == 'accepted': current_app.logger.info( f'Admin user {jwt_username} is deleting the group membership for user {username} in group with id ' f'{group_id}.') else: current_app.logger.info( f'User {jwt_username} is not authorized to delete the group membership for user {username} in group with ' f'id {group_id}.') response = jsonify({ 'self': f'/v2/groups/members/{group_id}/{username}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to delete the group membership for user {username} in ' f'group with id {group_id}.' }) response.status_code = 400 return response membership_deleted = GroupMemberDao.soft_delete_group_member( int(group_id), username) if membership_deleted: team: Team = TeamDao.get_team_by_group_id(int(group_id)) user_groups: ResultProxy = GroupMemberDao.get_user_groups_in_team( username, team.name) # If the user has no more group memberships in this team, remove them from the team. if user_groups.rowcount == 0: TeamMemberDao.update_user_memberships(username=username, teams_joined=[], teams_left=[team.name], groups_joined=[], groups_left=[]) response = jsonify({ 'self': f'/v2/groups/members/{group_id}/{username}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/groups/members/{group_id}/{username}', 'deleted': False, 'error': 'Failed to delete the group membership.' }) response.status_code = 500 return response
def group_members_by_group_id_and_username_put(group_id: str, username: str) -> Response: """ Update a group membership. The membership is identified by a group's identifier and a user's username. :param group_id: Unique id which identifies a group within a team. :param username: Unique name for a user. :return: A response object for the PUT API request. """ jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') group_member: GroupMember = GroupMemberDao.get_group_member( group_id=int(group_id), username=jwt_username) if group_member is not None and group_member.user == 'admin' and group_member.status == 'accepted': current_app.logger.info( f'Admin user {jwt_username} is updating the group membership for user {username} in group with id ' f'{group_id}.') else: current_app.logger.info( f'User {jwt_username} is not authorized to update the group membership for user {username} in group with ' f'id {group_id}.') response = jsonify({ 'self': f'/v2/groups/members/{group_id}/{username}', 'updated': False, 'group_member': None, 'error': f'User {jwt_username} is not authorized to update the group membership for user {username} in ' f'group with id {group_id}.' }) response.status_code = 400 return response group_member_data: dict = request.get_json() status = group_member_data.get('status') user = group_member_data.get('user') is_updated = GroupMemberDao.update_group_member(int(group_id), username, status, user) if is_updated: team: Team = TeamDao.get_team_by_group_id(int(group_id)) team_membership: ResultProxy = TeamMemberDao.get_user_team_membership( username=username, team_name=team.name) if team_membership.rowcount > 0: for membership in team_membership: if membership.user != 'accepted': TeamMemberDao.accept_user_team_membership( username=username, team_name=team.name, updating_username=jwt_username) updated_group_member = GroupMemberDao.get_group_member( int(group_id), username) updated_group_member_dict: dict = GroupMemberData( updated_group_member).__dict__ response = jsonify({ 'self': f'/v2/groups/members/{group_id}/{username}', 'updated': True, 'group_member': updated_group_member_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/groups/members/{group_id}/{username}', 'updated': False, 'group_member': None, 'error': 'The group membership failed to update.' }) response.status_code = 500 return response
def group_by_id_put(group_id: str) -> Response: """ Update a group based on the unique group id. :param group_id: Unique id which identifies a group. :return: A response object for the PUT API request. """ old_group = GroupDao.get_group_by_id(int(group_id)) jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') group_member: GroupMember = GroupMemberDao.get_group_member( group_id=int(group_id), username=jwt_username) if group_member is not None and group_member.user == 'admin' and group_member.status == 'accepted': current_app.logger.info( f'Admin user {jwt_username} is updating a group with id {group_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to update a group with id {group_id}.' ) response = jsonify({ 'self': f'/v2/groups/{group_id}', 'updated': False, 'group': None, 'error': f'User {jwt_username} is not authorized to update a group with id {group_id}.' }) response.status_code = 400 return response if old_group is None: response = jsonify({ 'self': f'/v2/groups/{group_id}', 'updated': False, 'group': None, 'error': 'There is no existing group with this id.' }) response.status_code = 400 return response group_data: dict = request.get_json() new_group = Group(group_data) if new_group != old_group: new_group.modified_date = datetime.now() new_group.modified_app = 'saints-xctf-api' is_updated = GroupDao.update_group(group=new_group) if is_updated: updated_group = GroupDao.get_group_by_id(int(group_id)) updated_group_dict: dict = GroupData(updated_group).__dict__ response = jsonify({ 'self': f'/v2/groups/{group_id}', 'updated': True, 'group': updated_group_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/groups/{group_id}', 'updated': False, 'group': None, 'error': 'The group failed to update.' }) response.status_code = 500 return response else: response = jsonify({ 'self': f'/v2/groups/{group_id}', 'updated': False, 'group': None, 'error': 'The group submitted is equal to the existing group with the same id.' }) response.status_code = 400 return response
def group_by_group_name_put(team_name: str, group_name: str) -> Response: """ Update a group in the database. :param team_name: Unique name which identifies a team. :param group_name: Unique name which identifies a group within a team. :return: A response object for the PUT API request. """ old_group_row: Optional[RowProxy] = GroupDao.get_group( team_name=team_name, group_name=group_name) if old_group_row is None: response = jsonify({ 'self': f'/v2/groups/{team_name}/{group_name}', 'updated': False, 'group': None, 'error': 'there is no existing group with this name' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') group_member: GroupMember = GroupMemberDao.get_group_member_by_group_name( team_name=team_name, group_name=group_name, username=jwt_username) if group_member is not None and group_member.user == 'admin' and group_member.status == 'accepted': current_app.logger.info( f'Admin user {jwt_username} is updating a group with name {group_name} in team {team_name}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to update a group with name {group_name} in team {team_name}.' ) response = jsonify({ 'self': f'/v2/groups/{team_name}/{group_name}', 'updated': False, 'group': None, 'error': f'User {jwt_username} is not authorized to update a group with name {group_name} in team ' f'{team_name}.' }) response.status_code = 400 return response old_group_dict = {key: value for key, value in old_group_row.items()} old_group = Group(old_group_dict) group_data: dict = request.get_json() new_group = Group(group_data) if old_group != new_group: new_group.modified_date = datetime.now() new_group.modified_app = 'saints-xctf-api' is_updated = GroupDao.update_group(group=new_group) if is_updated: updated_group_row: Optional[RowProxy] = GroupDao.get_group( team_name=team_name, group_name=new_group.group_name) updated_group_dict = { key: value for key, value in updated_group_row.items() } response = jsonify({ 'self': f'/v2/groups/{team_name}/{group_name}', 'updated': True, 'group': updated_group_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/groups/{team_name}/{group_name}', 'updated': False, 'group': None, 'error': 'the group failed to update' }) response.status_code = 500 return response else: response = jsonify({ 'self': f'/v2/groups/{team_name}/{group_name}', 'updated': False, 'group': None, 'error': 'the group submitted is equal to the existing group with the same name' }) response.status_code = 400 return response
def activation_code_by_code_soft_delete(code: str) -> Response: """ Soft delete an activation code based on a unique code. :param code: The activation code to delete. :return: A response object for the DELETE API request. """ existing_code: Code = ActivationCodeDao.get_activation_code(code=code) if existing_code is None: response = jsonify({ 'self': f'/v2/activation_code/soft/{code}', 'deleted': False, 'error': 'there is no existing activation code with this code' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') jwt_email = jwt_claims.get('email') if existing_code.email == jwt_email: current_app.logger.info( f'User {jwt_username} is soft deleting activation code {existing_code.activation_code}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to soft delete activation code {existing_code.activation_code}.' ) response = jsonify({ 'self': f'/v2/activation_code/soft/{code}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to soft delete activation code ' f'{existing_code.activation_code}.' }) response.status_code = 400 return response # Update the activation code model to reflect the soft delete existing_code.deleted = True existing_code.deleted_date = datetime.now() existing_code.deleted_app = 'saints-xctf-api' existing_code.modified_date = datetime.now() existing_code.modified_app = 'saints-xctf-api' is_deleted = ActivationCodeDao.soft_delete_code(existing_code) if is_deleted: response = jsonify({ 'self': f'/v2/activation_code/soft/{code}', 'deleted': True }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/activation_code/soft/{code}', 'deleted': False, 'error': 'failed to soft delete the activation code' }) response.status_code = 500 return response
def forgot_password_get(username) -> Response: """ Retrieve an existing forgot password code for a specific user. :param username: Uniquely identifies a user. :return: JSON with the resulting Forgot Password object and relevant metadata. """ user: User = UserDao.get_user_by_username(username=username) # If the user cant be found, try searching the email column in the database if user is None: email = username user: User = UserDao.get_user_by_email(email=email) if user is None: response = jsonify({ 'self': f'/v2/forgot_password/{username}', 'forgot_password_codes': [], 'error': 'There is no user associated with this username/email.' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if user.username == jwt_username: current_app.logger.info( f'User {jwt_username} is accessing their forgot password codes.') else: current_app.logger.info( f'User {jwt_username} is not authorized to access forgot password codes for user {user.username}.' ) response = jsonify({ 'self': f'/v2/forgot_password/{username}', 'created': False, 'error': f'User {jwt_username} is not authorized to access forgot password codes for user {user.username}.' }) response.status_code = 400 return response forgot_password_codes: ResultProxy = ForgotPasswordDao.get_forgot_password_codes( username=user.username) if forgot_password_codes is None: response = jsonify({ 'self': f'/v2/forgot_password/{username}', 'forgot_password_codes': [], 'error': 'This user has no forgot password codes.' }) response.status_code = 400 return response else: forgot_password_list = [] for code in forgot_password_codes: fpw = ForgotPasswordData(None) fpw.forgot_code = code[0] fpw.username = code[1] fpw.expires = code[2] fpw.deleted = code[3] forgot_password_list.append(fpw.__dict__) response = jsonify({ 'self': f'/v2/forgot_password/{username}', 'forgot_password_codes': forgot_password_list, }) response.status_code = 200 return response
def log_by_id_put(log_id) -> Response: """ Update an existing exercise log based on a unique ID. :param log_id: The unique identifier for an exercise log. :return: A response object for the PUT API request. """ old_log: Log = LogDao.get_log_by_id(log_id=log_id) if old_log is None: response = jsonify({ 'self': f'/v2/logs/{log_id}', 'updated': False, 'log': None, 'error': 'there is no existing log with this id' }) response.status_code = 400 return response log_data: dict = request.get_json() new_log = Log(log_data) jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if old_log.username == jwt_username: current_app.logger.info(f'User {jwt_username} is updating their exercise log with id {log_id}.') else: current_app.logger.info( f'User {jwt_username} is not authorized to update an exercise log owned by user {old_log.username}.' ) response = jsonify({ 'self': f'/v2/logs/{log_id}', 'updated': False, 'log': None, 'error': f'User {jwt_username} is not authorized to update an exercise log owned by user ' f'{old_log.username}.' }) response.status_code = 400 return response if new_log.distance and new_log.metric: new_log.miles = to_miles(new_log.metric, new_log.distance) new_log.pace = calculate_mile_pace(new_log.miles, new_log.time) if old_log != new_log: new_log.modified_date = datetime.now() new_log.modified_app = 'saints-xctf-api' is_updated: bool = LogDao.update_log(new_log) if is_updated: updated_log: Log = LogDao.get_log_by_id(log_id=new_log.log_id) log_dict: dict = LogData(updated_log).__dict__ if log_dict.get('date') is not None: log_dict['date'] = str(log_dict['date']) if log_dict.get('time') is not None: log_dict['time'] = str(log_dict['time']) if log_dict.get('pace') is not None: log_dict['pace'] = str(log_dict['pace']) response = jsonify({ 'self': f'/v2/logs/{log_id}', 'updated': True, 'log': log_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/logs/{log_id}', 'updated': False, 'log': None, 'error': 'the log failed to update' }) response.status_code = 500 return response else: response = jsonify({ 'self': f'/v2/logs/{log_id}', 'updated': False, 'log': None, 'error': 'the log submitted is equal to the existing log with the same id' }) response.status_code = 400 return response
def log_by_id_delete(log_id) -> Response: """ Delete an existing exercise log based on a unique ID. :param log_id: The unique identifier for an exercise log. :return: A response object for the DELETE API request. """ existing_log: Log = LogDao.get_log_by_id(log_id=log_id) if existing_log is None: response = jsonify({ 'self': f'/v2/logs/{log_id}', 'deleted': False, 'error': 'There is no existing exercise log with this id.' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if existing_log.username == jwt_username: current_app.logger.info(f'User {jwt_username} is deleting their exercise log with id {log_id}.') else: current_app.logger.info( f'User {jwt_username} is not authorized to delete an exercise log owned by user {existing_log.username}.' ) response = jsonify({ 'self': f'/v2/logs/{log_id}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to delete an exercise log owned by user ' f'{existing_log.username}.' }) response.status_code = 400 return response are_comments_deleted = CommentDao.delete_comments_by_log_id(log_id=log_id) if not are_comments_deleted: response = jsonify({ 'self': f'/v2/logs/{log_id}', 'deleted': False, 'error': 'failed to delete the comments on this log' }) response.status_code = 500 return response is_log_deleted = LogDao.delete_log(log_id=log_id) if is_log_deleted: response = jsonify({ 'self': f'/v2/logs/{log_id}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/logs/{log_id}', 'deleted': False, 'error': 'failed to delete the log' }) response.status_code = 500 return response
def user_by_username_soft_delete(username) -> Response: """ Soft delete an existing user with a given username. :param username: Username that uniquely identifies a user. :return: A response object for the DELETE API request. """ jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if username == jwt_username: current_app.logger.info( f'User {jwt_username} is soft deleting their user.') else: current_app.logger.info( f'User {jwt_username} is not authorized to soft delete user {username}.' ) response = jsonify({ 'self': f'/v2/users/soft/{username}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to soft delete user {username}.' }) response.status_code = 400 return response existing_user: User = UserDao.get_user_by_username(username=username) if existing_user is None: response = jsonify({ 'self': f'/v2/users/soft/{username}', 'deleted': False, 'error': 'there is no existing user with this username' }) response.status_code = 400 return response # Update the user model to reflect the soft delete existing_user.deleted = True existing_user.deleted_date = datetime.now() existing_user.deleted_app = 'saints-xctf-api' existing_user.modified_date = datetime.now() existing_user.modified_app = 'saints-xctf-api' is_deleted: bool = UserDao.soft_delete_user(existing_user) if is_deleted: response = jsonify({ 'self': f'/v2/users/soft/{username}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/users/soft/{username}', 'deleted': False, 'error': 'failed to soft delete the user' }) response.status_code = 500 return response
def log_by_id_soft_delete(log_id) -> Response: """ Soft delete an exercise log based on a unique id. :param log_id: Unique identifier for an exercise log. :return: A response object for the DELETE API request. """ existing_log: Log = LogDao.get_log_by_id(log_id=log_id) if existing_log is None: response = jsonify({ 'self': f'/v2/logs/soft/{log_id}', 'deleted': False, 'error': 'there is no existing exercise log with this id' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if existing_log.username == jwt_username: current_app.logger.info(f'User {jwt_username} is soft deleting their exercise log with id {log_id}.') else: current_app.logger.info( f'User {jwt_username} is not authorized to soft delete an exercise log owned by user ' f'{existing_log.username}.' ) response = jsonify({ 'self': f'/v2/logs/{log_id}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to soft delete an exercise log owned by user ' f'{existing_log.username}.' }) response.status_code = 400 return response if existing_log.deleted: response = jsonify({ 'self': f'/v2/logs/soft/{log_id}', 'deleted': False, 'error': 'this exercise log is already soft deleted' }) response.status_code = 400 return response # Update the comment model to reflect the soft delete existing_log.deleted = True existing_log.deleted_date = datetime.now() existing_log.deleted_app = 'saints-xctf-api' existing_log.modified_date = datetime.now() existing_log.modified_app = 'saints-xctf-api' is_deleted: bool = LogDao.soft_delete_log(existing_log) if is_deleted: response = jsonify({ 'self': f'/v2/logs/soft/{log_id}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/logs/soft/{log_id}', 'deleted': False, 'error': 'failed to soft delete the log' }) response.status_code = 500 return response
def notification_by_id_put(notification_id) -> Response: """ Update an existing notification based on its identifier. :param notification_id: Unique identifier for a user's notification. :return: A response object for the PUT API request. """ notification_id = int(notification_id) old_notification = NotificationDao.get_notification_by_id( notification_id=notification_id) if old_notification is None: response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'updated': False, 'notification': None, 'error': 'there is no existing notification with this id' }) response.status_code = 400 return response notification_data: dict = request.get_json() new_notification = Notification(notification_data) new_notification.notification_id = notification_id jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if old_notification.username == jwt_username: current_app.logger.info( f'User {jwt_username} is updating their notification with id {new_notification.notification_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to update a notification sent to {old_notification.username}.' ) response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'updated': False, 'notification': None, 'error': f'User {jwt_username} is not authorized to update a notification sent to ' f'{old_notification.username}.' }) response.status_code = 400 return response if old_notification != new_notification: new_notification.modified_date = datetime.now() new_notification.modified_app = 'saints-xctf-api' is_updated = NotificationDao.update_notification( notification=new_notification) if is_updated: updated_notification = NotificationDao.get_notification_by_id( notification_id=notification_id) notification_dict = NotificationData(updated_notification).__dict__ notification_dict['time'] = str(notification_dict['time']) response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'updated': True, 'notification': notification_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'updated': False, 'notification': None, 'error': 'the notification failed to update' }) response.status_code = 500 return response else: response = jsonify({ 'self': f'/v2/notifications/{notification_id}', 'updated': False, 'notification': None, 'error': 'the notification submitted is equal to the existing notification with the same id' }) response.status_code = 400 return response
def comment_post(): """ Create a new comment. :return: A response object for the POST API request. """ comment_data: dict = request.get_json() if comment_data is None: response = jsonify({ 'self': f'/v2/comments', 'added': False, 'comment': None, 'error': "the request body isn't populated" }) response.status_code = 400 return response comment_to_add = Comment(comment_data) jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if comment_to_add.username == jwt_username: # You are so loved. current_app.logger.info( f'User {jwt_username} is creating a comment on log {comment_to_add.log_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to create a comment for user {comment_to_add.username}.' ) response = jsonify({ 'self': f'/v2/comments', 'added': False, 'comment': None, 'error': f'User {jwt_username} is not authorized to create a comment for user {comment_to_add.username}.' }) response.status_code = 400 return response if None in [ comment_to_add.username, comment_to_add.first, comment_to_add.last, comment_to_add.log_id ]: response = jsonify({ 'self': f'/v2/comments', 'added': False, 'comment': None, 'error': "'username', 'first', 'last', and 'log_id' are required fields" }) response.status_code = 400 return response comment_to_add.time = datetime.now() comment_to_add.created_date = datetime.now() comment_to_add.created_app = 'saints-xctf-api' comment_to_add.created_user = None comment_to_add.modified_date = None comment_to_add.modified_app = None comment_to_add.modified_user = None comment_to_add.deleted_date = None comment_to_add.deleted_app = None comment_to_add.deleted_user = None comment_to_add.deleted = False comment_added_successfully: bool = CommentDao.add_comment( new_comment=comment_to_add) if comment_added_successfully: comment_added = CommentDao.get_comment_by_id(comment_to_add.comment_id) comment_added_dict: dict = CommentData(comment_added).__dict__ response = jsonify({ 'self': '/v2/comments', 'added': True, 'comment': comment_added_dict }) response.status_code = 200 return response else: response = jsonify({ 'self': '/v2/comments', 'added': False, 'comment': None, 'error': 'failed to create a new comment' }) response.status_code = 500 return response
def notification_by_id_soft_delete(notification_id) -> Response: """ Soft delete an existing notification with a given unique ID. :param notification_id: The unique identifier for a user notification :return: A response object for the DELETE API request. """ existing_notification: Notification = NotificationDao.get_notification_by_id( notification_id=notification_id) if existing_notification is None: response = jsonify({ 'self': f'/v2/notifications/soft/{notification_id}', 'deleted': False, 'error': 'there is no existing notification with this id' }) response.status_code = 400 return response jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if existing_notification.username == jwt_username: current_app.logger.info( f'User {jwt_username} is soft deleting their notification with id {existing_notification.notification_id}.' ) else: current_app.logger.info( f'User {jwt_username} is not authorized to soft delete a notification sent to ' f'{existing_notification.username}.') response = jsonify({ 'self': f'/v2/notifications/soft/{notification_id}', 'deleted': False, 'error': f'User {jwt_username} is not authorized to soft delete a notification sent to ' f'{existing_notification.username}.' }) response.status_code = 400 return response # Update the notification model to reflect the soft delete existing_notification.deleted = True existing_notification.deleted_date = datetime.now() existing_notification.deleted_app = 'saints-xctf-api' existing_notification.modified_date = datetime.now() existing_notification.modified_app = 'saints-xctf-api' is_deleted: bool = NotificationDao.soft_delete_notification( existing_notification) if is_deleted: response = jsonify({ 'self': f'/v2/notifications/soft/{notification_id}', 'deleted': True, }) response.status_code = 204 return response else: response = jsonify({ 'self': f'/v2/notifications/soft/{notification_id}', 'deleted': False, 'error': 'failed to soft delete the notification' }) response.status_code = 500 return response
def flair_post(): """ Endpoint for creating flair used on a users profile. :return: JSON with the resulting Flair object and relevant metadata. """ flair_data: dict = request.get_json() if flair_data is None: response = jsonify({ 'self': f'/v2/flair', 'added': False, 'error': "the request body isn't populated" }) response.status_code = 400 return response username = flair_data.get('username') flair_content = flair_data.get('flair') jwt_claims: dict = get_claims(request) jwt_username = jwt_claims.get('sub') if username == jwt_username: current_app.logger.info(f'User {jwt_username} is creating a flair for their profile.') else: current_app.logger.info( f'User {jwt_username} is not authorized to create a flair for user {username}.' ) response = jsonify({ 'self': f'/v2/flair', 'added': False, 'error': f'User {jwt_username} is not authorized to create a flair for user {username}.' }) response.status_code = 400 return response if username is None or flair_content is None: response = jsonify({ 'self': f'/v2/flair', 'added': False, 'error': "'username' and 'flair' are required fields" }) response.status_code = 400 return response flair = Flair({ 'username': username, 'flair': flair_content }) flair.created_date = datetime.now() flair.created_app = 'saints-xctf-api' flair.created_user = None flair.modified_date = None flair.modified_app = None flair.modified_user = None flair.deleted_date = None flair.deleted_app = None flair.deleted_user = None flair.deleted = False flair_added: bool = FlairDao.add_flair(flair) if flair_added: new_flair: Flair = FlairDao.get_flair_by_content(username, flair_content) new_flair_dict: dict = FlairData(new_flair).__dict__ response = jsonify({ 'self': f'/v2/flair', 'added': True, 'flair': new_flair_dict }) response.status_code = 201 return response else: response = jsonify({ 'self': f'/v2/flair', 'added': False, 'flair': None, 'error': 'the flair creation failed' }) response.status_code = 500 return response