backend/api/users/actions.py (141 lines of code) (raw):

from flask_restful import Resource, current_app, request from schematics.exceptions import DataError from backend.models.dtos.user_dto import UserDTO, UserRegisterEmailDTO from backend.services.messaging.message_service import MessageService from backend.services.users.authentication_service import token_auth, tm from backend.services.users.user_service import UserService, UserServiceError, NotFound from backend.services.interests_service import InterestService class UsersActionsSetUsersAPI(Resource): @tm.pm_only(False) @token_auth.login_required def patch(self): """ Updates user info --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: body name: body required: true description: JSON object to update a user schema: properties: name: type: string example: Your Name city: type: string example: Your City country: type: string example: Your Country emailAddress: type: string example: test@test.com twitterId: type: string example: twitter handle without @ facebookId: type: string example: facebook username linkedinId: type: string example: linkedin username gender: type: string description: gender selfDescriptionGender: type: string description: gender self-description responses: 200: description: Details saved 400: description: Client Error - Invalid Request 401: description: Unauthorized - Invalid credentials 500: description: Internal Server Error """ try: user_dto = UserDTO(request.get_json()) if user_dto.email_address == "": user_dto.email_address = ( None # Replace empty string with None so validation doesn't break ) user_dto.validate() authenticated_user_id = token_auth.current_user() if authenticated_user_id != user_dto.id: return {"Error": "Unable to authenticate"}, 401 except ValueError as e: return {"Error": str(e)}, 400 except DataError as e: current_app.logger.error(f"error validating request: {str(e)}") return {"Error": "Unable to update user details"}, 400 try: verification_sent = UserService.update_user_details( authenticated_user_id, user_dto ) return verification_sent, 200 except NotFound: return {"Error": "User not found"}, 404 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to update user details"}, 500 class UsersActionsSetLevelAPI(Resource): @tm.pm_only() @token_auth.login_required def patch(self, username, level): """ Allows PMs to set a user's mapping level --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: username in: path description: Mapper's OpenStreetMap username required: true type: string default: Thinkwhere - name: level in: path description: The mapping level that should be set required: true type: string default: ADVANCED responses: 200: description: Level set 400: description: Bad Request - Client Error 401: description: Unauthorized - Invalid credentials 404: description: User not found 500: description: Internal Server Error """ try: UserService.set_user_mapping_level(username, level) return {"Success": "Level set"}, 200 except UserServiceError: return {"Error": "Not allowed"}, 400 except NotFound: return {"Error": "User or mapping not found"}, 404 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to update mapping level"}, 500 class UsersActionsSetRoleAPI(Resource): @tm.pm_only() @token_auth.login_required def patch(self, username, role): """ Allows PMs to set a user's role --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: username in: path description: Mapper's OpenStreetMap username required: true type: string default: Thinkwhere - name: role in: path description: The role to add required: true type: string default: ADMIN responses: 200: description: Role set 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 404: description: User not found 500: description: Internal Server Error """ try: UserService.add_role_to_user(token_auth.current_user(), username, role) return {"Success": "Role Added"}, 200 except UserServiceError: return {"Error": "Not allowed"}, 403 except NotFound: return {"Error": "User or mapping not found"}, 404 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to update user role"}, 500 class UsersActionsSetExpertModeAPI(Resource): @tm.pm_only(False) @token_auth.login_required def patch(self, is_expert): """ Allows user to enable or disable expert mode --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: is_expert in: path description: true to enable expert mode, false to disable required: true type: string responses: 200: description: Mode set 400: description: Bad Request - Client Error 401: description: Unauthorized - Invalid credentials 404: description: User not found 500: description: Internal Server Error """ try: UserService.set_user_is_expert( token_auth.current_user(), is_expert == "true" ) return {"Success": "Expert mode updated"}, 200 except UserServiceError: return {"Error": "Not allowed"}, 400 except NotFound: return {"Error": "User not found"}, 404 except Exception as e: error_msg = f"UserSetExpert POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to update expert mode"}, 500 class UsersActionsVerifyEmailAPI(Resource): @tm.pm_only(False) @token_auth.login_required def patch(self): """ Resends the verification email token to the logged in user --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== responses: 200: description: Resends the user their email verification email 500: description: Internal Server Error """ try: MessageService.resend_email_validation(token_auth.current_user()) return {"Success": "Verification email resent"}, 200 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to send verification email"}, 500 class UsersActionsRegisterEmailAPI(Resource): def post(self): """ Registers users without OpenStreetMap account --- tags: - users produces: - application/json parameters: - in: body name: body required: true description: JSON object to update a user schema: properties: email: type: string example: test@test.com responses: 200: description: User registered 400: description: Client Error - Invalid Request 500: description: Internal Server Error """ try: user_dto = UserRegisterEmailDTO(request.get_json()) user_dto.validate() except DataError as e: current_app.logger.error(f"error validating request: {str(e)}") return str(e), 400 try: user = UserService.register_user_with_email(user_dto) user_dto = UserRegisterEmailDTO( dict( success=True, email=user_dto.email, details="User created successfully", id=user.id, ) ) return user_dto.to_primitive(), 200 except ValueError as e: user_dto = UserRegisterEmailDTO(dict(email=user_dto.email, details=str(e))) return user_dto.to_primitive(), 400 except Exception as e: details_msg = "User POST - unhandled error: Unknown error" current_app.logger.critical(str(e)) user_dto = UserRegisterEmailDTO( dict(email=user_dto.email, details=details_msg) ) return user_dto.to_primitive(), 500 class UsersActionsSetInterestsAPI(Resource): @token_auth.login_required def post(self): """ Creates a relationship between user and interests --- tags: - interests produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: body name: body required: true description: JSON object for creating/updating user and interests relationships schema: properties: interests: type: array items: type: integer responses: 200: description: New user interest relationship created 400: description: Invalid Request 401: description: Unauthorized - Invalid credentials 500: description: Internal Server Error """ try: data = request.get_json() user_interests = InterestService.create_or_update_user_interests( token_auth.current_user(), data["interests"] ) return user_interests.to_primitive(), 200 except ValueError as e: return {"Error": str(e)}, 400 except NotFound: return {"Error": "Interest not Found"}, 404 except Exception as e: error_msg = f"User relationship POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500