def get(self): # Get optional page number try: filter_params = { 'per_page': request.args.get('per_page', default=10, type=int), 'page': request.args.get('page', default=1, type=int), 'from': request.args.get('from', default=None, type=toDate), 'to': request.args.get('to', default=None, type=toDate), 'sort': request.args.get('sort', default=OrderType.DESCENDING, type=OrderType), 'query': request.args.get('query', default='', type=str) } except ValueError: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse(details={'page': 'Page should be number'}, error='validation errors')) log.info(f'Invalid page query argument: {error_response}') return error_response, 400 # Find all articles on that page articles = Article.find_all_articles(filter_params) # Map articles to schema return self.paginated_articles_schema.dump(articles), 200
class NotificationResource(Resource): error_schema = ErrorResponseSchema() user_schema = UserSchema() notification_preferences_schema = NotificationPreferencesSchema() @api.expect(notification_preferences_model) @api.response(204, 'No Content') @jwt_required([RoleTypes.ADMIN, RoleTypes.CLIENT]) def post(self): # Find user uuid = get_jwt_identity() user = User.find_by_uuid(uuid) if not user: error_response = self.error_schema.dump( ErrorResponse( details={'uuid': f'User with {uuid} uuid does not exist'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 404 # Deserialize input notification_preferences = self.notification_preferences_schema.load( api.payload) # update notification preferences for key, value in notification_preferences.items(): setattr(user, key, value) user.commit() # return updated user return self.user_schema.dump(user), 200
def get(self): # Get optional page number try: page = int(request.args.get('page')) except ValueError: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse(details={'page': 'Page should be number'}, error='validation errors')) log.info(f'Invalid page query argument: {error_response}') return error_response, 400 # Find all users on that page users = User.find_all_users(page or 1, 20) # Map users to schema paginated_user_schema = PaginatedUserSchema() return paginated_user_schema.dump(users), 200
class LoginResource(Resource): login_schema = LoginSchema() error_schema = ErrorResponseSchema() token_schema = TokenSchema() @api.expect(login_model) @api.response(200, 'Success', login_response) def post(self): # Serialize login model try: login_dto = self.login_schema.load(api.payload) except ValidationError as err: error_response = self.error_schema.dump( ErrorResponse(details=err.messages, error='validation errors')) log.info(f'Validation errors during login: {error_response}') return error_response, 400 # Find user in database user = User.find_by_email(login_dto.email) if not user: error_response = self.error_schema.dump( ErrorResponse(details={ 'user': [f'There is no user with {login_dto.email} email'] }, error='not existing user')) log.info(f'Trying to log in non existing user: {error_response}') return error_response, 404 # Chcek if user is confirmed if not user.confirmed: error_response = self.error_schema.dump( ErrorResponse( details={'user': [f'User {user.name} is unconfirmed']}, error='user not confirmed')) log.info(f'Trying to log in unconfirmed user: {error_response}') return error_response, 400 # Check user password if not user.check_password(login_dto.password): error_response = self.error_schema.dump( ErrorResponse( details={'password': ['You provided wrong password']}, error='wrong password')) log.info(f'Wrong password used during login: {error_response}') return error_response, 400 # Create JWT from user data token = TokenDto(create_access_token(identity=user), create_refresh_token(identity=user)) # Return token log.info('User login sucessful') return self.token_schema.dump(token), 200
def get(self, uuid): # Try to find user try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 user = User.find_by_uuid(uuid) # If user is requesting details for another user user_claims = self.user_claims_schema.load(get_jwt_claims()) if user_claims.is_client() and user.uuid != UUID(get_jwt_identity()): error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'Access to that resource is forbidden'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 403 # If there is no user with given id if not user: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'User with {uuid} uuid does not exist'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 404 # Return user return self.user_schema.dump(user), 200
def delete(self, uuid): # Try to find user try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 user = User.find_by_uuid(uuid) # If there is no user with given id if not user: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'User with {uuid} uuid does not exist'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 404 # delete user user.remove() return '', 204
def get(self): # Get identity of user from refresh token current_user_uuid = get_jwt_identity() # Try to find user in db user = User.find_by_uuid(UUID(current_user_uuid)) if not user: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'user': ['There is no user with given email']}, error='not existing user')) log.warn(f'Non existing user {current_user_uuid}' + f' trying to refresh token: {error_response}') return error_response, 404 # Generate new access token with user token = TokenDto(create_access_token(identity=user)) # Return only access token token_schema = TokenSchema(only=['access_token']) log.info(f'Access token refresh successful') return token_schema.dump(token), 200
class ConfirmationResource(Resource): error_schema = ErrorResponseSchema() def get(self, token): # Confirm token try: email = ConfirmationMailHandler.confirm_token(token) except InvalidConfirmationToken: error_response = self.error_schema.dump( ErrorResponse( details={'token': f'{email} is invalid or expired'}, error='Invalid or expired token')) log.info(f'Invalid token: {error_response}') return error_response, 403 # Find user that token belongs to user = User.find_by_email(email) if not user: error_response = self.error_schema.dump( ErrorResponse( details={'user': [f'There is no user with {email} email']}, error='not existing user')) log.info(f'Trying to confirm non existing user: {error_response}') return error_response, 404 # Check if user was already confirmed if user.confirmed: error_response = self.error_schema.dump( ErrorResponse(details={ 'user': [f'User "{user.name}" is already confirmed'] }, error='User already confirmed')) log.info( f'Trying to confirm already confirmed user: {error_response}') return error_response, 404 # Confirm user user.confirm_account() user.commit() return '', 204
def post(self): # Map request body to user model try: user = self.user_schema.load(api.payload) except ValidationError as err: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse(details=err.messages, error='validation errors')) log.info( f'Validation errors during user creation: {error_response}') return error_response, 400 # Check if user with same email already exists if User.find_by_email(user.email) is not None: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse(details={ 'user': ['User with provided email already exists'] }, error='duplicate email')) log.info(f'trying to create user with existing email {user.email}') return error_response, 400 # If caller was ADMIN create ADMIN if caller was CLIENT create CLIENT user_claims = self.user_claims_schema.load(get_jwt_claims()) if user_claims.is_admin(): user.add_to_role(RoleTypes.ADMIN) else: user.add_to_role(RoleTypes.CLIENT) # Send confirmation mail that user was created if app.config['REQUIRE_MAIL_CONFIRMATION']: send_confirmation_token(user.email) else: user.confirm_account() # Save model to DB user.commit() # Map saved user to response body log.info(f'Sucessfuly created new user') return self.user_schema.dump(user), 201
def put(self, uuid): # Map input data try: user_update_schema = UpdateUserSchema() update_info = user_update_schema.load(api.payload) except ValidationError as err: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse(details=err.messages, error='validation errors')) log.info(f'Validation errors during user update: {error_response}') return error_response, 400 # Try to find user try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 user = User.find_by_uuid(uuid) # If there is no user with given id if not user: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'User with {uuid} uuid does not exist'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 404 # update user properties for key, value in update_info.items(): setattr(user, key, value) user.commit() # return updated user return self.user_schema.dump(user), 200
class ArticlesResource(Resource): article_schema = ArticleSchema() paginated_articles_schema = PaginatedArticleSchema() error_schema = ErrorResponseSchema() create_article_schema = CreateArticleSchema() error_schema = ErrorResponseSchema() # POST api/article - create new article @api.expect(create_article_model) @api.response(201, 'Created', article_model) @jwt_required([RoleTypes.ADMIN]) def post(self): # Find user trying to save article user = User.find_by_uuid(get_jwt_identity()) # Check if article is valid try: article = self.create_article_schema.load(request.form.to_dict()) except ValidationError as err: error_response = self.error_schema.dump( ErrorResponse(details=err.messages, error='validation errors')) log.info( f'Validation errors during article creation: {error_response}') return error_response, 400 # Try to save images to AWS saved_images = upload_request_files(request.files) article.images = saved_images # Add user to article article.user = user # Save article article.commit() # Send notification that there is new article users_to_notify = User.find_with_mail_notifications_enabled() send_notification_mail([user.email for user in users_to_notify], article.title, article.uuid) # Return article model return self.article_schema.dump(article), 201 # GET api/article - get all articles (filtered by query) def get(self): # Get optional page number try: filter_params = { 'per_page': request.args.get('per_page', default=10, type=int), 'page': request.args.get('page', default=1, type=int), 'from': request.args.get('from', default=None, type=toDate), 'to': request.args.get('to', default=None, type=toDate), 'sort': request.args.get('sort', default=OrderType.DESCENDING, type=OrderType), 'query': request.args.get('query', default='', type=str) } except ValueError: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse(details={'page': 'Page should be number'}, error='validation errors')) log.info(f'Invalid page query argument: {error_response}') return error_response, 400 # Find all articles on that page articles = Article.find_all_articles(filter_params) # Map articles to schema return self.paginated_articles_schema.dump(articles), 200
class ArticleResource(Resource): error_schema = ErrorResponseSchema() article_schema = ArticleSchema() update_article_schema = UpdateArticleSchema() def incorrect_uuid(self, uuid): error_response = self.error_schema.dump( ErrorResponse(details={'uuid': f'Badly formed uuid: {uuid}'}, error='uuid format error')) log.info(f'uuid format error: {error_response}') return error_response # GET api/article/1 - get details for article def get(self, uuid): try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 article = Article.find_by_uuid(uuid) if not article: error_response = self.error_schema.dump( ErrorResponse(details={ 'uuid': f'Article with {uuid} uuid does not exist' }, error='Article not found')) log.info(f'Article not found: {error_response}') return error_response, 404 return self.article_schema.dump(article), 200 # PUT api/article/1 - update article @jwt_required([RoleTypes.ADMIN]) def put(self, uuid): # Map input data try: update_info = self.update_article_schema.load(api.payload) except ValidationError as err: error_response = self.error_schema.dump( ErrorResponse(details=err.messages, error='validation errors')) log.info( f'Validation errors during article update: {error_response}') return error_response, 400 # Try to find article article = Article.find_by_uuid(uuid) if not article: error_response = self.error_schema.dump( ErrorResponse(details={ 'uuid': f'Article with {uuid} uuid does not exist' }, error='Article not found')) log.info(f'Article not found: {error_response}') return error_response, 404 # Update article for key, value in update_info.items(): setattr(article, key, value) article.commit() return self.article_schema.dump(article), 200 # DELETE api/article/1 - delete article @jwt_required([RoleTypes.ADMIN]) def delete(self, uuid): try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 article = Article.find_by_uuid(uuid) if not article: error_response = self.error_schema.dump( ErrorResponse(details={ 'uuid': f'Article with {uuid} uuid does not exist' }, error='Article not found')) log.info(f'Article not found: {error_response}') return error_response, 404 article.remove() return '', 204 pass
class UserResourceList(Resource): error_schema = ErrorResponseSchema() user_claims_schema = UserClaimsSchema() user_schema = UserSchema() def incorrect_uuid(self, uuid): error_response = self.error_schema.dump( ErrorResponse(details={'uuid': f'Badly formed uuid: {uuid}'}, error='uuid format error')) log.info(f'uuid format error: {error_response}') return error_response # GET api/user/1 - get details for specific users @jwt_required([RoleTypes.ADMIN, RoleTypes.CLIENT]) def get(self, uuid): # Try to find user try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 user = User.find_by_uuid(uuid) # If user is requesting details for another user user_claims = self.user_claims_schema.load(get_jwt_claims()) if user_claims.is_client() and user.uuid != UUID(get_jwt_identity()): error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'Access to that resource is forbidden'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 403 # If there is no user with given id if not user: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'User with {uuid} uuid does not exist'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 404 # Return user return self.user_schema.dump(user), 200 # DELETE api/user/1 - delete specific user @jwt_required([RoleTypes.ADMIN]) def delete(self, uuid): # Try to find user try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 user = User.find_by_uuid(uuid) # If there is no user with given id if not user: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'User with {uuid} uuid does not exist'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 404 # delete user user.remove() return '', 204 @jwt_required([RoleTypes.ADMIN]) def put(self, uuid): # Map input data try: user_update_schema = UpdateUserSchema() update_info = user_update_schema.load(api.payload) except ValidationError as err: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse(details=err.messages, error='validation errors')) log.info(f'Validation errors during user update: {error_response}') return error_response, 400 # Try to find user try: uuid = UUID(uuid) except ValueError: return self.incorrect_uuid(uuid), 404 user = User.find_by_uuid(uuid) # If there is no user with given id if not user: error_schema = ErrorResponseSchema() error_response = error_schema.dump( ErrorResponse( details={'uuid': f'User with {uuid} uuid does not exist'}, error='User not found')) log.info(f'User not found: {error_response}') return error_response, 404 # update user properties for key, value in update_info.items(): setattr(user, key, value) user.commit() # return updated user return self.user_schema.dump(user), 200
from schemas.user.user_claims_schema import UserClaimsSchema from flask_jwt_extended import JWTManager from core.responses.error_response import ErrorResponse from schemas.error.error_response_schema import ErrorResponseSchema from dao.user.user import User error_schema = ErrorResponseSchema() def setup_jwt(app): jwt = JWTManager(app) @jwt.user_claims_loader def add_claims_to_jwt(user: User): schema = UserClaimsSchema() return schema.dump(user) @jwt.user_identity_loader def user_identity_lookup(user: User): return user.uuid @jwt.expired_token_loader def expired_token_callback(): return error_schema.dump( ErrorResponse(details={'token': ['Token has expired']}, error='expired_token')), 401 @jwt.invalid_token_loader def invalid_token_callback(error): return error_schema.dump( ErrorResponse(details={'token': ['Signature verification failed']},