From 00b6e058052d25f0d72662cf20cc61804af9897d Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Dec 2021 19:22:47 +0100 Subject: [PATCH 1/6] API - authentication decorators return user directly instead of user id --- Makefile | 2 + fittrackee/application/app_config.py | 5 +- fittrackee/users/auth.py | 65 ++++++++++++------------- fittrackee/users/decorators.py | 10 ++-- fittrackee/users/users.py | 18 ++----- fittrackee/users/utils.py | 6 +-- fittrackee/workouts/records.py | 7 ++- fittrackee/workouts/sports.py | 27 ++++------- fittrackee/workouts/stats.py | 10 ++-- fittrackee/workouts/workouts.py | 71 +++++++++++----------------- 10 files changed, 88 insertions(+), 133 deletions(-) diff --git a/Makefile b/Makefile index 03e8b22a..4b950ff5 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,8 @@ build-client: lint-client check-all: lint-all type-check test-python test-client +check-python: lint-python type-check test-python + clean: rm -rf .mypy_cache rm -rf .pytest_cache diff --git a/fittrackee/application/app_config.py b/fittrackee/application/app_config.py index e3e97f70..c97c9278 100644 --- a/fittrackee/application/app_config.py +++ b/fittrackee/application/app_config.py @@ -10,6 +10,7 @@ from fittrackee.responses import ( handle_error_and_return_response, ) from fittrackee.users.decorators import authenticate_as_admin +from fittrackee.users.models import User from .models import AppConfig from .utils import update_app_config_from_database, verify_app_config @@ -64,7 +65,7 @@ def get_application_config() -> Union[Dict, HttpResponse]: @config_blueprint.route('/config', methods=['PATCH']) @authenticate_as_admin -def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]: +def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]: """ Update Application config @@ -95,8 +96,6 @@ def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]: "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - : Union[Dict, HttpResponse]: @auth_blueprint.route('/auth/logout', methods=['GET']) @authenticate -def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]: +def logout_user(auth_user: User) -> Union[Dict, HttpResponse]: """ user logout @@ -274,7 +274,7 @@ def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]: auth_token = auth_header.split(' ')[1] resp = User.decode_auth_token(auth_token) - if isinstance(auth_user_id, str): + if isinstance(resp, str): return UnauthorizedErrorResponse(resp) return { @@ -286,7 +286,7 @@ def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]: @auth_blueprint.route('/auth/profile', methods=['GET']) @authenticate def get_authenticated_user_profile( - auth_user_id: int, + auth_user: User, ) -> Union[Dict, HttpResponse]: """ get authenticated user info @@ -381,13 +381,12 @@ def get_authenticated_user_profile( - invalid token, please log in again """ - user = User.query.filter_by(id=auth_user_id).first() - return {'status': 'success', 'data': user.serialize()} + return {'status': 'success', 'data': auth_user.serialize()} @auth_blueprint.route('/auth/profile/edit', methods=['POST']) @authenticate -def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]: +def edit_user(auth_user: User) -> Union[Dict, HttpResponse]: """ edit authenticated user @@ -523,24 +522,23 @@ def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]: ).decode() try: - user = User.query.filter_by(id=auth_user_id).first() - user.first_name = first_name - user.last_name = last_name - user.bio = bio - user.location = location - user.birth_date = ( + auth_user.first_name = first_name + auth_user.last_name = last_name + auth_user.bio = bio + auth_user.location = location + auth_user.birth_date = ( datetime.datetime.strptime(birth_date, '%Y-%m-%d') if birth_date else None ) if password is not None and password != '': - user.password = password + auth_user.password = password db.session.commit() return { 'status': 'success', 'message': 'user profile updated', - 'data': user.serialize(), + 'data': auth_user.serialize(), } # handler errors @@ -550,7 +548,7 @@ def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]: @auth_blueprint.route('/auth/profile/edit/preferences', methods=['POST']) @authenticate -def edit_user_preferences(auth_user_id: int) -> Union[Dict, HttpResponse]: +def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]: """ edit authenticated user preferences @@ -670,17 +668,16 @@ def edit_user_preferences(auth_user_id: int) -> Union[Dict, HttpResponse]: weekm = post_data.get('weekm') try: - user = User.query.filter_by(id=auth_user_id).first() - user.imperial_units = imperial_units - user.language = language - user.timezone = timezone - user.weekm = weekm + auth_user.imperial_units = imperial_units + auth_user.language = language + auth_user.timezone = timezone + auth_user.weekm = weekm db.session.commit() return { 'status': 'success', 'message': 'user preferences updated', - 'data': user.serialize(), + 'data': auth_user.serialize(), } # handler errors @@ -691,7 +688,7 @@ def edit_user_preferences(auth_user_id: int) -> Union[Dict, HttpResponse]: @auth_blueprint.route('/auth/profile/edit/sports', methods=['POST']) @authenticate def edit_user_sport_preferences( - auth_user_id: int, + auth_user: User, ) -> Union[Dict, HttpResponse]: """ edit authenticated user sport preferences @@ -758,12 +755,12 @@ def edit_user_sport_preferences( try: user_sport = UserSportPreference.query.filter_by( - user_id=auth_user_id, + user_id=auth_user.id, sport_id=sport_id, ).first() if not user_sport: user_sport = UserSportPreference( - user_id=auth_user_id, + user_id=auth_user.id, sport_id=sport_id, stopped_speed_threshold=sport.stopped_speed_threshold, ) @@ -792,7 +789,7 @@ def edit_user_sport_preferences( @auth_blueprint.route('/auth/picture', methods=['POST']) @authenticate -def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]: +def edit_picture(auth_user: User) -> Union[Dict, HttpResponse]: """ update authenticated user picture @@ -848,23 +845,22 @@ def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]: file = request.files['file'] filename = secure_filename(file.filename) # type: ignore dirpath = os.path.join( - current_app.config['UPLOAD_FOLDER'], 'pictures', str(auth_user_id) + current_app.config['UPLOAD_FOLDER'], 'pictures', str(auth_user.id) ) if not os.path.exists(dirpath): os.makedirs(dirpath) absolute_picture_path = os.path.join(dirpath, filename) relative_picture_path = os.path.join( - 'pictures', str(auth_user_id), filename + 'pictures', str(auth_user.id), filename ) try: - user = User.query.filter_by(id=auth_user_id).first() - if user.picture is not None: - old_picture_path = get_absolute_file_path(user.picture) + if auth_user.picture is not None: + old_picture_path = get_absolute_file_path(auth_user.picture) if os.path.isfile(get_absolute_file_path(old_picture_path)): os.remove(old_picture_path) file.save(absolute_picture_path) - user.picture = relative_picture_path + auth_user.picture = relative_picture_path db.session.commit() return { 'status': 'success', @@ -879,7 +875,7 @@ def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]: @auth_blueprint.route('/auth/picture', methods=['DELETE']) @authenticate -def del_picture(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]: +def del_picture(auth_user: User) -> Union[Tuple[Dict, int], HttpResponse]: """ delete authenticated user picture @@ -908,11 +904,10 @@ def del_picture(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]: """ try: - user = User.query.filter_by(id=auth_user_id).first() - picture_path = get_absolute_file_path(user.picture) + picture_path = get_absolute_file_path(auth_user.picture) if os.path.isfile(picture_path): os.remove(picture_path) - user.picture = None + auth_user.picture = None db.session.commit() return {'status': 'no content'}, 204 except (exc.IntegrityError, ValueError) as e: diff --git a/fittrackee/users/decorators.py b/fittrackee/users/decorators.py index 8f260e4f..b3a841a5 100644 --- a/fittrackee/users/decorators.py +++ b/fittrackee/users/decorators.py @@ -13,11 +13,10 @@ def authenticate(f: Callable) -> Callable: def decorated_function( *args: Any, **kwargs: Any ) -> Union[Callable, HttpResponse]: - verify_admin = False - response_object, resp = verify_user(request, verify_admin) + response_object, user = verify_user(request, verify_admin=False) if response_object: return response_object - return f(resp, *args, **kwargs) + return f(user, *args, **kwargs) return decorated_function @@ -27,10 +26,9 @@ def authenticate_as_admin(f: Callable) -> Callable: def decorated_function( *args: Any, **kwargs: Any ) -> Union[Callable, HttpResponse]: - verify_admin = True - response_object, resp = verify_user(request, verify_admin) + response_object, user = verify_user(request, verify_admin=True) if response_object: return response_object - return f(resp, *args, **kwargs) + return f(user, *args, **kwargs) return decorated_function diff --git a/fittrackee/users/users.py b/fittrackee/users/users.py index 44faf458..8d0089be 100644 --- a/fittrackee/users/users.py +++ b/fittrackee/users/users.py @@ -27,7 +27,7 @@ USER_PER_PAGE = 10 @users_blueprint.route('/users', methods=['GET']) @authenticate -def get_users(auth_user_id: int) -> Dict: +def get_users(auth_user: User) -> Dict: """ Get all users @@ -144,8 +144,6 @@ def get_users(auth_user_id: int) -> Dict: "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - :query integer page: page if using pagination (default: 1) :query integer per_page: number of users per page (default: 10, max: 50) :query string q: query on user name @@ -219,7 +217,7 @@ def get_users(auth_user_id: int) -> Dict: @users_blueprint.route('/users/', methods=['GET']) @authenticate def get_single_user( - auth_user_id: int, user_name: str + auth_user: User, user_name: str ) -> Union[Dict, HttpResponse]: """ Get single user details @@ -306,7 +304,6 @@ def get_single_user( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param integer user_name: user name :reqheader Authorization: OAuth 2.0 Bearer Token @@ -371,9 +368,7 @@ def get_picture(user_name: str) -> Any: @users_blueprint.route('/users/', methods=['PATCH']) @authenticate_as_admin -def update_user( - auth_user_id: int, user_name: str -) -> Union[Dict, HttpResponse]: +def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]: """ Update user to add admin rights @@ -461,7 +456,6 @@ def update_user( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string user_name: user name :', methods=['DELETE']) @authenticate def delete_user( - auth_user_id: int, user_name: str + auth_user: User, user_name: str ) -> Union[Tuple[Dict, int], HttpResponse]: """ Delete a user account @@ -524,7 +518,6 @@ def delete_user( HTTP/1.1 204 NO CONTENT Content-Type: application/json - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string user_name: user name :reqheader Authorization: OAuth 2.0 Bearer Token @@ -543,12 +536,11 @@ def delete_user( """ try: - auth_user = User.query.filter_by(id=auth_user_id).first() user = User.query.filter_by(username=user_name).first() if not user: return UserNotFoundErrorResponse() - if user.id != auth_user_id and not auth_user.admin: + if user.id != auth_user.id and not auth_user.admin: return ForbiddenErrorResponse() if ( user.admin is True diff --git a/fittrackee/users/utils.py b/fittrackee/users/utils.py index c938a522..6f6a1984 100644 --- a/fittrackee/users/utils.py +++ b/fittrackee/users/utils.py @@ -62,7 +62,7 @@ def register_controls( def verify_user( current_request: Request, verify_admin: bool -) -> Tuple[Optional[HttpResponse], Optional[int]]: +) -> Tuple[Optional[HttpResponse], Optional[User]]: """ Return user id, if the provided token is valid and if user has admin rights if 'verify_admin' is True @@ -78,9 +78,9 @@ def verify_user( user = User.query.filter_by(id=resp).first() if not user: return UnauthorizedErrorResponse(default_message), None - if verify_admin and not is_admin(resp): + if verify_admin and not user.admin: return ForbiddenErrorResponse(), None - return None, resp + return None, user def can_view_workout( diff --git a/fittrackee/workouts/records.py b/fittrackee/workouts/records.py index f0905415..5714fa8e 100644 --- a/fittrackee/workouts/records.py +++ b/fittrackee/workouts/records.py @@ -3,6 +3,7 @@ from typing import Dict from flask import Blueprint from fittrackee.users.decorators import authenticate +from fittrackee.users.models import User from .models import Record @@ -11,7 +12,7 @@ records_blueprint = Blueprint('records', __name__) @records_blueprint.route('/records', methods=['GET']) @authenticate -def get_records(auth_user_id: int) -> Dict: +def get_records(auth_user: User) -> Dict: """ Get all records for authenticated user. @@ -95,8 +96,6 @@ def get_records(auth_user_id: int) -> Dict: "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - :reqheader Authorization: OAuth 2.0 Bearer Token :statuscode 200: success @@ -107,7 +106,7 @@ def get_records(auth_user_id: int) -> Dict: """ records = ( - Record.query.filter_by(user_id=auth_user_id) + Record.query.filter_by(user_id=auth_user.id) .order_by(Record.sport_id.asc(), Record.record_type.asc()) .all() ) diff --git a/fittrackee/workouts/sports.py b/fittrackee/workouts/sports.py index e91cf973..9236068c 100644 --- a/fittrackee/workouts/sports.py +++ b/fittrackee/workouts/sports.py @@ -20,7 +20,7 @@ sports_blueprint = Blueprint('sports', __name__) @sports_blueprint.route('/sports', methods=['GET']) @authenticate -def get_sports(auth_user_id: int) -> Dict: +def get_sports(auth_user: User) -> Dict: """ Get all sports @@ -165,8 +165,6 @@ def get_sports(auth_user_id: int) -> Dict: "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - :reqheader Authorization: OAuth 2.0 Bearer Token :statuscode 200: success @@ -176,16 +174,15 @@ def get_sports(auth_user_id: int) -> Dict: - invalid token, please log in again """ - user = User.query.filter_by(id=int(auth_user_id)).first() sports = Sport.query.order_by(Sport.id).all() sports_data = [] for sport in sports: sport_preferences = UserSportPreference.query.filter_by( - user_id=user.id, sport_id=sport.id + user_id=auth_user.id, sport_id=sport.id ).first() sports_data.append( sport.serialize( - is_admin=user.admin, + is_admin=auth_user.admin, sport_preferences=sport_preferences.serialize() if sport_preferences else None, @@ -199,7 +196,7 @@ def get_sports(auth_user_id: int) -> Dict: @sports_blueprint.route('/sports/', methods=['GET']) @authenticate -def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]: +def get_sport(auth_user: User, sport_id: int) -> Union[Dict, HttpResponse]: """ Get a sport @@ -273,7 +270,6 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]: "status": "not found" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param integer sport_id: sport id :reqheader Authorization: OAuth 2.0 Bearer Token @@ -286,18 +282,17 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]: :statuscode 404: sport not found """ - user = User.query.filter_by(id=int(auth_user_id)).first() sport = Sport.query.filter_by(id=sport_id).first() if sport: sport_preferences = UserSportPreference.query.filter_by( - user_id=user.id, sport_id=sport.id + user_id=auth_user.id, sport_id=sport.id ).first() return { 'status': 'success', 'data': { 'sports': [ sport.serialize( - is_admin=user.admin, + is_admin=auth_user.admin, sport_preferences=sport_preferences.serialize() if sport_preferences else None, @@ -310,9 +305,7 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]: @sports_blueprint.route('/sports/', methods=['PATCH']) @authenticate_as_admin -def update_sport( - auth_user_id: int, sport_id: int -) -> Union[Dict, HttpResponse]: +def update_sport(auth_user: User, sport_id: int) -> Union[Dict, HttpResponse]: """ Update a sport Authenticated user must be an admin @@ -364,7 +357,6 @@ def update_sport( "status": "not found" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param integer sport_id: sport id :/by_time', methods=['GET']) @authenticate def get_workouts_by_time( - auth_user_id: int, user_name: str + auth_user: User, user_name: str ) -> Union[Dict, HttpResponse]: """ Get workouts statistics for a user by time @@ -258,7 +258,6 @@ def get_workouts_by_time( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param integer user_name: user name :query string from: start date (format: ``%Y-%m-%d``) @@ -287,7 +286,7 @@ def get_workouts_by_time( @stats_blueprint.route('/stats//by_sport', methods=['GET']) @authenticate def get_workouts_by_sport( - auth_user_id: int, user_name: str + auth_user: User, user_name: str ) -> Union[Dict, HttpResponse]: """ Get workouts statistics for a user by sport @@ -361,7 +360,6 @@ def get_workouts_by_sport( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param integer user_name: user name :query integer sport_id: sport id @@ -383,7 +381,7 @@ def get_workouts_by_sport( @stats_blueprint.route('/stats/all', methods=['GET']) @authenticate_as_admin -def get_application_stats(auth_user_id: int) -> Dict: +def get_application_stats(auth_user: User) -> Dict: """ Get all application statistics @@ -411,8 +409,6 @@ def get_application_stats(auth_user_id: int) -> Dict: "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - :reqheader Authorization: OAuth 2.0 Bearer Token :statuscode 200: success diff --git a/fittrackee/workouts/workouts.py b/fittrackee/workouts/workouts.py index 607a65cc..192e7217 100644 --- a/fittrackee/workouts/workouts.py +++ b/fittrackee/workouts/workouts.py @@ -56,7 +56,7 @@ MAX_WORKOUTS_PER_PAGE = 100 @workouts_blueprint.route('/workouts', methods=['GET']) @authenticate -def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]: +def get_workouts(auth_user: User) -> Union[Dict, HttpResponse]: """ Get workouts for the authenticated user. @@ -171,8 +171,6 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]: "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - :query integer page: page if using pagination (default: 1) :query integer per_page: number of workouts per page (default: 5, max: 100) @@ -200,10 +198,9 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]: """ try: - user = User.query.filter_by(id=auth_user_id).first() params = request.args.copy() page = int(params.get('page', 1)) - date_from, date_to = get_datetime_from_request_args(params, user) + date_from, date_to = get_datetime_from_request_args(params, auth_user) distance_from = params.get('distance_from') distance_to = params.get('distance_to') duration_from = params.get('duration_from') @@ -220,7 +217,7 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]: per_page = MAX_WORKOUTS_PER_PAGE workouts_pagination = ( Workout.query.filter( - Workout.user_id == auth_user_id, + Workout.user_id == auth_user.id, Workout.sport_id == sport_id if sport_id else True, Workout.workout_date >= date_from if date_from else True, Workout.workout_date < date_to + timedelta(seconds=1) @@ -302,7 +299,7 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]: ) @authenticate def get_workout( - auth_user_id: int, workout_short_id: str + auth_user: User, workout_short_id: str ) -> Union[Dict, HttpResponse]: """ Get an workout @@ -372,8 +369,6 @@ def get_workout( }, "status": "not found" } - - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id :reqheader Authorization: OAuth 2.0 Bearer Token @@ -392,7 +387,7 @@ def get_workout( if not workout: return DataNotFoundErrorResponse('workouts') - error_response = can_view_workout(auth_user_id, workout.user_id) + error_response = can_view_workout(auth_user.id, workout.user_id) if error_response: return error_response @@ -403,7 +398,7 @@ def get_workout( def get_workout_data( - auth_user_id: int, + auth_user: User, workout_short_id: str, data_type: str, segment_id: Optional[int] = None, @@ -417,7 +412,7 @@ def get_workout_data( message=f'workout not found (id: {workout_short_id})', ) - error_response = can_view_workout(auth_user_id, workout.user_id) + error_response = can_view_workout(auth_user.id, workout.user_id) if error_response: return error_response if not workout.gpx or workout.gpx == '': @@ -467,7 +462,7 @@ def get_workout_data( ) @authenticate def get_workout_gpx( - auth_user_id: int, workout_short_id: str + auth_user: User, workout_short_id: str ) -> Union[Dict, HttpResponse]: """ Get gpx file for an workout displayed on map with Leaflet @@ -494,7 +489,6 @@ def get_workout_gpx( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id :reqheader Authorization: OAuth 2.0 Bearer Token @@ -510,7 +504,7 @@ def get_workout_gpx( :statuscode 500: """ - return get_workout_data(auth_user_id, workout_short_id, 'gpx') + return get_workout_data(auth_user, workout_short_id, 'gpx') @workouts_blueprint.route( @@ -518,7 +512,7 @@ def get_workout_gpx( ) @authenticate def get_workout_chart_data( - auth_user_id: int, workout_short_id: str + auth_user: User, workout_short_id: str ) -> Union[Dict, HttpResponse]: """ Get chart data from an workout gpx file, to display it with Recharts @@ -564,7 +558,6 @@ def get_workout_chart_data( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id :reqheader Authorization: OAuth 2.0 Bearer Token @@ -580,7 +573,7 @@ def get_workout_chart_data( :statuscode 500: """ - return get_workout_data(auth_user_id, workout_short_id, 'chart_data') + return get_workout_data(auth_user, workout_short_id, 'chart_data') @workouts_blueprint.route( @@ -589,7 +582,7 @@ def get_workout_chart_data( ) @authenticate def get_segment_gpx( - auth_user_id: int, workout_short_id: str, segment_id: int + auth_user: User, workout_short_id: str, segment_id: int ) -> Union[Dict, HttpResponse]: """ Get gpx file for an workout segment displayed on map with Leaflet @@ -616,7 +609,6 @@ def get_segment_gpx( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id :param integer segment_id: segment id @@ -632,7 +624,7 @@ def get_segment_gpx( :statuscode 500: """ - return get_workout_data(auth_user_id, workout_short_id, 'gpx', segment_id) + return get_workout_data(auth_user, workout_short_id, 'gpx', segment_id) @workouts_blueprint.route( @@ -642,7 +634,7 @@ def get_segment_gpx( ) @authenticate def get_segment_chart_data( - auth_user_id: int, workout_short_id: str, segment_id: int + auth_user: User, workout_short_id: str, segment_id: int ) -> Union[Dict, HttpResponse]: """ Get chart data from an workout gpx file, to display it with Recharts @@ -688,7 +680,6 @@ def get_segment_chart_data( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id :param integer segment_id: segment id @@ -705,7 +696,7 @@ def get_segment_chart_data( """ return get_workout_data( - auth_user_id, workout_short_id, 'chart_data', segment_id + auth_user, workout_short_id, 'chart_data', segment_id ) @@ -714,7 +705,7 @@ def get_segment_chart_data( ) @authenticate def download_workout_gpx( - auth_user_id: int, workout_short_id: str + auth_user: User, workout_short_id: str ) -> Union[HttpResponse, Response]: """ Download gpx file @@ -732,7 +723,6 @@ def download_workout_gpx( HTTP/1.1 200 OK Content-Type: application/gpx+xml - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id :statuscode 200: success @@ -746,7 +736,7 @@ def download_workout_gpx( """ workout_uuid = decode_short_id(workout_short_id) workout = Workout.query.filter_by( - uuid=workout_uuid, user_id=auth_user_id + uuid=workout_uuid, user_id=auth_user.id ).first() if not workout: return DataNotFoundErrorResponse( @@ -852,7 +842,7 @@ def get_map_tile(s: str, z: str, x: str, y: str) -> Tuple[Response, int]: @workouts_blueprint.route('/workouts', methods=['POST']) @authenticate -def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]: +def post_workout(auth_user: User) -> Union[Tuple[Dict, int], HttpResponse]: """ Post an workout with a gpx file @@ -944,8 +934,6 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]: "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - :form file: gpx file (allowed extensions: .gpx, .zip) :form data: sport id and notes (example: ``{"sport_id": 1, "notes": ""}``) @@ -983,7 +971,7 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]: workout_file = request.files['file'] upload_dir = os.path.join( - current_app.config['UPLOAD_FOLDER'], 'workouts', str(auth_user_id) + current_app.config['UPLOAD_FOLDER'], 'workouts', str(auth_user.id) ) folders = { 'extract_dir': os.path.join(upload_dir, 'extract'), @@ -992,7 +980,7 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]: try: new_workouts = process_files( - auth_user_id, workout_data, workout_file, folders + auth_user.id, workout_data, workout_file, folders ) if len(new_workouts) > 0: response_object = { @@ -1021,7 +1009,7 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]: @workouts_blueprint.route('/workouts/no_gpx', methods=['POST']) @authenticate def post_workout_no_gpx( - auth_user_id: int, + auth_user: User, ) -> Union[Tuple[Dict, int], HttpResponse]: """ Post an workout without gpx file @@ -1114,8 +1102,6 @@ def post_workout_no_gpx( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) - : Union[Dict, HttpResponse]: """ Update an workout @@ -1265,7 +1250,6 @@ def update_workout( "status": "success" } - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id : Union[Tuple[Dict, int], HttpResponse]: """ Delete an workout @@ -1339,7 +1323,6 @@ def delete_workout( HTTP/1.1 204 NO CONTENT Content-Type: application/json - :param integer auth_user_id: authenticate user id (from JSON Web Token) :param string workout_short_id: workout short id :reqheader Authorization: OAuth 2.0 Bearer Token @@ -1359,7 +1342,7 @@ def delete_workout( workout = Workout.query.filter_by(uuid=workout_uuid).first() if not workout: return DataNotFoundErrorResponse('workouts') - error_response = can_view_workout(auth_user_id, workout.user_id) + error_response = can_view_workout(auth_user.id, workout.user_id) if error_response: return error_response From 9e7fbd6eb4e31d12336887fee4276fe7651a0d5e Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Dec 2021 19:31:42 +0100 Subject: [PATCH 2/6] API - remove useless user queries --- fittrackee/tests/workouts/test_gpx_utils.py | 4 ++-- fittrackee/users/utils.py | 8 -------- fittrackee/workouts/utils.py | 15 +++++++-------- fittrackee/workouts/workouts.py | 2 +- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/fittrackee/tests/workouts/test_gpx_utils.py b/fittrackee/tests/workouts/test_gpx_utils.py index 7c80d5de..df5da68c 100644 --- a/fittrackee/tests/workouts/test_gpx_utils.py +++ b/fittrackee/tests/workouts/test_gpx_utils.py @@ -46,7 +46,7 @@ class TestStoppedSpeedThreshold: ) as gpx_track_segment_mock: process_files( - auth_user_id=user_1.id, + auth_user=user_1, folders=folders, workout_data={'sport_id': sport_id}, workout_file=gpx_file_storage, @@ -76,7 +76,7 @@ class TestStoppedSpeedThreshold: ) as gpx_track_segment_mock: process_files( - auth_user_id=user_1.id, + auth_user=user_1, folders=folders, workout_data={'sport_id': sport_1_cycling.id}, workout_file=gpx_file_storage, diff --git a/fittrackee/users/utils.py b/fittrackee/users/utils.py index 6f6a1984..cd881874 100644 --- a/fittrackee/users/utils.py +++ b/fittrackee/users/utils.py @@ -12,14 +12,6 @@ from fittrackee.responses import ( from .models import User -def is_admin(user_id: int) -> bool: - """ - Return if user has admin rights - """ - user = User.query.filter_by(id=user_id).first() - return user.admin - - def is_valid_email(email: str) -> bool: """ Return if email format is valid diff --git a/fittrackee/workouts/utils.py b/fittrackee/workouts/utils.py index 95488cbf..015b825b 100644 --- a/fittrackee/workouts/utils.py +++ b/fittrackee/workouts/utils.py @@ -299,9 +299,9 @@ def process_one_gpx_file( gpx_data, map_data, weather_data = get_gpx_info( params['file_path'], stopped_speed_threshold ) - auth_user_id = params['user'].id + auth_user = params['auth_user'] new_filepath = get_new_file_path( - auth_user_id=auth_user_id, + auth_user_id=auth_user.id, workout_date=gpx_data['start'], old_filename=filename, sport=params['sport_label'], @@ -311,7 +311,7 @@ def process_one_gpx_file( gpx_data['filename'] = new_filepath map_filepath = get_new_file_path( - auth_user_id=auth_user_id, + auth_user_id=auth_user.id, workout_date=gpx_data['start'], extension='.png', sport=params['sport_label'], @@ -325,7 +325,7 @@ def process_one_gpx_file( try: new_workout = create_workout( - params['user'], params['workout_data'], gpx_data + auth_user, params['workout_data'], gpx_data ) new_workout.map = map_filepath new_workout.map_id = get_map_hash(map_filepath) @@ -380,7 +380,7 @@ def process_zip_archive( def process_files( - auth_user_id: int, + auth_user: User, workout_data: Dict, workout_file: FileStorage, folders: Dict, @@ -399,9 +399,8 @@ def process_files( 'error', f"Sport id: {workout_data.get('sport_id')} does not exist", ) - user = User.query.filter_by(id=auth_user_id).first() sport_preferences = UserSportPreference.query.filter_by( - user_id=user.id, sport_id=sport.id + user_id=auth_user.id, sport_id=sport.id ).first() stopped_speed_threshold = ( sport.stopped_speed_threshold @@ -410,7 +409,7 @@ def process_files( ) common_params = { - 'user': user, + 'auth_user': auth_user, 'workout_data': workout_data, 'file_path': file_path, 'sport_label': sport.label, diff --git a/fittrackee/workouts/workouts.py b/fittrackee/workouts/workouts.py index 192e7217..e0828c11 100644 --- a/fittrackee/workouts/workouts.py +++ b/fittrackee/workouts/workouts.py @@ -980,7 +980,7 @@ def post_workout(auth_user: User) -> Union[Tuple[Dict, int], HttpResponse]: try: new_workouts = process_files( - auth_user.id, workout_data, workout_file, folders + auth_user, workout_data, workout_file, folders ) if len(new_workouts) > 0: response_object = { From c4d19089e40ed0197fd192b6ccdb71ac153bf9a6 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Dec 2021 19:39:45 +0100 Subject: [PATCH 3/6] update documentation --- docs/api/configuration.html | 15 ++++------- docs/api/records.html | 11 +++----- docs/api/sports.html | 13 +++------ docs/api/stats.html | 13 +++------ docs/api/users.html | 18 ++++--------- docs/api/workouts.html | 53 +++++++++++-------------------------- docs/searchindex.js | 2 +- fittrackee/users/utils.py | 4 +-- 8 files changed, 37 insertions(+), 92 deletions(-) diff --git a/docs/api/configuration.html b/docs/api/configuration.html index 2b5f4f41..7837f53a 100644 --- a/docs/api/configuration.html +++ b/docs/api/configuration.html @@ -191,13 +191,8 @@
-
Parameters
+
Request JSON Object
    -
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
-
-
Request JSON Object
-
  • gpx_limit_import (integer) – max number of files in zip archive

  • is_registration_enabled (boolean) – is registration enabled ?

  • max_single_file_size (integer) – max size of a single file

  • @@ -205,13 +200,13 @@
  • max_users (integer) – max users allowed to register on instance

-
Request Headers
-
    +
    Request Headers
    +
    -
    Status Codes
    -
      +
      Status Codes
      +
      • 200 OK – success

      • 400 Bad Request – invalid payload

      • 401 Unauthorized

          diff --git a/docs/api/records.html b/docs/api/records.html index ee46ed6c..1bb1015a 100644 --- a/docs/api/records.html +++ b/docs/api/records.html @@ -212,18 +212,13 @@
          -
          Parameters
          +
          Request Headers
            -
          • auth_user_id (integer) – authenticate user id (from JSON Web Token)

          • -
          -
          -
          Request Headers
          -
          -
          Status Codes
          -
            +
            Status Codes
            +
            • 200 OK – success

            • 401 Unauthorized

              • provide a valid auth token

              • diff --git a/docs/api/sports.html b/docs/api/sports.html index a2f65223..860d8d06 100644 --- a/docs/api/sports.html +++ b/docs/api/sports.html @@ -270,18 +270,13 @@
                -
                Parameters
                +
                Request Headers
                  -
                • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                • -
                -
                -
                Request Headers
                -
                -
                Status Codes
                -
                  +
                  Status Codes
                  +
                  • 200 OK – success

                  • 401 Unauthorized

                    • provide a valid auth token

                    • @@ -368,7 +363,6 @@
                      Parameters
                        -
                      • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                      • sport_id (integer) – sport id

                      @@ -444,7 +438,6 @@ Authenticated user must be an admin

                      Parameters
                        -
                      • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                      • sport_id (integer) – sport id

                      diff --git a/docs/api/stats.html b/docs/api/stats.html index d1bb4f5f..9b767bd2 100644 --- a/docs/api/stats.html +++ b/docs/api/stats.html @@ -206,7 +206,6 @@
                      Parameters
                        -
                      • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                      • user_name (integer) – user name

                      @@ -321,7 +320,6 @@
                      Parameters
                        -
                      • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                      • user_name (integer) – user name

                      @@ -378,18 +376,13 @@
                      -
                      Parameters
                      +
                      Request Headers
                        -
                      • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                      • -
                      -
                      -
                      Request Headers
                      -
                      -
                      Status Codes
                      -
                        +
                        Status Codes
                        +
                        • 200 OK – success

                        • 401 Unauthorized

                          • provide a valid auth token

                          • diff --git a/docs/api/users.html b/docs/api/users.html index bb5a4cbd..c273cc59 100644 --- a/docs/api/users.html +++ b/docs/api/users.html @@ -242,13 +242,8 @@
                            -
                            Parameters
                            +
                            Query Parameters
                              -
                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                            • -
                            -
                            -
                            Query Parameters
                            -
                            • page (integer) – page if using pagination (default: 1)

                            • per_page (integer) – number of users per page (default: 10, max: 50)

                            • q (string) – query on user name

                            • @@ -257,13 +252,13 @@
                            • order (string) – sorting order (default: asc)

                            -
                            Request Headers
                            -
                              +
                              Request Headers
                              +
                              -
                              Status Codes
                              -
                                +
                                Status Codes
                                +
                                • 200 OK – success

                                • 401 Unauthorized

                                  • provide a valid auth token

                                  • @@ -361,7 +356,6 @@
                                    Parameters
                                      -
                                    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                    • user_name (integer) – user name

                                    @@ -507,7 +501,6 @@
                                    Parameters
                                      -
                                    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                    • user_name (string) – user name

                                    @@ -561,7 +554,6 @@ one admin

                                    Parameters
                                      -
                                    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                    • user_name (string) – user name

                                    diff --git a/docs/api/workouts.html b/docs/api/workouts.html index 8e1cd3eb..e8c066f3 100644 --- a/docs/api/workouts.html +++ b/docs/api/workouts.html @@ -241,13 +241,8 @@
                                    -
                                    Parameters
                                    +
                                    Query Parameters
                                      -
                                    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                    • -
                                    -
                                    -
                                    Query Parameters
                                    -
                                    • page (integer) – page if using pagination (default: 1)

                                    • per_page (integer) – number of workouts per page (default: 5, max: 100)

                                    • @@ -265,13 +260,13 @@
                                    • order (string) – sorting order (default: desc)

                                    -
                                    Request Headers
                                    -
                                      +
                                      Request Headers
                                      +
                                      -
                                      Status Codes
                                      -
                                        +
                                        Status Codes
                                        +
                                        • 200 OK – success

                                        • 401 Unauthorized

                                          • provide a valid auth token

                                          • @@ -355,7 +350,6 @@
                                            Parameters
                                              -
                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                            • workout_short_id (string) – workout short id

                                            @@ -405,7 +399,6 @@
                                            Parameters
                                              -
                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                            • workout_short_id (string) – workout short id

                                            @@ -478,7 +471,6 @@
                                            Parameters
                                              -
                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                            • workout_short_id (string) – workout short id

                                            @@ -551,7 +543,6 @@
                                            Parameters
                                              -
                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                            • workout_short_id (string) – workout short id

                                            • segment_id (integer) – segment id

                                            @@ -603,7 +594,6 @@
                                            Parameters
                                              -
                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                            • workout_short_id (string) – workout short id

                                            • segment_id (integer) – segment id

                                            @@ -708,7 +698,6 @@
                                            Parameters
                                              -
                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                            • workout_short_id (string) – workout short id

                                            @@ -820,24 +809,19 @@
                                            -
                                            Parameters
                                            +
                                            Form Parameters
                                              -
                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                            • -
                                            -
                                            -
                                            Form Parameters
                                            -
                                            • file – gpx file (allowed extensions: .gpx, .zip)

                                            • data – sport id and notes (example: {"sport_id": 1, "notes": ""})

                                            -
                                            Request Headers
                                            -
                                              +
                                              Request Headers
                                              +
                                              -
                                              Status Codes
                                              -
                                                +
                                                Status Codes
                                                +
                                                • 201 Created – workout created

                                                • 400 Bad Request

                                                  • invalid payload

                                                  • @@ -948,13 +932,8 @@
                                                    -
                                                    Parameters
                                                    +
                                                    Request JSON Object
                                                      -
                                                    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                                    • -
                                                    -
                                                    -
                                                    Request JSON Object
                                                    -
                                                    • workout_date (string) – workout date (format: %Y-%m-%d %H:%M)

                                                    • distance (float) – workout distance in km

                                                    • duration (integer) – workout duration in seconds

                                                    • @@ -963,13 +942,13 @@
                                                    • title (string) – workout title

                                                    -
                                                    Request Headers
                                                    -
                                                      +
                                                      Request Headers
                                                      +
                                                      -
                                                      Status Codes
                                                      -
                                                        +
                                                        Status Codes
                                                        +
                                                        • 201 Created – workout created

                                                        • 400 Bad Request – invalid payload

                                                        • 401 Unauthorized

                                                            @@ -1075,7 +1054,6 @@
                                                            Parameters
                                                              -
                                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                                            • workout_short_id (string) – workout short id

                                                            @@ -1131,7 +1109,6 @@
                                                            Parameters
                                                              -
                                                            • auth_user_id (integer) – authenticate user id (from JSON Web Token)

                                                            • workout_short_id (string) – workout short id

                                                            diff --git a/docs/searchindex.js b/docs/searchindex.js index 7519b655..e47e0cdd 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["api/auth","api/configuration","api/index","api/records","api/sports","api/stats","api/users","api/workouts","changelog","features","index","installation","troubleshooting/administrator","troubleshooting/index","troubleshooting/user"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["api/auth.rst","api/configuration.rst","api/index.rst","api/records.rst","api/sports.rst","api/stats.rst","api/users.rst","api/workouts.rst","changelog.md","features.rst","index.rst","installation.rst","troubleshooting/administrator.rst","troubleshooting/index.rst","troubleshooting/user.rst"],objects:{"":[[0,0,1,"post--api-auth-login","/api/auth/login"],[0,1,1,"get--api-auth-logout","/api/auth/logout"],[0,0,1,"post--api-auth-password-reset-request","/api/auth/password/reset-request"],[0,0,1,"post--api-auth-password-update","/api/auth/password/update"],[0,2,1,"delete--api-auth-picture","/api/auth/picture"],[0,0,1,"post--api-auth-picture","/api/auth/picture"],[0,1,1,"get--api-auth-profile","/api/auth/profile"],[0,0,1,"post--api-auth-profile-edit","/api/auth/profile/edit"],[0,0,1,"post--api-auth-profile-edit-preferences","/api/auth/profile/edit/preferences"],[0,0,1,"post--api-auth-profile-edit-sports","/api/auth/profile/edit/sports"],[0,0,1,"post--api-auth-register","/api/auth/register"],[1,1,1,"get--api-config","/api/config"],[1,3,1,"patch--api-config","/api/config"],[1,1,1,"get--api-ping","/api/ping"],[3,1,1,"get--api-records","/api/records"],[4,1,1,"get--api-sports","/api/sports"],[4,1,1,"get--api-sports-(int-sport_id)","/api/sports/(int:sport_id)"],[4,3,1,"patch--api-sports-(int-sport_id)","/api/sports/(int:sport_id)"],[5,1,1,"get--api-stats-(user_name)-by_sport","/api/stats/(user_name)/by_sport"],[5,1,1,"get--api-stats-(user_name)-by_time","/api/stats/(user_name)/by_time"],[5,1,1,"get--api-stats-all","/api/stats/all"],[6,1,1,"get--api-users","/api/users"],[6,2,1,"delete--api-users-(user_name)","/api/users/(user_name)"],[6,1,1,"get--api-users-(user_name)","/api/users/(user_name)"],[6,3,1,"patch--api-users-(user_name)","/api/users/(user_name)"],[6,1,1,"get--api-users-(user_name)-picture","/api/users/(user_name)/picture"],[7,1,1,"get--api-workouts","/api/workouts"],[7,0,1,"post--api-workouts","/api/workouts"],[7,2,1,"delete--api-workouts-(string-workout_short_id)","/api/workouts/(string:workout_short_id)"],[7,1,1,"get--api-workouts-(string-workout_short_id)","/api/workouts/(string:workout_short_id)"],[7,3,1,"patch--api-workouts-(string-workout_short_id)","/api/workouts/(string:workout_short_id)"],[7,1,1,"get--api-workouts-(string-workout_short_id)-chart_data","/api/workouts/(string:workout_short_id)/chart_data"],[7,1,1,"get--api-workouts-(string-workout_short_id)-chart_data-segment-(int-segment_id)","/api/workouts/(string:workout_short_id)/chart_data/segment/(int:segment_id)"],[7,1,1,"get--api-workouts-(string-workout_short_id)-gpx","/api/workouts/(string:workout_short_id)/gpx"],[7,1,1,"get--api-workouts-(string-workout_short_id)-gpx-download","/api/workouts/(string:workout_short_id)/gpx/download"],[7,1,1,"get--api-workouts-(string-workout_short_id)-gpx-segment-(int-segment_id)","/api/workouts/(string:workout_short_id)/gpx/segment/(int:segment_id)"],[7,1,1,"get--api-workouts-map-(map_id)","/api/workouts/map/(map_id)"],[7,0,1,"post--api-workouts-no_gpx","/api/workouts/no_gpx"],[11,4,1,"-","APP_LOG"],[11,4,1,"-","APP_SECRET_KEY"],[11,4,1,"-","APP_SETTINGS"],[11,4,1,"-","APP_WORKERS"],[11,4,1,"-","DATABASE_DISABLE_POOLING"],[11,4,1,"-","DATABASE_URL"],[11,4,1,"envvar-DEFAULT_STATICMAP","DEFAULT_STATICMAP \ud83c\udd95"],[11,4,1,"-","EMAIL_URL"],[11,4,1,"-","FLASK_APP"],[11,4,1,"-","HOST"],[11,4,1,"-","MAP_ATTRIBUTION"],[11,4,1,"-","PORT"],[11,4,1,"-","REDIS_URL"],[11,4,1,"-","SENDER_EMAIL"],[11,4,1,"-","TILE_SERVER_URL"],[11,4,1,"-","UI_URL"],[11,4,1,"-","UPLOAD_FOLDER"],[11,4,1,"-","VUE_APP_API_URL"],[11,4,1,"-","WEATHER_API_KEY"],[11,4,1,"-","WORKERS_PROCESSES"]],"/api/workouts/map_tile/(s)/(z)/(x)/(y)":[[7,1,1,"get--api-workouts-map_tile-(s)-(z)-(x)-(y).png","png"]]},objnames:{"0":["http","post","HTTP post"],"1":["http","get","HTTP get"],"2":["http","delete","HTTP delete"],"3":["http","patch","HTTP patch"],"4":["std","envvar","environment variable"]},objtypes:{"0":"http:post","1":"http:get","2":"http:delete","3":"http:patch","4":"std:envvar"},terms:{"0":[0,1,3,4,5,6,7,9,10,11],"00":[0,3,6,7],"000000":0,"01":[0,3,5,6,7,10],"02":[7,10],"03":[6,7,10],"04":[7,10],"06":5,"07":[0,3,6,7,10],"08":[0,3,6],"09":[0,6,10],"0mb":[0,7],"1":[0,1,3,4,5,6,7,9,10,11],"10":[0,1,3,6,7,10,11],"100":[7,8,9],"1000":5,"101":8,"104":8,"1048576":1,"10485760":1,"109":8,"11":[0,3,6,9,10],"115":8,"116":8,"12":[0,3,6,7,10],"1232004":7,"12341":5,"1234538":7,"1267":5,"127":11,"13":[7,8],"14":[0,6,7,10],"15":[5,7,10],"150":5,"156":5,"1563529507772":7,"16":[5,7,10],"17":[7,10,11],"178":5,"18":[0,3,6,7,8],"19":10,"2":[0,1,3,4,5,6,7,10,11],"20":6,"200":[0,1,3,4,5,6,7],"201":[0,7],"2017":[5,7],"2018":[5,7,10],"2019":[0,3,5,6,7,10],"2020":10,"2021":10,"203":5,"204":[0,6,7],"21":10,"22":[7,8],"23":10,"24":8,"25":[8,11],"26":8,"27":[0,6],"279":7,"28":8,"280":7,"282":5,"29":10,"2930":7,"2e1ee2c":8,"3":[0,4,5,6,7,9,10,11],"30":[5,10],"3000":11,"301":11,"31":[7,10],"33":8,"34":8,"34614d5":8,"36":8,"37":8,"39":7,"4":[0,4,5,6,7,10,11],"40":8,"400":[0,1,4,7],"401":[0,1,3,4,5,6,7],"403":[0,1,4,5,6,7],"404":[0,4,5,6,7],"41":8,"4109":7,"413":[0,7],"43":8,"44":[7,8],"443":11,"45":7,"46":[5,8],"465":11,"47":[5,7,8],"48":5,"4c3fc34":8,"5":[1,4,5,6,7,9,10,11],"50":[0,6,8],"500":[0,1,4,6,7],"5000":11,"5078118":7,"5079733":7,"51":7,"53":8,"54":8,"5432":11,"57":[7,8],"58":[0,6,8],"587":11,"59":8,"6":[0,4,6,7,10],"613":5,"62":8,"63":7,"64":8,"66":8,"67":[0,6],"7":[7,10,11],"70":8,"71":8,"72":8,"7380":7,"75":8,"78":5,"79":8,"8":[0,7,10],"80":[8,11],"8025":11,"81":8,"82":8,"83":8,"84":8,"895":[0,6],"9":[0,3,6,10,11],"90":8,"91":8,"93":8,"95":[5,8],"98":8,"99":[5,8],"9960":5,"boolean":[0,1,6],"case":9,"default":[5,6,7,8,9,11],"do":[1,4,5,6,7],"export":10,"float":[0,7],"import":[8,11],"int":[4,7],"new":[0,9,11],"null":[0,4,6,7],"return":[3,7,11],"short":7,"static":[8,11],"switch":8,"true":[0,1,4,6,8,11],"try":[0,6,7],A:[6,8,9],AS:[0,3,6,7],For:[9,11],If:[9,11],In:[8,9],It:[8,9,10,12],NO:[0,6,7],NOT:[0,4,7],No:[0,6,7,8,10],Not:[4,5,6,7],OF:11,ON:11,On:11,One:11,TO:11,The:[8,9,11],There:11,To:11,WITH:11,With:11,_:8,__main__:11,_blank:11,access:11,account:[6,8],acit:7,activ:[4,8,9,10,11],ad:[0,8,9],adapt:11,add:[6,8,9,10],addit:11,address:11,admin:[0,1,3,4,5,6,7,8,9,11],administr:[0,6,7,10,13],after:[8,11],again:[0,1,3,4,5,6,7],agplv3:8,all:[3,4,5,6,11],allow:[0,1,7,8,10],along:7,alpin:9,alreadi:0,also:[8,10,11],altitud:8,alwai:11,an:[1,4,6,7,8,9,11],android:10,anoth:[6,11],anymor:8,apach:10,api:[0,1,3,4,5,6,7,8,9,10,11],apikei:11,app:10,app_log:11,app_secret_kei:11,app_set:11,app_work:11,appear:9,applic:[0,1,3,4,5,6,7,8,9,10,11],ar:[3,7,8,9,10,11,12],arch:11,archiv:[1,8,9,11],archlinux:11,asc:6,ascent:[7,9],attribut:11,auth:[0,1,3,4,5,6,7],auth_token:0,auth_user_id:[1,3,4,5,6,7],authent:[1,2,3,4,5,6,7,10],author:[0,1,3,4,5,6,7],avail:[0,3,9,10,11],ave_spe:7,ave_speed_from:7,ave_speed_to:7,averag:[3,7,8,9],average_spe:5,axi:7,b862a77:8,b:11,background:8,backup:11,bad:[0,1,4,7],bearer:[0,1,3,4,5,6,7],becom:8,been:8,befor:[8,11],begin:11,better:8,between:9,bike:[4,7,8,9],bin:11,bio:[0,6],biographi:0,birth:[0,8],birth_dat:[0,6],bound:7,build:11,button:8,by_sport:5,by_tim:5,c:7,calcul:8,calendar:[8,9],can:[6,8,9,10,11,12],cannot:8,cd:11,chang:[9,10,11],charact:[0,8],chart:[7,8,9,11],chart_data:7,check:[1,11,12],choos:[8,9],client:[8,11],client_max_body_s:11,clone:11,code:[0,1,3,4,5,6,7],color:[0,4,8,9],com:[0,6,11],complet:8,config:[1,11],configur:[2,8,9,10,11],confirm:0,contact:[0,6,7],contain:[8,9,11],content:[0,1,3,4,5,6,7],contributor:[1,8,11],control:8,coordin:11,copi:[1,11],copyright:[1,11],correctli:8,countri:9,cp:11,creat:[0,7,8,9,11],create_app:11,created_at:[0,6],creation:[8,9],creation_d:7,credenti:[0,11],criteria:6,cross:9,current:8,custom:11,cycl:[4,8,9],d:[0,5,7],dai:[8,9],dark:11,darkski:[8,9],dashboard:[8,10],data:[0,1,3,4,5,6,7,8,9,10,11],databas:[8,9,11,12],database_disable_pool:11,database_url:[8,11],date:[0,5,7,8,9],db:11,debian:11,default_staticmap:[8,11],defin:9,definit:8,delet:[0,6,7,8,9],depend:[8,11],deploy:10,desc:7,descent:[7,9],describ:11,descript:11,detail:[6,8,10],develop:[8,10],dialect:12,differ:8,directli:11,directori:[8,11],disabl:[0,8,9,11],displai:[7,8,9,10,11,12],distanc:[3,7,8,9],distance_from:7,distance_to:7,distribut:11,docker:[8,10],document:[8,10,11],doe:[0,5,6,7,8],don:0,down:8,download:[7,8,9,11],dramatiq:11,drop:8,dropdown:9,due:8,durat:[3,7,8,9],duration_from:7,duration_to:7,dure:[0,7],easi:8,edit:[0,8,9],electr:9,elev:[7,8,9,11],els:11,email:[0,6,8],email_url:11,empti:8,en:[0,6],enabl:[1,9],encount:11,end:[5,7],endpoint:[1,8],engin:[8,11,12],english:9,enter:[8,9],entiti:[0,7],entri:11,env:11,environ:[8,10,12],error:[0,1,4,6,7,8,9,11,12],europ:[0,6],evalu:[8,11],even:[8,9],exampl:[0,1,3,4,5,6,7,10,11],exc:12,exce:[0,7],exceed:8,except:6,execstart:11,exhaust:10,exist:[0,5,6,7,9,10,11],expir:[0,1,3,4,5,6,7],extens:[0,7],fa33f4d996844a5c73ecd1ae24456ab8:7,fail:[8,13],fals:[0,1,4,6,7,11],farest:[3,8,9],fd:[0,3,6,7],featur:[10,11],fetch:11,file:[0,1,7,8,9,10,11],filter:[8,9],first:[0,9,10],first_nam:[0,6],fitotrack:10,fittracke:[9,11,13],fittrackee_cli:11,fittrackee_init_data:11,fittrackee_upgrade_db:11,fittrackee_work:11,fix:10,flask:11,flask_app:11,flaticon:11,fmstrat:8,follow:[3,9,11,12],forbidden:[0,1,4,5,6,7],forecast:11,form:[0,7],format:[0,5,7],former:11,forrunn:10,forward:11,found:[0,4,5,6,7],fr:6,frame:5,freepik:11,french:[9,10],fri:7,from:[1,3,4,5,6,7,8,10],full:8,fullchain:11,gener:[8,11],get:[0,1,3,4,5,6,7],gif:0,git:11,github:11,given:11,gmt:[0,3,6,7],gpl:10,gpx:[7,8,9,10,11],gpx_limit_import:1,gpxpy:[0,9,11],grant:11,graph:8,greater:8,gunicorn:[11,12],gz:11,h:[7,9],ha:[6,9],handl:[0,9,11],has_workout:4,have:[1,4,5,6,7,8],he:6,header:[0,1,3,4,5,6,7],health:1,heavi:[10,11],hexadecim:0,hi:[6,8,9],hike:[4,8,9],home:11,host:11,href:[1,11],http:[0,1,3,4,5,6,7,11],hvybqybra7wwxpastwr4v2:[0,3,6],i18n:8,icon:11,id:[0,1,3,4,5,6,7],imag:[0,6,7,8,9,11],imperi:[8,9],imperial_unit:[0,6],improv:10,incorrect:8,index:7,info:0,inform:[8,10,11],init:11,initi:11,initialis:11,insid:11,instal:[8,10],instanc:[1,9,11],instead:9,integ:[1,3,4,5,6,7],interceptor:8,interfac:11,intern:[0,1,4,6,7],introduc:8,invalid:[0,1,3,4,5,6,7,8,11],io:11,ip:11,is_act:[0,4],is_active_for_us:4,is_registration_en:1,issu:[10,11],jan:7,javascript:8,john_do:6,jpeg:6,jpg:0,js:11,json:[0,1,3,4,5,6,7],jul:[0,3,6,7],keep:[8,10,11],kei:[8,9,11],kjxavsturjvoah2wvcegef:7,km:[7,9],label:4,languag:[0,6,9],larg:[0,7,9],larger:11,last:[0,11],last_nam:[0,6],latitud:7,layer:[8,11],ld:[0,3,6,7],leaflet:[7,11],least:7,less:8,librari:11,licens:[8,10],like:[9,11],limit:[8,9],link:11,linux:11,list:[8,10,11],listen:11,load:[8,12],local:[8,10,11],localhost:11,locat:[0,6,11],log:[0,1,3,4,5,6,7,10,11,12],logfil:11,login:0,logo:11,logout:[0,8],longer:[8,12],longest:[3,8,9],longitud:7,m:[0,5,7],made:11,mai:[9,10,11],mailhog:11,major:8,make:[8,11],makefil:11,manag:8,mandatori:[7,8,11],map:[7,8,9,10],map_attribut:[1,11],map_id:7,map_til:7,match:0,max:[1,6,7,8],max_alt:7,max_single_file_s:1,max_spe:7,max_speed_from:7,max_speed_to:7,max_us:1,max_zip_file_s:1,maxim:7,maximum:[3,8,9],messag:[0,1,7,8],method:11,metric:9,migrat:8,min:8,min_alt:7,minim:7,minor:10,miss:8,mobil:10,model:8,modifi:[6,8],modification_d:7,modul:11,mon:7,mondai:[0,5,9],montain:8,month:[5,8,9],more:[8,9,10,11],morn:7,mountain:[4,9],mous:8,move:[7,8],movement:8,mpwoadmin:11,ms:[0,3,6,7],multi:11,multipart:[0,7],must:[0,1,4,8,9,11,12],mv:11,n:0,name:[0,5,6,11],nano:11,nb_sport:[0,6],nb_workout:[0,5,6],necessari:[9,11],need:11,network:11,next:9,next_workout:7,nginx:[9,11],no_gpx:7,non:[4,10],noopen:11,noreferr:11,nosuchmoduleerror:12,note:[7,8,9,11],now:[8,9,11],number:[1,6,7,8,9,11],oauth:[0,1,3,4,5,6,7],object:[0,1,4,6,7],ok:[0,1,3,4,5,6,7],one:[6,7,9],onli:[6,7,8,9,11],open:[10,11],openstreetmap:[1,8,11],opentrack:10,option:[8,11],order:[6,7,8],order_bi:6,org:[1,11],os:11,other:[6,11],out:0,outdoor:[8,10,11],over:8,overrid:9,overridden:9,overwrit:11,own:[6,10],owner:[8,9],packag:[8,11],paf38:8,page:[6,7],pagin:[6,7],par_pag:6,paramet:[0,1,3,4,5,6,7,8,9],pari:[0,6],pars:11,part:[0,7],pass:11,password:[0,8,9,11],password_conf:0,patch:[1,4,6,7],path:11,paus:[7,8],payload:[0,1,4,7],pem:11,per:[6,7,8],per_pag:[6,7],period:9,permiss:[1,4,5,6,7],pg_dump:11,pictur:[0,6,7],ping:1,pip:11,pipenv:8,pleas:[0,1,3,4,5,6,7,8],plugin:12,png:[0,7,11],poetri:[8,11],point:[8,11],pong:1,pool:11,port:11,possibl:[8,10],post:[0,7],postgr:[8,12],postgresql:[8,11,12],prefer:[0,8],prerequisit:10,previous_workout:7,privileg:11,privkei:11,process:[0,9,11],productionconfig:11,profil:0,project:11,provid:[0,1,3,4,5,6,7,8,9,11],proxi:11,proxy_add_x_forwarded_for:11,proxy_pass:11,proxy_redirect:11,proxy_set_head:11,pull:11,purpos:[8,11],pwd:11,py:11,pypi:10,python:[8,11],q:6,queri:[5,6,7],queue:11,r:11,rais:9,read:8,real:11,rebuild:8,rechart:7,recommend:11,record:[0,2,6,7,8,9,10],record_typ:[0,3,6,7],redi:[8,11],redis_url:11,refactor:8,regist:[0,1,11],registr:[0,1,8,9],rel:11,relat:[9,11],releas:[10,11],remain:8,remote_addr:11,remov:9,renam:8,replac:[8,11],repo:11,repositori:11,request:[0,1,3,4,5,6,7],request_uri:11,requir:0,reset:[0,8,9],respons:[0,1,3,4,5,6,7],restart:11,restartsec:11,right:[6,8,9],rout:8,row:9,run:[4,8,9,11],runner:10,s:[6,7,8,9,11],sam:[0,6],same:8,samr1:11,sat:6,save:[8,9],schema:11,screen:8,search:8,second:7,secret:11,see:[8,9,10,11],seem:8,segment:[7,8,9],segment_id:7,select:[0,7],send:[8,11],sender:11,sender_email:11,serv:11,server:[0,1,4,6,7,8,9,10],server_nam:11,servic:11,set:[8,9],sever:[10,11],shell:11,should:11,show:8,shown:8,side:8,signatur:[0,1,3,4,5,6,7],simpl:11,simplifi:8,sinc:11,singl:[1,6],size:[0,1,7,8,9],ski:9,sky:11,slow:8,smtp:11,some:[6,7,8,10,11],sorri:0,sort:[6,7],sourc:10,spawn:11,speed:[0,3,7,8,9,11],spinner:8,sport:[0,2,5,7,8,9,10,11],sport_id:[0,3,4,5,6,7],sports_list:[0,6],sql:11,sqlalchemi:[8,11,12],ssl:11,ssl_certif:11,ssl_certificate_kei:11,standard:[8,11],standarderror:11,standardoutput:11,start:[0,5,7,8,9,11,13],startlimitintervalsec:11,starttl:11,stat:[5,8],staticmap:11,statist:[2,10],statu:[0,1,3,4,5,6,7],step:11,still:[9,10],stop:[0,8,9,11],stopped_speed_threshold:[0,4],store:[9,10],street:10,string:[0,4,5,6,7],subdomain:7,success:[0,1,3,4,5,6,7],successfulli:0,sun:[0,3,6,7],sundai:[5,7,9],support:[8,9,12],syslog:11,syslogidentifi:11,system:[9,11],systemd:11,t:[0,12],tar:11,target:11,task:11,term:[8,11],test:11,textarea:8,than:8,thank:8,thei:11,them:10,thi:[7,8,9,10,11],threshold:[0,8,9],thunderforest:[8,11],tile:[7,8],tile_server_url:11,time:[0,5,7,8,9],timezon:[0,6,8,9],titl:7,tl:11,todo:14,token:[0,1,3,4,5,6,7],too:[0,7],tool:11,tooltip:8,total:[8,9],total_asc:5,total_dist:[0,5,6],total_dur:[0,5,6],track:10,trail:9,transport:[4,8,9],troubleshoot:10,type:[0,1,3,4,5,6,7,11],typescript:11,u:11,ui:8,ui_url:11,unauthor:[0,1,3,4,5,6,7],under:[10,11],unencrypt:11,unit:[8,11],unstabl:[10,11],up:[9,10],updat:[0,1,4,6,7,8,9,11],upload:[8,9,11],upload_fold:11,uploads_dir_s:5,url:[8,11,12],us:[0,6,7,8,9,10,11],user:[0,1,2,3,4,5,7,8,9,10,11,13],user_id:0,user_nam:[5,6],usernam:[0,6,11],uuid:[7,8],v0:11,v3:10,valid:[0,1,3,4,5,6,7,11],valu:[0,3,6,7],variabl:[8,10,12],venv:11,version:[1,10,11],view:8,virtualenv:11,vue3:11,vue:11,vue_app_api_url:11,vuex:11,wa:8,wai:11,walk:[4,8,9],wantedbi:11,warn:8,weather:[8,9,11],weather_api:11,weather_api_kei:11,weather_end:7,weather_start:7,web:[0,1,3,4,5,6,7,10,11],week:[0,5,8,9],weekend:8,weekm:[0,5],were:8,wget:11,when:[0,1,8,9,11],where:11,which:9,with_gpx:7,without:[5,6,7,8,9,10],worker:11,workers_process:11,workingdirectori:11,workout:[0,2,5,8,10],workout_d:[0,3,6,7],workout_id:[0,3,6,7],workout_short_id:7,workouts_count:6,written:11,www:[1,11],x:[7,11],xml:7,xxxx:11,xzf:11,y:[0,5,7,11],yai:11,yarn:11,year:[5,9],yet:10,you:[1,4,5,6,7,10],your:[6,10,11],z:[7,11],zip:[1,7,8,9],zone:0,zoom:7},titles:["Authentication","Configuration","API documentation","Records","Sports","Statistics","Users","Workouts","Change log","Features","FitTrackee","Installation","Administrator","Troubleshooting","User"],titleterms:{"0":8,"01":8,"02":8,"03":8,"04":8,"07":8,"09":8,"1":8,"10":8,"11":8,"12":8,"14":8,"15":8,"16":8,"17":8,"19":8,"2":8,"2018":8,"2019":8,"2020":8,"2021":8,"21":8,"23":8,"29":8,"3":8,"30":8,"31":8,"4":8,"5":8,"6":8,"7":8,"8":8,"9":8,"new":8,account:9,administr:[8,9,12],api:2,authent:0,avail:8,bug:8,chang:8,close:8,configur:1,content:10,dashboard:9,deploy:11,detail:9,dev:11,develop:11,docker:11,document:2,email:11,endpoint:[2,13],environ:11,fail:12,featur:[8,9],first:8,fittracke:[8,10,12],fix:8,french:8,from:11,improv:8,instal:11,issu:8,list:9,log:8,map:11,minor:8,misc:8,prefer:9,prerequisit:11,prod:11,product:11,pull:8,pypi:[8,11],record:3,releas:8,request:8,server:11,sourc:11,sport:4,start:12,statist:[5,8,9],tabl:10,tile:11,translat:9,troubleshoot:13,upgrad:11,user:[6,14],variabl:11,version:8,workout:[7,9]}}) \ No newline at end of file +Search.setIndex({docnames:["api/auth","api/configuration","api/index","api/records","api/sports","api/stats","api/users","api/workouts","changelog","features","index","installation","troubleshooting/administrator","troubleshooting/index","troubleshooting/user"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["api/auth.rst","api/configuration.rst","api/index.rst","api/records.rst","api/sports.rst","api/stats.rst","api/users.rst","api/workouts.rst","changelog.md","features.rst","index.rst","installation.rst","troubleshooting/administrator.rst","troubleshooting/index.rst","troubleshooting/user.rst"],objects:{"":[[0,0,1,"post--api-auth-login","/api/auth/login"],[0,1,1,"get--api-auth-logout","/api/auth/logout"],[0,0,1,"post--api-auth-password-reset-request","/api/auth/password/reset-request"],[0,0,1,"post--api-auth-password-update","/api/auth/password/update"],[0,2,1,"delete--api-auth-picture","/api/auth/picture"],[0,0,1,"post--api-auth-picture","/api/auth/picture"],[0,1,1,"get--api-auth-profile","/api/auth/profile"],[0,0,1,"post--api-auth-profile-edit","/api/auth/profile/edit"],[0,0,1,"post--api-auth-profile-edit-preferences","/api/auth/profile/edit/preferences"],[0,0,1,"post--api-auth-profile-edit-sports","/api/auth/profile/edit/sports"],[0,0,1,"post--api-auth-register","/api/auth/register"],[1,1,1,"get--api-config","/api/config"],[1,3,1,"patch--api-config","/api/config"],[1,1,1,"get--api-ping","/api/ping"],[3,1,1,"get--api-records","/api/records"],[4,1,1,"get--api-sports","/api/sports"],[4,1,1,"get--api-sports-(int-sport_id)","/api/sports/(int:sport_id)"],[4,3,1,"patch--api-sports-(int-sport_id)","/api/sports/(int:sport_id)"],[5,1,1,"get--api-stats-(user_name)-by_sport","/api/stats/(user_name)/by_sport"],[5,1,1,"get--api-stats-(user_name)-by_time","/api/stats/(user_name)/by_time"],[5,1,1,"get--api-stats-all","/api/stats/all"],[6,1,1,"get--api-users","/api/users"],[6,2,1,"delete--api-users-(user_name)","/api/users/(user_name)"],[6,1,1,"get--api-users-(user_name)","/api/users/(user_name)"],[6,3,1,"patch--api-users-(user_name)","/api/users/(user_name)"],[6,1,1,"get--api-users-(user_name)-picture","/api/users/(user_name)/picture"],[7,1,1,"get--api-workouts","/api/workouts"],[7,0,1,"post--api-workouts","/api/workouts"],[7,2,1,"delete--api-workouts-(string-workout_short_id)","/api/workouts/(string:workout_short_id)"],[7,1,1,"get--api-workouts-(string-workout_short_id)","/api/workouts/(string:workout_short_id)"],[7,3,1,"patch--api-workouts-(string-workout_short_id)","/api/workouts/(string:workout_short_id)"],[7,1,1,"get--api-workouts-(string-workout_short_id)-chart_data","/api/workouts/(string:workout_short_id)/chart_data"],[7,1,1,"get--api-workouts-(string-workout_short_id)-chart_data-segment-(int-segment_id)","/api/workouts/(string:workout_short_id)/chart_data/segment/(int:segment_id)"],[7,1,1,"get--api-workouts-(string-workout_short_id)-gpx","/api/workouts/(string:workout_short_id)/gpx"],[7,1,1,"get--api-workouts-(string-workout_short_id)-gpx-download","/api/workouts/(string:workout_short_id)/gpx/download"],[7,1,1,"get--api-workouts-(string-workout_short_id)-gpx-segment-(int-segment_id)","/api/workouts/(string:workout_short_id)/gpx/segment/(int:segment_id)"],[7,1,1,"get--api-workouts-map-(map_id)","/api/workouts/map/(map_id)"],[7,0,1,"post--api-workouts-no_gpx","/api/workouts/no_gpx"],[11,4,1,"-","APP_LOG"],[11,4,1,"-","APP_SECRET_KEY"],[11,4,1,"-","APP_SETTINGS"],[11,4,1,"-","APP_WORKERS"],[11,4,1,"-","DATABASE_DISABLE_POOLING"],[11,4,1,"-","DATABASE_URL"],[11,4,1,"envvar-DEFAULT_STATICMAP","DEFAULT_STATICMAP \ud83c\udd95"],[11,4,1,"-","EMAIL_URL"],[11,4,1,"-","FLASK_APP"],[11,4,1,"-","HOST"],[11,4,1,"-","MAP_ATTRIBUTION"],[11,4,1,"-","PORT"],[11,4,1,"-","REDIS_URL"],[11,4,1,"-","SENDER_EMAIL"],[11,4,1,"-","TILE_SERVER_URL"],[11,4,1,"-","UI_URL"],[11,4,1,"-","UPLOAD_FOLDER"],[11,4,1,"-","VUE_APP_API_URL"],[11,4,1,"-","WEATHER_API_KEY"],[11,4,1,"-","WORKERS_PROCESSES"]],"/api/workouts/map_tile/(s)/(z)/(x)/(y)":[[7,1,1,"get--api-workouts-map_tile-(s)-(z)-(x)-(y).png","png"]]},objnames:{"0":["http","post","HTTP post"],"1":["http","get","HTTP get"],"2":["http","delete","HTTP delete"],"3":["http","patch","HTTP patch"],"4":["std","envvar","environment variable"]},objtypes:{"0":"http:post","1":"http:get","2":"http:delete","3":"http:patch","4":"std:envvar"},terms:{"0":[0,1,3,4,5,6,7,9,10,11],"00":[0,3,6,7],"000000":0,"01":[0,3,5,6,7,10],"02":[7,10],"03":[6,7,10],"04":[7,10],"06":5,"07":[0,3,6,7,10],"08":[0,3,6],"09":[0,6,10],"0mb":[0,7],"1":[0,1,3,4,5,6,7,9,10,11],"10":[0,1,3,6,7,10,11],"100":[7,8,9],"1000":5,"101":8,"104":8,"1048576":1,"10485760":1,"109":8,"11":[0,3,6,9,10],"115":8,"116":8,"12":[0,3,6,7,10],"1232004":7,"12341":5,"1234538":7,"1267":5,"127":11,"13":[7,8],"14":[0,6,7,10],"15":[5,7,10],"150":5,"156":5,"1563529507772":7,"16":[5,7,10],"17":[7,10,11],"178":5,"18":[0,3,6,7,8],"19":10,"2":[0,1,3,4,5,6,7,10,11],"20":6,"200":[0,1,3,4,5,6,7],"201":[0,7],"2017":[5,7],"2018":[5,7,10],"2019":[0,3,5,6,7,10],"2020":10,"2021":10,"203":5,"204":[0,6,7],"21":10,"22":[7,8],"23":10,"24":8,"25":[8,11],"26":8,"27":[0,6],"279":7,"28":8,"280":7,"282":5,"29":10,"2930":7,"2e1ee2c":8,"3":[0,4,5,6,7,9,10,11],"30":[5,10],"3000":11,"301":11,"31":[7,10],"33":8,"34":8,"34614d5":8,"36":8,"37":8,"39":7,"4":[0,4,5,6,7,10,11],"40":8,"400":[0,1,4,7],"401":[0,1,3,4,5,6,7],"403":[0,1,4,5,6,7],"404":[0,4,5,6,7],"41":8,"4109":7,"413":[0,7],"43":8,"44":[7,8],"443":11,"45":7,"46":[5,8],"465":11,"47":[5,7,8],"48":5,"4c3fc34":8,"5":[1,4,5,6,7,9,10,11],"50":[0,6,8],"500":[0,1,4,6,7],"5000":11,"5078118":7,"5079733":7,"51":7,"53":8,"54":8,"5432":11,"57":[7,8],"58":[0,6,8],"587":11,"59":8,"6":[0,4,6,7,10],"613":5,"62":8,"63":7,"64":8,"66":8,"67":[0,6],"7":[7,10,11],"70":8,"71":8,"72":8,"7380":7,"75":8,"78":5,"79":8,"8":[0,7,10],"80":[8,11],"8025":11,"81":8,"82":8,"83":8,"84":8,"895":[0,6],"9":[0,3,6,10,11],"90":8,"91":8,"93":8,"95":[5,8],"98":8,"99":[5,8],"9960":5,"boolean":[0,1,6],"case":9,"default":[5,6,7,8,9,11],"do":[1,4,5,6,7],"export":10,"float":[0,7],"import":[8,11],"int":[4,7],"new":[0,9,11],"null":[0,4,6,7],"return":[3,7,11],"short":7,"static":[8,11],"switch":8,"true":[0,1,4,6,8,11],"try":[0,6,7],A:[6,8,9],AS:[0,3,6,7],For:[9,11],If:[9,11],In:[8,9],It:[8,9,10,12],NO:[0,6,7],NOT:[0,4,7],No:[0,6,7,8,10],Not:[4,5,6,7],OF:11,ON:11,On:11,One:11,TO:11,The:[8,9,11],There:11,To:11,WITH:11,With:11,_:8,__main__:11,_blank:11,access:11,account:[6,8],acit:7,activ:[4,8,9,10,11],ad:[0,8,9],adapt:11,add:[6,8,9,10],addit:11,address:11,admin:[0,1,3,4,5,6,7,8,9,11],administr:[0,6,7,10,13],after:[8,11],again:[0,1,3,4,5,6,7],agplv3:8,all:[3,4,5,6,11],allow:[0,1,7,8,10],along:7,alpin:9,alreadi:0,also:[8,10,11],altitud:8,alwai:11,an:[1,4,6,7,8,9,11],android:10,anoth:[6,11],anymor:8,apach:10,api:[0,1,3,4,5,6,7,8,9,10,11],apikei:11,app:10,app_log:11,app_secret_kei:11,app_set:11,app_work:11,appear:9,applic:[0,1,3,4,5,6,7,8,9,10,11],ar:[3,7,8,9,10,11,12],arch:11,archiv:[1,8,9,11],archlinux:11,asc:6,ascent:[7,9],attribut:11,auth:[0,1,3,4,5,6,7],auth_token:0,authent:[1,2,3,4,7,10],author:[0,1,3,4,5,6,7],avail:[0,3,9,10,11],ave_spe:7,ave_speed_from:7,ave_speed_to:7,averag:[3,7,8,9],average_spe:5,axi:7,b862a77:8,b:11,background:8,backup:11,bad:[0,1,4,7],bearer:[0,1,3,4,5,6,7],becom:8,been:8,befor:[8,11],begin:11,better:8,between:9,bike:[4,7,8,9],bin:11,bio:[0,6],biographi:0,birth:[0,8],birth_dat:[0,6],bound:7,build:11,button:8,by_sport:5,by_tim:5,c:7,calcul:8,calendar:[8,9],can:[6,8,9,10,11,12],cannot:8,cd:11,chang:[9,10,11],charact:[0,8],chart:[7,8,9,11],chart_data:7,check:[1,11,12],choos:[8,9],client:[8,11],client_max_body_s:11,clone:11,code:[0,1,3,4,5,6,7],color:[0,4,8,9],com:[0,6,11],complet:8,config:[1,11],configur:[2,8,9,10,11],confirm:0,contact:[0,6,7],contain:[8,9,11],content:[0,1,3,4,5,6,7],contributor:[1,8,11],control:8,coordin:11,copi:[1,11],copyright:[1,11],correctli:8,countri:9,cp:11,creat:[0,7,8,9,11],create_app:11,created_at:[0,6],creation:[8,9],creation_d:7,credenti:[0,11],criteria:6,cross:9,current:8,custom:11,cycl:[4,8,9],d:[0,5,7],dai:[8,9],dark:11,darkski:[8,9],dashboard:[8,10],data:[0,1,3,4,5,6,7,8,9,10,11],databas:[8,9,11,12],database_disable_pool:11,database_url:[8,11],date:[0,5,7,8,9],db:11,debian:11,default_staticmap:[8,11],defin:9,definit:8,delet:[0,6,7,8,9],depend:[8,11],deploy:10,desc:7,descent:[7,9],describ:11,descript:11,detail:[6,8,10],develop:[8,10],dialect:12,differ:8,directli:11,directori:[8,11],disabl:[0,8,9,11],displai:[7,8,9,10,11,12],distanc:[3,7,8,9],distance_from:7,distance_to:7,distribut:11,docker:[8,10],document:[8,10,11],doe:[0,5,6,7,8],don:0,down:8,download:[7,8,9,11],dramatiq:11,drop:8,dropdown:9,due:8,durat:[3,7,8,9],duration_from:7,duration_to:7,dure:[0,7],easi:8,edit:[0,8,9],electr:9,elev:[7,8,9,11],els:11,email:[0,6,8],email_url:11,empti:8,en:[0,6],enabl:[1,9],encount:11,end:[5,7],endpoint:[1,8],engin:[8,11,12],english:9,enter:[8,9],entiti:[0,7],entri:11,env:11,environ:[8,10,12],error:[0,1,4,6,7,8,9,11,12],europ:[0,6],evalu:[8,11],even:[8,9],exampl:[0,1,3,4,5,6,7,10,11],exc:12,exce:[0,7],exceed:8,except:6,execstart:11,exhaust:10,exist:[0,5,6,7,9,10,11],expir:[0,1,3,4,5,6,7],extens:[0,7],fa33f4d996844a5c73ecd1ae24456ab8:7,fail:[8,13],fals:[0,1,4,6,7,11],farest:[3,8,9],fd:[0,3,6,7],featur:[10,11],fetch:11,file:[0,1,7,8,9,10,11],filter:[8,9],first:[0,9,10],first_nam:[0,6],fitotrack:10,fittracke:[9,11,13],fittrackee_cli:11,fittrackee_init_data:11,fittrackee_upgrade_db:11,fittrackee_work:11,fix:10,flask:11,flask_app:11,flaticon:11,fmstrat:8,follow:[3,9,11,12],forbidden:[0,1,4,5,6,7],forecast:11,form:[0,7],format:[0,5,7],former:11,forrunn:10,forward:11,found:[0,4,5,6,7],fr:6,frame:5,freepik:11,french:[9,10],fri:7,from:[5,7,8,10],full:8,fullchain:11,gener:[8,11],get:[0,1,3,4,5,6,7],gif:0,git:11,github:11,given:11,gmt:[0,3,6,7],gpl:10,gpx:[7,8,9,10,11],gpx_limit_import:1,gpxpy:[0,9,11],grant:11,graph:8,greater:8,gunicorn:[11,12],gz:11,h:[7,9],ha:[6,9],handl:[0,9,11],has_workout:4,have:[1,4,5,6,7,8],he:6,header:[0,1,3,4,5,6,7],health:1,heavi:[10,11],hexadecim:0,hi:[6,8,9],hike:[4,8,9],home:11,host:11,href:[1,11],http:[0,1,3,4,5,6,7,11],hvybqybra7wwxpastwr4v2:[0,3,6],i18n:8,icon:11,id:[0,3,4,5,6,7],imag:[0,6,7,8,9,11],imperi:[8,9],imperial_unit:[0,6],improv:10,incorrect:8,index:7,info:0,inform:[8,10,11],init:11,initi:11,initialis:11,insid:11,instal:[8,10],instanc:[1,9,11],instead:9,integ:[1,4,5,6,7],interceptor:8,interfac:11,intern:[0,1,4,6,7],introduc:8,invalid:[0,1,3,4,5,6,7,8,11],io:11,ip:11,is_act:[0,4],is_active_for_us:4,is_registration_en:1,issu:[10,11],jan:7,javascript:8,john_do:6,jpeg:6,jpg:0,js:11,json:[0,1,3,4,5,6,7],jul:[0,3,6,7],keep:[8,10,11],kei:[8,9,11],kjxavsturjvoah2wvcegef:7,km:[7,9],label:4,languag:[0,6,9],larg:[0,7,9],larger:11,last:[0,11],last_nam:[0,6],latitud:7,layer:[8,11],ld:[0,3,6,7],leaflet:[7,11],least:7,less:8,librari:11,licens:[8,10],like:[9,11],limit:[8,9],link:11,linux:11,list:[8,10,11],listen:11,load:[8,12],local:[8,10,11],localhost:11,locat:[0,6,11],log:[0,1,3,4,5,6,7,10,11,12],logfil:11,login:0,logo:11,logout:[0,8],longer:[8,12],longest:[3,8,9],longitud:7,m:[0,5,7],made:11,mai:[9,10,11],mailhog:11,major:8,make:[8,11],makefil:11,manag:8,mandatori:[7,8,11],map:[7,8,9,10],map_attribut:[1,11],map_id:7,map_til:7,match:0,max:[1,6,7,8],max_alt:7,max_single_file_s:1,max_spe:7,max_speed_from:7,max_speed_to:7,max_us:1,max_zip_file_s:1,maxim:7,maximum:[3,8,9],messag:[0,1,7,8],method:11,metric:9,migrat:8,min:8,min_alt:7,minim:7,minor:10,miss:8,mobil:10,model:8,modifi:[6,8],modification_d:7,modul:11,mon:7,mondai:[0,5,9],montain:8,month:[5,8,9],more:[8,9,10,11],morn:7,mountain:[4,9],mous:8,move:[7,8],movement:8,mpwoadmin:11,ms:[0,3,6,7],multi:11,multipart:[0,7],must:[0,1,4,8,9,11,12],mv:11,n:0,name:[0,5,6,11],nano:11,nb_sport:[0,6],nb_workout:[0,5,6],necessari:[9,11],need:11,network:11,next:9,next_workout:7,nginx:[9,11],no_gpx:7,non:[4,10],noopen:11,noreferr:11,nosuchmoduleerror:12,note:[7,8,9,11],now:[8,9,11],number:[1,6,7,8,9,11],oauth:[0,1,3,4,5,6,7],object:[0,1,4,6,7],ok:[0,1,3,4,5,6,7],one:[6,7,9],onli:[6,7,8,9,11],open:[10,11],openstreetmap:[1,8,11],opentrack:10,option:[8,11],order:[6,7,8],order_bi:6,org:[1,11],os:11,other:[6,11],out:0,outdoor:[8,10,11],over:8,overrid:9,overridden:9,overwrit:11,own:[6,10],owner:[8,9],packag:[8,11],paf38:8,page:[6,7],pagin:[6,7],par_pag:6,paramet:[0,4,5,6,7,8,9],pari:[0,6],pars:11,part:[0,7],pass:11,password:[0,8,9,11],password_conf:0,patch:[1,4,6,7],path:11,paus:[7,8],payload:[0,1,4,7],pem:11,per:[6,7,8],per_pag:[6,7],period:9,permiss:[1,4,5,6,7],pg_dump:11,pictur:[0,6,7],ping:1,pip:11,pipenv:8,pleas:[0,1,3,4,5,6,7,8],plugin:12,png:[0,7,11],poetri:[8,11],point:[8,11],pong:1,pool:11,port:11,possibl:[8,10],post:[0,7],postgr:[8,12],postgresql:[8,11,12],prefer:[0,8],prerequisit:10,previous_workout:7,privileg:11,privkei:11,process:[0,9,11],productionconfig:11,profil:0,project:11,provid:[0,1,3,4,5,6,7,8,9,11],proxi:11,proxy_add_x_forwarded_for:11,proxy_pass:11,proxy_redirect:11,proxy_set_head:11,pull:11,purpos:[8,11],pwd:11,py:11,pypi:10,python:[8,11],q:6,queri:[5,6,7],queue:11,r:11,rais:9,read:8,real:11,rebuild:8,rechart:7,recommend:11,record:[0,2,6,7,8,9,10],record_typ:[0,3,6,7],redi:[8,11],redis_url:11,refactor:8,regist:[0,1,11],registr:[0,1,8,9],rel:11,relat:[9,11],releas:[10,11],remain:8,remote_addr:11,remov:9,renam:8,replac:[8,11],repo:11,repositori:11,request:[0,1,3,4,5,6,7],request_uri:11,requir:0,reset:[0,8,9],respons:[0,1,3,4,5,6,7],restart:11,restartsec:11,right:[6,8,9],rout:8,row:9,run:[4,8,9,11],runner:10,s:[6,7,8,9,11],sam:[0,6],same:8,samr1:11,sat:6,save:[8,9],schema:11,screen:8,search:8,second:7,secret:11,see:[8,9,10,11],seem:8,segment:[7,8,9],segment_id:7,select:[0,7],send:[8,11],sender:11,sender_email:11,serv:11,server:[0,1,4,6,7,8,9,10],server_nam:11,servic:11,set:[8,9],sever:[10,11],shell:11,should:11,show:8,shown:8,side:8,signatur:[0,1,3,4,5,6,7],simpl:11,simplifi:8,sinc:11,singl:[1,6],size:[0,1,7,8,9],ski:9,sky:11,slow:8,smtp:11,some:[6,7,8,10,11],sorri:0,sort:[6,7],sourc:10,spawn:11,speed:[0,3,7,8,9,11],spinner:8,sport:[0,2,5,7,8,9,10,11],sport_id:[0,3,4,5,6,7],sports_list:[0,6],sql:11,sqlalchemi:[8,11,12],ssl:11,ssl_certif:11,ssl_certificate_kei:11,standard:[8,11],standarderror:11,standardoutput:11,start:[0,5,7,8,9,11,13],startlimitintervalsec:11,starttl:11,stat:[5,8],staticmap:11,statist:[2,10],statu:[0,1,3,4,5,6,7],step:11,still:[9,10],stop:[0,8,9,11],stopped_speed_threshold:[0,4],store:[9,10],street:10,string:[0,4,5,6,7],subdomain:7,success:[0,1,3,4,5,6,7],successfulli:0,sun:[0,3,6,7],sundai:[5,7,9],support:[8,9,12],syslog:11,syslogidentifi:11,system:[9,11],systemd:11,t:[0,12],tar:11,target:11,task:11,term:[8,11],test:11,textarea:8,than:8,thank:8,thei:11,them:10,thi:[7,8,9,10,11],threshold:[0,8,9],thunderforest:[8,11],tile:[7,8],tile_server_url:11,time:[0,5,7,8,9],timezon:[0,6,8,9],titl:7,tl:11,todo:14,token:[0,1,3,4,5,6,7],too:[0,7],tool:11,tooltip:8,total:[8,9],total_asc:5,total_dist:[0,5,6],total_dur:[0,5,6],track:10,trail:9,transport:[4,8,9],troubleshoot:10,type:[0,1,3,4,5,6,7,11],typescript:11,u:11,ui:8,ui_url:11,unauthor:[0,1,3,4,5,6,7],under:[10,11],unencrypt:11,unit:[8,11],unstabl:[10,11],up:[9,10],updat:[0,1,4,6,7,8,9,11],upload:[8,9,11],upload_fold:11,uploads_dir_s:5,url:[8,11,12],us:[0,6,7,8,9,10,11],user:[0,1,2,3,4,5,7,8,9,10,11,13],user_id:0,user_nam:[5,6],usernam:[0,6,11],uuid:[7,8],v0:11,v3:10,valid:[0,1,3,4,5,6,7,11],valu:[0,3,6,7],variabl:[8,10,12],venv:11,version:[1,10,11],view:8,virtualenv:11,vue3:11,vue:11,vue_app_api_url:11,vuex:11,wa:8,wai:11,walk:[4,8,9],wantedbi:11,warn:8,weather:[8,9,11],weather_api:11,weather_api_kei:11,weather_end:7,weather_start:7,web:[0,10,11],week:[0,5,8,9],weekend:8,weekm:[0,5],were:8,wget:11,when:[0,1,8,9,11],where:11,which:9,with_gpx:7,without:[5,6,7,8,9,10],worker:11,workers_process:11,workingdirectori:11,workout:[0,2,5,8,10],workout_d:[0,3,6,7],workout_id:[0,3,6,7],workout_short_id:7,workouts_count:6,written:11,www:[1,11],x:[7,11],xml:7,xxxx:11,xzf:11,y:[0,5,7,11],yai:11,yarn:11,year:[5,9],yet:10,you:[1,4,5,6,7,10],your:[6,10,11],z:[7,11],zip:[1,7,8,9],zone:0,zoom:7},titles:["Authentication","Configuration","API documentation","Records","Sports","Statistics","Users","Workouts","Change log","Features","FitTrackee","Installation","Administrator","Troubleshooting","User"],titleterms:{"0":8,"01":8,"02":8,"03":8,"04":8,"07":8,"09":8,"1":8,"10":8,"11":8,"12":8,"14":8,"15":8,"16":8,"17":8,"19":8,"2":8,"2018":8,"2019":8,"2020":8,"2021":8,"21":8,"23":8,"29":8,"3":8,"30":8,"31":8,"4":8,"5":8,"6":8,"7":8,"8":8,"9":8,"new":8,account:9,administr:[8,9,12],api:2,authent:0,avail:8,bug:8,chang:8,close:8,configur:1,content:10,dashboard:9,deploy:11,detail:9,dev:11,develop:11,docker:11,document:2,email:11,endpoint:[2,13],environ:11,fail:12,featur:[8,9],first:8,fittracke:[8,10,12],fix:8,french:8,from:11,improv:8,instal:11,issu:8,list:9,log:8,map:11,minor:8,misc:8,prefer:9,prerequisit:11,prod:11,product:11,pull:8,pypi:[8,11],record:3,releas:8,request:8,server:11,sourc:11,sport:4,start:12,statist:[5,8,9],tabl:10,tile:11,translat:9,troubleshoot:13,upgrad:11,user:[6,14],variabl:11,version:8,workout:[7,9]}}) \ No newline at end of file diff --git a/fittrackee/users/utils.py b/fittrackee/users/utils.py index cd881874..9905657b 100644 --- a/fittrackee/users/utils.py +++ b/fittrackee/users/utils.py @@ -56,8 +56,8 @@ def verify_user( current_request: Request, verify_admin: bool ) -> Tuple[Optional[HttpResponse], Optional[User]]: """ - Return user id, if the provided token is valid and if user has admin - rights if 'verify_admin' is True + Return authenticated user, if the provided token is valid and user has + admin rights if 'verify_admin' is True """ default_message = 'provide a valid auth token' auth_header = current_request.headers.get('Authorization') From 1697f6051f6110d84e57a04bf955e083d9db17c5 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Dec 2021 19:44:57 +0100 Subject: [PATCH 4/6] API - minor refactoring --- fittrackee/users/decorators.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/fittrackee/users/decorators.py b/fittrackee/users/decorators.py index b3a841a5..6430071f 100644 --- a/fittrackee/users/decorators.py +++ b/fittrackee/users/decorators.py @@ -8,15 +8,22 @@ from fittrackee.responses import HttpResponse from .utils import verify_user +def verify_auth_user( + f: Callable, verify_admin: bool, *args: Any, **kwargs: Any +) -> Union[Callable, HttpResponse]: + response_object, user = verify_user(request, verify_admin=verify_admin) + if response_object: + return response_object + return f(user, *args, **kwargs) + + def authenticate(f: Callable) -> Callable: @wraps(f) def decorated_function( *args: Any, **kwargs: Any ) -> Union[Callable, HttpResponse]: - response_object, user = verify_user(request, verify_admin=False) - if response_object: - return response_object - return f(user, *args, **kwargs) + verify_admin = False + return verify_auth_user(f, verify_admin, *args, **kwargs) return decorated_function @@ -26,9 +33,7 @@ def authenticate_as_admin(f: Callable) -> Callable: def decorated_function( *args: Any, **kwargs: Any ) -> Union[Callable, HttpResponse]: - response_object, user = verify_user(request, verify_admin=True) - if response_object: - return response_object - return f(user, *args, **kwargs) + verify_admin = True + return verify_auth_user(f, verify_admin, *args, **kwargs) return decorated_function From 1b06d6b6bc7021950873e6a92ca939b51bb112f2 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Dec 2021 20:17:15 +0100 Subject: [PATCH 5/6] API - remove useless user query --- fittrackee/workouts/utils.py | 5 ++--- fittrackee/workouts/workouts.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/fittrackee/workouts/utils.py b/fittrackee/workouts/utils.py index 015b825b..3c9b463b 100644 --- a/fittrackee/workouts/utils.py +++ b/fittrackee/workouts/utils.py @@ -186,7 +186,7 @@ def update_workout(workout: Workout) -> Workout: def edit_workout( - workout: Workout, workout_data: Dict, auth_user_id: int + workout: Workout, workout_data: Dict, auth_user: User ) -> Workout: """ Edit an workout @@ -195,7 +195,6 @@ def edit_workout( In a next version, map_data and weather_data will be updated (case of a modified gpx file, see issue #7) """ - user = User.query.filter_by(id=auth_user_id).first() if workout_data.get('refresh'): workout = update_workout(workout) if workout_data.get('sport_id'): @@ -210,7 +209,7 @@ def edit_workout( workout_data['workout_date'], '%Y-%m-%d %H:%M' ) _, workout.workout_date = get_datetime_with_tz( - user.timezone, workout_date + auth_user.timezone, workout_date ) if workout_data.get('duration'): diff --git a/fittrackee/workouts/workouts.py b/fittrackee/workouts/workouts.py index e0828c11..b0339ad2 100644 --- a/fittrackee/workouts/workouts.py +++ b/fittrackee/workouts/workouts.py @@ -1288,7 +1288,7 @@ def update_workout( if response_object: return response_object - workout = edit_workout(workout, workout_data, auth_user.id) + workout = edit_workout(workout, workout_data, auth_user) db.session.commit() return { 'status': 'success', From 7206a46a379316085b6e5b88fae4234aa1b42967 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Dec 2021 20:31:42 +0100 Subject: [PATCH 6/6] fix documentation warning --- fittrackee/workouts/workouts.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fittrackee/workouts/workouts.py b/fittrackee/workouts/workouts.py index b0339ad2..35a041cd 100644 --- a/fittrackee/workouts/workouts.py +++ b/fittrackee/workouts/workouts.py @@ -369,6 +369,7 @@ def get_workout( }, "status": "not found" } + :param string workout_short_id: workout short id :reqheader Authorization: OAuth 2.0 Bearer Token