diff --git a/fittrackee/responses.py b/fittrackee/responses.py index 430c34eb..165b8ca0 100644 --- a/fittrackee/responses.py +++ b/fittrackee/responses.py @@ -1,7 +1,7 @@ from json import dumps from typing import Dict, List, Optional, Union -from flask import Response +from flask import Request, Response, current_app from flask_sqlalchemy import SQLAlchemy from fittrackee import appLog @@ -143,3 +143,48 @@ def handle_error_and_return_response( db.session.rollback() appLog.error(error) return InternalServerErrorResponse(message=message, status=status) + + +def get_error_response_if_file_is_invalid( + file_type: str, req: Request +) -> Optional[HttpResponse]: + if 'file' not in req.files: + return InvalidPayloadErrorResponse('no file part', 'fail') + + file = req.files['file'] + if not file.filename or file.filename == '': + return InvalidPayloadErrorResponse('no selected file', 'fail') + + allowed_extensions = ( + 'WORKOUT_ALLOWED_EXTENSIONS' + if file_type == 'workout' + else 'PICTURE_ALLOWED_EXTENSIONS' + ) + + file_extension = ( + file.filename.rsplit('.', 1)[1].lower() + if '.' in file.filename + else None + ) + max_file_size = current_app.config['max_single_file_size'] + + if not ( + file_extension + and file_extension in current_app.config[allowed_extensions] + ): + return InvalidPayloadErrorResponse( + 'file extension not allowed', 'fail' + ) + + if ( + file_extension != 'zip' + and req.content_length is not None + and req.content_length > max_file_size + ): + return PayloadTooLargeErrorResponse( + file_type=file_type, + file_size=req.content_length, + max_size=max_file_size, + ) + + return None diff --git a/fittrackee/users/auth.py b/fittrackee/users/auth.py index 98bd49a3..de58731a 100644 --- a/fittrackee/users/auth.py +++ b/fittrackee/users/auth.py @@ -18,10 +18,11 @@ from fittrackee.responses import ( NotFoundErrorResponse, PayloadTooLargeErrorResponse, UnauthorizedErrorResponse, + get_error_response_if_file_is_invalid, handle_error_and_return_response, ) from fittrackee.tasks import reset_password_email -from fittrackee.utils import get_readable_duration, verify_extension_and_size +from fittrackee.utils import get_readable_duration from fittrackee.workouts.models import Sport from .decorators import authenticate @@ -890,7 +891,9 @@ def edit_picture(auth_user: User) -> Union[Dict, HttpResponse]: """ try: - response_object = verify_extension_and_size('picture', request) + response_object = get_error_response_if_file_is_invalid( + 'picture', request + ) except RequestEntityTooLarge as e: appLog.error(e) return PayloadTooLargeErrorResponse( diff --git a/fittrackee/utils.py b/fittrackee/utils.py index 1e48ac02..a28323df 100644 --- a/fittrackee/utils.py +++ b/fittrackee/utils.py @@ -2,61 +2,6 @@ from datetime import timedelta from typing import Optional import humanize -from flask import Request, current_app - -from .responses import ( - HttpResponse, - InvalidPayloadErrorResponse, - PayloadTooLargeErrorResponse, -) - - -def verify_extension_and_size( - file_type: str, req: Request -) -> Optional[HttpResponse]: - """ - Return error Response if file is invalid - """ - if 'file' not in req.files: - return InvalidPayloadErrorResponse('no file part', 'fail') - - file = req.files['file'] - if not file.filename or file.filename == '': - return InvalidPayloadErrorResponse('no selected file', 'fail') - - allowed_extensions = ( - 'WORKOUT_ALLOWED_EXTENSIONS' - if file_type == 'workout' - else 'PICTURE_ALLOWED_EXTENSIONS' - ) - - file_extension = ( - file.filename.rsplit('.', 1)[1].lower() - if '.' in file.filename - else None - ) - max_file_size = current_app.config['max_single_file_size'] - - if not ( - file_extension - and file_extension in current_app.config[allowed_extensions] - ): - return InvalidPayloadErrorResponse( - 'file extension not allowed', 'fail' - ) - - if ( - file_extension != 'zip' - and req.content_length is not None - and req.content_length > max_file_size - ): - return PayloadTooLargeErrorResponse( - file_type=file_type, - file_size=req.content_length, - max_size=max_file_size, - ) - - return None def get_readable_duration(duration: int, locale: Optional[str] = None) -> str: diff --git a/fittrackee/workouts/workouts.py b/fittrackee/workouts/workouts.py index b4e556a4..7b9beff4 100644 --- a/fittrackee/workouts/workouts.py +++ b/fittrackee/workouts/workouts.py @@ -25,12 +25,12 @@ from fittrackee.responses import ( InvalidPayloadErrorResponse, NotFoundErrorResponse, PayloadTooLargeErrorResponse, + get_error_response_if_file_is_invalid, handle_error_and_return_response, ) from fittrackee.users.decorators import authenticate from fittrackee.users.models import User from fittrackee.users.utils import can_view_workout -from fittrackee.utils import verify_extension_and_size from .models import Workout from .utils import ( @@ -961,7 +961,9 @@ def post_workout(auth_user: User) -> Union[Tuple[Dict, int], HttpResponse]: """ try: - error_response = verify_extension_and_size('workout', request) + error_response = get_error_response_if_file_is_invalid( + 'workout', request + ) except RequestEntityTooLarge as e: appLog.error(e) return PayloadTooLargeErrorResponse(