API - authentication decorators return user directly instead of user id
This commit is contained in:
parent
d9048032e4
commit
00b6e05805
2
Makefile
2
Makefile
@ -11,6 +11,8 @@ build-client: lint-client
|
|||||||
|
|
||||||
check-all: lint-all type-check test-python test-client
|
check-all: lint-all type-check test-python test-client
|
||||||
|
|
||||||
|
check-python: lint-python type-check test-python
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf .mypy_cache
|
rm -rf .mypy_cache
|
||||||
rm -rf .pytest_cache
|
rm -rf .pytest_cache
|
||||||
|
@ -10,6 +10,7 @@ from fittrackee.responses import (
|
|||||||
handle_error_and_return_response,
|
handle_error_and_return_response,
|
||||||
)
|
)
|
||||||
from fittrackee.users.decorators import authenticate_as_admin
|
from fittrackee.users.decorators import authenticate_as_admin
|
||||||
|
from fittrackee.users.models import User
|
||||||
|
|
||||||
from .models import AppConfig
|
from .models import AppConfig
|
||||||
from .utils import update_app_config_from_database, verify_app_config
|
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'])
|
@config_blueprint.route('/config', methods=['PATCH'])
|
||||||
@authenticate_as_admin
|
@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
|
Update Application config
|
||||||
|
|
||||||
@ -95,8 +96,6 @@ def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
|
|
||||||
:<json integer gpx_limit_import: max number of files in zip archive
|
:<json integer gpx_limit_import: max number of files in zip archive
|
||||||
:<json boolean is_registration_enabled: is registration enabled ?
|
:<json boolean is_registration_enabled: is registration enabled ?
|
||||||
:<json integer max_single_file_size: max size of a single file
|
:<json integer max_single_file_size: max size of a single file
|
||||||
|
@ -224,7 +224,7 @@ def login_user() -> Union[Dict, HttpResponse]:
|
|||||||
|
|
||||||
@auth_blueprint.route('/auth/logout', methods=['GET'])
|
@auth_blueprint.route('/auth/logout', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
def logout_user(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
user logout
|
user logout
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
|
|
||||||
auth_token = auth_header.split(' ')[1]
|
auth_token = auth_header.split(' ')[1]
|
||||||
resp = User.decode_auth_token(auth_token)
|
resp = User.decode_auth_token(auth_token)
|
||||||
if isinstance(auth_user_id, str):
|
if isinstance(resp, str):
|
||||||
return UnauthorizedErrorResponse(resp)
|
return UnauthorizedErrorResponse(resp)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -286,7 +286,7 @@ def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
@auth_blueprint.route('/auth/profile', methods=['GET'])
|
@auth_blueprint.route('/auth/profile', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_authenticated_user_profile(
|
def get_authenticated_user_profile(
|
||||||
auth_user_id: int,
|
auth_user: User,
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
get authenticated user info
|
get authenticated user info
|
||||||
@ -381,13 +381,12 @@ def get_authenticated_user_profile(
|
|||||||
- invalid token, please log in again
|
- invalid token, please log in again
|
||||||
|
|
||||||
"""
|
"""
|
||||||
user = User.query.filter_by(id=auth_user_id).first()
|
return {'status': 'success', 'data': auth_user.serialize()}
|
||||||
return {'status': 'success', 'data': user.serialize()}
|
|
||||||
|
|
||||||
|
|
||||||
@auth_blueprint.route('/auth/profile/edit', methods=['POST'])
|
@auth_blueprint.route('/auth/profile/edit', methods=['POST'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
def edit_user(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
edit authenticated user
|
edit authenticated user
|
||||||
|
|
||||||
@ -523,24 +522,23 @@ def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
).decode()
|
).decode()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(id=auth_user_id).first()
|
auth_user.first_name = first_name
|
||||||
user.first_name = first_name
|
auth_user.last_name = last_name
|
||||||
user.last_name = last_name
|
auth_user.bio = bio
|
||||||
user.bio = bio
|
auth_user.location = location
|
||||||
user.location = location
|
auth_user.birth_date = (
|
||||||
user.birth_date = (
|
|
||||||
datetime.datetime.strptime(birth_date, '%Y-%m-%d')
|
datetime.datetime.strptime(birth_date, '%Y-%m-%d')
|
||||||
if birth_date
|
if birth_date
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
if password is not None and password != '':
|
if password is not None and password != '':
|
||||||
user.password = password
|
auth_user.password = password
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'message': 'user profile updated',
|
'message': 'user profile updated',
|
||||||
'data': user.serialize(),
|
'data': auth_user.serialize(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# handler errors
|
# 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'])
|
@auth_blueprint.route('/auth/profile/edit/preferences', methods=['POST'])
|
||||||
@authenticate
|
@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
|
edit authenticated user preferences
|
||||||
|
|
||||||
@ -670,17 +668,16 @@ def edit_user_preferences(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
weekm = post_data.get('weekm')
|
weekm = post_data.get('weekm')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(id=auth_user_id).first()
|
auth_user.imperial_units = imperial_units
|
||||||
user.imperial_units = imperial_units
|
auth_user.language = language
|
||||||
user.language = language
|
auth_user.timezone = timezone
|
||||||
user.timezone = timezone
|
auth_user.weekm = weekm
|
||||||
user.weekm = weekm
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'message': 'user preferences updated',
|
'message': 'user preferences updated',
|
||||||
'data': user.serialize(),
|
'data': auth_user.serialize(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# handler errors
|
# 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'])
|
@auth_blueprint.route('/auth/profile/edit/sports', methods=['POST'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def edit_user_sport_preferences(
|
def edit_user_sport_preferences(
|
||||||
auth_user_id: int,
|
auth_user: User,
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
edit authenticated user sport preferences
|
edit authenticated user sport preferences
|
||||||
@ -758,12 +755,12 @@ def edit_user_sport_preferences(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
user_sport = UserSportPreference.query.filter_by(
|
user_sport = UserSportPreference.query.filter_by(
|
||||||
user_id=auth_user_id,
|
user_id=auth_user.id,
|
||||||
sport_id=sport_id,
|
sport_id=sport_id,
|
||||||
).first()
|
).first()
|
||||||
if not user_sport:
|
if not user_sport:
|
||||||
user_sport = UserSportPreference(
|
user_sport = UserSportPreference(
|
||||||
user_id=auth_user_id,
|
user_id=auth_user.id,
|
||||||
sport_id=sport_id,
|
sport_id=sport_id,
|
||||||
stopped_speed_threshold=sport.stopped_speed_threshold,
|
stopped_speed_threshold=sport.stopped_speed_threshold,
|
||||||
)
|
)
|
||||||
@ -792,7 +789,7 @@ def edit_user_sport_preferences(
|
|||||||
|
|
||||||
@auth_blueprint.route('/auth/picture', methods=['POST'])
|
@auth_blueprint.route('/auth/picture', methods=['POST'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
def edit_picture(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
update authenticated user picture
|
update authenticated user picture
|
||||||
|
|
||||||
@ -848,23 +845,22 @@ def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
file = request.files['file']
|
file = request.files['file']
|
||||||
filename = secure_filename(file.filename) # type: ignore
|
filename = secure_filename(file.filename) # type: ignore
|
||||||
dirpath = os.path.join(
|
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):
|
if not os.path.exists(dirpath):
|
||||||
os.makedirs(dirpath)
|
os.makedirs(dirpath)
|
||||||
absolute_picture_path = os.path.join(dirpath, filename)
|
absolute_picture_path = os.path.join(dirpath, filename)
|
||||||
relative_picture_path = os.path.join(
|
relative_picture_path = os.path.join(
|
||||||
'pictures', str(auth_user_id), filename
|
'pictures', str(auth_user.id), filename
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(id=auth_user_id).first()
|
if auth_user.picture is not None:
|
||||||
if user.picture is not None:
|
old_picture_path = get_absolute_file_path(auth_user.picture)
|
||||||
old_picture_path = get_absolute_file_path(user.picture)
|
|
||||||
if os.path.isfile(get_absolute_file_path(old_picture_path)):
|
if os.path.isfile(get_absolute_file_path(old_picture_path)):
|
||||||
os.remove(old_picture_path)
|
os.remove(old_picture_path)
|
||||||
file.save(absolute_picture_path)
|
file.save(absolute_picture_path)
|
||||||
user.picture = relative_picture_path
|
auth_user.picture = relative_picture_path
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
@ -879,7 +875,7 @@ def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
|
|
||||||
@auth_blueprint.route('/auth/picture', methods=['DELETE'])
|
@auth_blueprint.route('/auth/picture', methods=['DELETE'])
|
||||||
@authenticate
|
@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
|
delete authenticated user picture
|
||||||
|
|
||||||
@ -908,11 +904,10 @@ def del_picture(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(id=auth_user_id).first()
|
picture_path = get_absolute_file_path(auth_user.picture)
|
||||||
picture_path = get_absolute_file_path(user.picture)
|
|
||||||
if os.path.isfile(picture_path):
|
if os.path.isfile(picture_path):
|
||||||
os.remove(picture_path)
|
os.remove(picture_path)
|
||||||
user.picture = None
|
auth_user.picture = None
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {'status': 'no content'}, 204
|
return {'status': 'no content'}, 204
|
||||||
except (exc.IntegrityError, ValueError) as e:
|
except (exc.IntegrityError, ValueError) as e:
|
||||||
|
@ -13,11 +13,10 @@ def authenticate(f: Callable) -> Callable:
|
|||||||
def decorated_function(
|
def decorated_function(
|
||||||
*args: Any, **kwargs: Any
|
*args: Any, **kwargs: Any
|
||||||
) -> Union[Callable, HttpResponse]:
|
) -> Union[Callable, HttpResponse]:
|
||||||
verify_admin = False
|
response_object, user = verify_user(request, verify_admin=False)
|
||||||
response_object, resp = verify_user(request, verify_admin)
|
|
||||||
if response_object:
|
if response_object:
|
||||||
return response_object
|
return response_object
|
||||||
return f(resp, *args, **kwargs)
|
return f(user, *args, **kwargs)
|
||||||
|
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
@ -27,10 +26,9 @@ def authenticate_as_admin(f: Callable) -> Callable:
|
|||||||
def decorated_function(
|
def decorated_function(
|
||||||
*args: Any, **kwargs: Any
|
*args: Any, **kwargs: Any
|
||||||
) -> Union[Callable, HttpResponse]:
|
) -> Union[Callable, HttpResponse]:
|
||||||
verify_admin = True
|
response_object, user = verify_user(request, verify_admin=True)
|
||||||
response_object, resp = verify_user(request, verify_admin)
|
|
||||||
if response_object:
|
if response_object:
|
||||||
return response_object
|
return response_object
|
||||||
return f(resp, *args, **kwargs)
|
return f(user, *args, **kwargs)
|
||||||
|
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
@ -27,7 +27,7 @@ USER_PER_PAGE = 10
|
|||||||
|
|
||||||
@users_blueprint.route('/users', methods=['GET'])
|
@users_blueprint.route('/users', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_users(auth_user_id: int) -> Dict:
|
def get_users(auth_user: User) -> Dict:
|
||||||
"""
|
"""
|
||||||
Get all users
|
Get all users
|
||||||
|
|
||||||
@ -144,8 +144,6 @@ def get_users(auth_user_id: int) -> Dict:
|
|||||||
"status": "success"
|
"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 page: page if using pagination (default: 1)
|
||||||
:query integer per_page: number of users per page (default: 10, max: 50)
|
:query integer per_page: number of users per page (default: 10, max: 50)
|
||||||
:query string q: query on user name
|
:query string q: query on user name
|
||||||
@ -219,7 +217,7 @@ def get_users(auth_user_id: int) -> Dict:
|
|||||||
@users_blueprint.route('/users/<user_name>', methods=['GET'])
|
@users_blueprint.route('/users/<user_name>', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_single_user(
|
def get_single_user(
|
||||||
auth_user_id: int, user_name: str
|
auth_user: User, user_name: str
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get single user details
|
Get single user details
|
||||||
@ -306,7 +304,6 @@ def get_single_user(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param integer user_name: user name
|
:param integer user_name: user name
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
@ -371,9 +368,7 @@ def get_picture(user_name: str) -> Any:
|
|||||||
|
|
||||||
@users_blueprint.route('/users/<user_name>', methods=['PATCH'])
|
@users_blueprint.route('/users/<user_name>', methods=['PATCH'])
|
||||||
@authenticate_as_admin
|
@authenticate_as_admin
|
||||||
def update_user(
|
def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]:
|
||||||
auth_user_id: int, user_name: str
|
|
||||||
) -> Union[Dict, HttpResponse]:
|
|
||||||
"""
|
"""
|
||||||
Update user to add admin rights
|
Update user to add admin rights
|
||||||
|
|
||||||
@ -461,7 +456,6 @@ def update_user(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string user_name: user name
|
:param string user_name: user name
|
||||||
|
|
||||||
:<json boolean admin: does the user have administrator rights
|
:<json boolean admin: does the user have administrator rights
|
||||||
@ -500,7 +494,7 @@ def update_user(
|
|||||||
@users_blueprint.route('/users/<user_name>', methods=['DELETE'])
|
@users_blueprint.route('/users/<user_name>', methods=['DELETE'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def delete_user(
|
def delete_user(
|
||||||
auth_user_id: int, user_name: str
|
auth_user: User, user_name: str
|
||||||
) -> Union[Tuple[Dict, int], HttpResponse]:
|
) -> Union[Tuple[Dict, int], HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Delete a user account
|
Delete a user account
|
||||||
@ -524,7 +518,6 @@ def delete_user(
|
|||||||
HTTP/1.1 204 NO CONTENT
|
HTTP/1.1 204 NO CONTENT
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string user_name: user name
|
:param string user_name: user name
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
@ -543,12 +536,11 @@ def delete_user(
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
auth_user = User.query.filter_by(id=auth_user_id).first()
|
|
||||||
user = User.query.filter_by(username=user_name).first()
|
user = User.query.filter_by(username=user_name).first()
|
||||||
if not user:
|
if not user:
|
||||||
return UserNotFoundErrorResponse()
|
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()
|
return ForbiddenErrorResponse()
|
||||||
if (
|
if (
|
||||||
user.admin is True
|
user.admin is True
|
||||||
|
@ -62,7 +62,7 @@ def register_controls(
|
|||||||
|
|
||||||
def verify_user(
|
def verify_user(
|
||||||
current_request: Request, verify_admin: bool
|
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
|
Return user id, if the provided token is valid and if user has admin
|
||||||
rights if 'verify_admin' is True
|
rights if 'verify_admin' is True
|
||||||
@ -78,9 +78,9 @@ def verify_user(
|
|||||||
user = User.query.filter_by(id=resp).first()
|
user = User.query.filter_by(id=resp).first()
|
||||||
if not user:
|
if not user:
|
||||||
return UnauthorizedErrorResponse(default_message), None
|
return UnauthorizedErrorResponse(default_message), None
|
||||||
if verify_admin and not is_admin(resp):
|
if verify_admin and not user.admin:
|
||||||
return ForbiddenErrorResponse(), None
|
return ForbiddenErrorResponse(), None
|
||||||
return None, resp
|
return None, user
|
||||||
|
|
||||||
|
|
||||||
def can_view_workout(
|
def can_view_workout(
|
||||||
|
@ -3,6 +3,7 @@ from typing import Dict
|
|||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
|
|
||||||
from fittrackee.users.decorators import authenticate
|
from fittrackee.users.decorators import authenticate
|
||||||
|
from fittrackee.users.models import User
|
||||||
|
|
||||||
from .models import Record
|
from .models import Record
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ records_blueprint = Blueprint('records', __name__)
|
|||||||
|
|
||||||
@records_blueprint.route('/records', methods=['GET'])
|
@records_blueprint.route('/records', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_records(auth_user_id: int) -> Dict:
|
def get_records(auth_user: User) -> Dict:
|
||||||
"""
|
"""
|
||||||
Get all records for authenticated user.
|
Get all records for authenticated user.
|
||||||
|
|
||||||
@ -95,8 +96,6 @@ def get_records(auth_user_id: int) -> Dict:
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
|
|
||||||
:statuscode 200: success
|
:statuscode 200: success
|
||||||
@ -107,7 +106,7 @@ def get_records(auth_user_id: int) -> Dict:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
records = (
|
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())
|
.order_by(Record.sport_id.asc(), Record.record_type.asc())
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,7 @@ sports_blueprint = Blueprint('sports', __name__)
|
|||||||
|
|
||||||
@sports_blueprint.route('/sports', methods=['GET'])
|
@sports_blueprint.route('/sports', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_sports(auth_user_id: int) -> Dict:
|
def get_sports(auth_user: User) -> Dict:
|
||||||
"""
|
"""
|
||||||
Get all sports
|
Get all sports
|
||||||
|
|
||||||
@ -165,8 +165,6 @@ def get_sports(auth_user_id: int) -> Dict:
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
|
|
||||||
:statuscode 200: success
|
:statuscode 200: success
|
||||||
@ -176,16 +174,15 @@ def get_sports(auth_user_id: int) -> Dict:
|
|||||||
- invalid token, please log in again
|
- 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 = Sport.query.order_by(Sport.id).all()
|
||||||
sports_data = []
|
sports_data = []
|
||||||
for sport in sports:
|
for sport in sports:
|
||||||
sport_preferences = UserSportPreference.query.filter_by(
|
sport_preferences = UserSportPreference.query.filter_by(
|
||||||
user_id=user.id, sport_id=sport.id
|
user_id=auth_user.id, sport_id=sport.id
|
||||||
).first()
|
).first()
|
||||||
sports_data.append(
|
sports_data.append(
|
||||||
sport.serialize(
|
sport.serialize(
|
||||||
is_admin=user.admin,
|
is_admin=auth_user.admin,
|
||||||
sport_preferences=sport_preferences.serialize()
|
sport_preferences=sport_preferences.serialize()
|
||||||
if sport_preferences
|
if sport_preferences
|
||||||
else None,
|
else None,
|
||||||
@ -199,7 +196,7 @@ def get_sports(auth_user_id: int) -> Dict:
|
|||||||
|
|
||||||
@sports_blueprint.route('/sports/<int:sport_id>', methods=['GET'])
|
@sports_blueprint.route('/sports/<int:sport_id>', methods=['GET'])
|
||||||
@authenticate
|
@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
|
Get a sport
|
||||||
|
|
||||||
@ -273,7 +270,6 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
"status": "not found"
|
"status": "not found"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param integer sport_id: sport id
|
:param integer sport_id: sport id
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
: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
|
: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()
|
sport = Sport.query.filter_by(id=sport_id).first()
|
||||||
if sport:
|
if sport:
|
||||||
sport_preferences = UserSportPreference.query.filter_by(
|
sport_preferences = UserSportPreference.query.filter_by(
|
||||||
user_id=user.id, sport_id=sport.id
|
user_id=auth_user.id, sport_id=sport.id
|
||||||
).first()
|
).first()
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'data': {
|
'data': {
|
||||||
'sports': [
|
'sports': [
|
||||||
sport.serialize(
|
sport.serialize(
|
||||||
is_admin=user.admin,
|
is_admin=auth_user.admin,
|
||||||
sport_preferences=sport_preferences.serialize()
|
sport_preferences=sport_preferences.serialize()
|
||||||
if sport_preferences
|
if sport_preferences
|
||||||
else None,
|
else None,
|
||||||
@ -310,9 +305,7 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
|
|
||||||
@sports_blueprint.route('/sports/<int:sport_id>', methods=['PATCH'])
|
@sports_blueprint.route('/sports/<int:sport_id>', methods=['PATCH'])
|
||||||
@authenticate_as_admin
|
@authenticate_as_admin
|
||||||
def update_sport(
|
def update_sport(auth_user: User, sport_id: int) -> Union[Dict, HttpResponse]:
|
||||||
auth_user_id: int, sport_id: int
|
|
||||||
) -> Union[Dict, HttpResponse]:
|
|
||||||
"""
|
"""
|
||||||
Update a sport
|
Update a sport
|
||||||
Authenticated user must be an admin
|
Authenticated user must be an admin
|
||||||
@ -364,7 +357,6 @@ def update_sport(
|
|||||||
"status": "not found"
|
"status": "not found"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param integer sport_id: sport id
|
:param integer sport_id: sport id
|
||||||
|
|
||||||
:<json string is_active: sport active status
|
:<json string is_active: sport active status
|
||||||
@ -387,7 +379,6 @@ def update_sport(
|
|||||||
return InvalidPayloadErrorResponse()
|
return InvalidPayloadErrorResponse()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(id=int(auth_user_id)).first()
|
|
||||||
sport = Sport.query.filter_by(id=sport_id).first()
|
sport = Sport.query.filter_by(id=sport_id).first()
|
||||||
if not sport:
|
if not sport:
|
||||||
return DataNotFoundErrorResponse('sports')
|
return DataNotFoundErrorResponse('sports')
|
||||||
@ -395,14 +386,14 @@ def update_sport(
|
|||||||
sport.is_active = sport_data.get('is_active')
|
sport.is_active = sport_data.get('is_active')
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
sport_preferences = UserSportPreference.query.filter_by(
|
sport_preferences = UserSportPreference.query.filter_by(
|
||||||
user_id=user.id, sport_id=sport.id
|
user_id=auth_user.id, sport_id=sport.id
|
||||||
).first()
|
).first()
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'data': {
|
'data': {
|
||||||
'sports': [
|
'sports': [
|
||||||
sport.serialize(
|
sport.serialize(
|
||||||
is_admin=user.admin,
|
is_admin=auth_user.admin,
|
||||||
sport_preferences=sport_preferences.serialize()
|
sport_preferences=sport_preferences.serialize()
|
||||||
if sport_preferences
|
if sport_preferences
|
||||||
else None,
|
else None,
|
||||||
|
@ -179,7 +179,7 @@ def get_workouts(
|
|||||||
@stats_blueprint.route('/stats/<user_name>/by_time', methods=['GET'])
|
@stats_blueprint.route('/stats/<user_name>/by_time', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_workouts_by_time(
|
def get_workouts_by_time(
|
||||||
auth_user_id: int, user_name: str
|
auth_user: User, user_name: str
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get workouts statistics for a user by time
|
Get workouts statistics for a user by time
|
||||||
@ -258,7 +258,6 @@ def get_workouts_by_time(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param integer user_name: user name
|
:param integer user_name: user name
|
||||||
|
|
||||||
:query string from: start date (format: ``%Y-%m-%d``)
|
:query string from: start date (format: ``%Y-%m-%d``)
|
||||||
@ -287,7 +286,7 @@ def get_workouts_by_time(
|
|||||||
@stats_blueprint.route('/stats/<user_name>/by_sport', methods=['GET'])
|
@stats_blueprint.route('/stats/<user_name>/by_sport', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_workouts_by_sport(
|
def get_workouts_by_sport(
|
||||||
auth_user_id: int, user_name: str
|
auth_user: User, user_name: str
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get workouts statistics for a user by sport
|
Get workouts statistics for a user by sport
|
||||||
@ -361,7 +360,6 @@ def get_workouts_by_sport(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param integer user_name: user name
|
:param integer user_name: user name
|
||||||
|
|
||||||
:query integer sport_id: sport id
|
:query integer sport_id: sport id
|
||||||
@ -383,7 +381,7 @@ def get_workouts_by_sport(
|
|||||||
|
|
||||||
@stats_blueprint.route('/stats/all', methods=['GET'])
|
@stats_blueprint.route('/stats/all', methods=['GET'])
|
||||||
@authenticate_as_admin
|
@authenticate_as_admin
|
||||||
def get_application_stats(auth_user_id: int) -> Dict:
|
def get_application_stats(auth_user: User) -> Dict:
|
||||||
"""
|
"""
|
||||||
Get all application statistics
|
Get all application statistics
|
||||||
|
|
||||||
@ -411,8 +409,6 @@ def get_application_stats(auth_user_id: int) -> Dict:
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
|
|
||||||
:statuscode 200: success
|
:statuscode 200: success
|
||||||
|
@ -56,7 +56,7 @@ MAX_WORKOUTS_PER_PAGE = 100
|
|||||||
|
|
||||||
@workouts_blueprint.route('/workouts', methods=['GET'])
|
@workouts_blueprint.route('/workouts', methods=['GET'])
|
||||||
@authenticate
|
@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.
|
Get workouts for the authenticated user.
|
||||||
|
|
||||||
@ -171,8 +171,6 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
"status": "success"
|
"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 page: page if using pagination (default: 1)
|
||||||
:query integer per_page: number of workouts per page
|
:query integer per_page: number of workouts per page
|
||||||
(default: 5, max: 100)
|
(default: 5, max: 100)
|
||||||
@ -200,10 +198,9 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(id=auth_user_id).first()
|
|
||||||
params = request.args.copy()
|
params = request.args.copy()
|
||||||
page = int(params.get('page', 1))
|
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_from = params.get('distance_from')
|
||||||
distance_to = params.get('distance_to')
|
distance_to = params.get('distance_to')
|
||||||
duration_from = params.get('duration_from')
|
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
|
per_page = MAX_WORKOUTS_PER_PAGE
|
||||||
workouts_pagination = (
|
workouts_pagination = (
|
||||||
Workout.query.filter(
|
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.sport_id == sport_id if sport_id else True,
|
||||||
Workout.workout_date >= date_from if date_from else True,
|
Workout.workout_date >= date_from if date_from else True,
|
||||||
Workout.workout_date < date_to + timedelta(seconds=1)
|
Workout.workout_date < date_to + timedelta(seconds=1)
|
||||||
@ -302,7 +299,7 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
|
|||||||
)
|
)
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_workout(
|
def get_workout(
|
||||||
auth_user_id: int, workout_short_id: str
|
auth_user: User, workout_short_id: str
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get an workout
|
Get an workout
|
||||||
@ -372,8 +369,6 @@ def get_workout(
|
|||||||
},
|
},
|
||||||
"status": "not found"
|
"status": "not found"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string workout_short_id: workout short id
|
:param string workout_short_id: workout short id
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
@ -392,7 +387,7 @@ def get_workout(
|
|||||||
if not workout:
|
if not workout:
|
||||||
return DataNotFoundErrorResponse('workouts')
|
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:
|
if error_response:
|
||||||
return error_response
|
return error_response
|
||||||
|
|
||||||
@ -403,7 +398,7 @@ def get_workout(
|
|||||||
|
|
||||||
|
|
||||||
def get_workout_data(
|
def get_workout_data(
|
||||||
auth_user_id: int,
|
auth_user: User,
|
||||||
workout_short_id: str,
|
workout_short_id: str,
|
||||||
data_type: str,
|
data_type: str,
|
||||||
segment_id: Optional[int] = None,
|
segment_id: Optional[int] = None,
|
||||||
@ -417,7 +412,7 @@ def get_workout_data(
|
|||||||
message=f'workout not found (id: {workout_short_id})',
|
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:
|
if error_response:
|
||||||
return error_response
|
return error_response
|
||||||
if not workout.gpx or workout.gpx == '':
|
if not workout.gpx or workout.gpx == '':
|
||||||
@ -467,7 +462,7 @@ def get_workout_data(
|
|||||||
)
|
)
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_workout_gpx(
|
def get_workout_gpx(
|
||||||
auth_user_id: int, workout_short_id: str
|
auth_user: User, workout_short_id: str
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get gpx file for an workout displayed on map with Leaflet
|
Get gpx file for an workout displayed on map with Leaflet
|
||||||
@ -494,7 +489,6 @@ def get_workout_gpx(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string workout_short_id: workout short id
|
:param string workout_short_id: workout short id
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
@ -510,7 +504,7 @@ def get_workout_gpx(
|
|||||||
:statuscode 500:
|
: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(
|
@workouts_blueprint.route(
|
||||||
@ -518,7 +512,7 @@ def get_workout_gpx(
|
|||||||
)
|
)
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_workout_chart_data(
|
def get_workout_chart_data(
|
||||||
auth_user_id: int, workout_short_id: str
|
auth_user: User, workout_short_id: str
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get chart data from an workout gpx file, to display it with Recharts
|
Get chart data from an workout gpx file, to display it with Recharts
|
||||||
@ -564,7 +558,6 @@ def get_workout_chart_data(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string workout_short_id: workout short id
|
:param string workout_short_id: workout short id
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
@ -580,7 +573,7 @@ def get_workout_chart_data(
|
|||||||
:statuscode 500:
|
: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(
|
@workouts_blueprint.route(
|
||||||
@ -589,7 +582,7 @@ def get_workout_chart_data(
|
|||||||
)
|
)
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_segment_gpx(
|
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]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get gpx file for an workout segment displayed on map with Leaflet
|
Get gpx file for an workout segment displayed on map with Leaflet
|
||||||
@ -616,7 +609,6 @@ def get_segment_gpx(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string workout_short_id: workout short id
|
:param string workout_short_id: workout short id
|
||||||
:param integer segment_id: segment id
|
:param integer segment_id: segment id
|
||||||
|
|
||||||
@ -632,7 +624,7 @@ def get_segment_gpx(
|
|||||||
:statuscode 500:
|
: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(
|
@workouts_blueprint.route(
|
||||||
@ -642,7 +634,7 @@ def get_segment_gpx(
|
|||||||
)
|
)
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_segment_chart_data(
|
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]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Get chart data from an workout gpx file, to display it with Recharts
|
Get chart data from an workout gpx file, to display it with Recharts
|
||||||
@ -688,7 +680,6 @@ def get_segment_chart_data(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string workout_short_id: workout short id
|
:param string workout_short_id: workout short id
|
||||||
:param integer segment_id: segment id
|
:param integer segment_id: segment id
|
||||||
|
|
||||||
@ -705,7 +696,7 @@ def get_segment_chart_data(
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
return get_workout_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
|
@authenticate
|
||||||
def download_workout_gpx(
|
def download_workout_gpx(
|
||||||
auth_user_id: int, workout_short_id: str
|
auth_user: User, workout_short_id: str
|
||||||
) -> Union[HttpResponse, Response]:
|
) -> Union[HttpResponse, Response]:
|
||||||
"""
|
"""
|
||||||
Download gpx file
|
Download gpx file
|
||||||
@ -732,7 +723,6 @@ def download_workout_gpx(
|
|||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
Content-Type: application/gpx+xml
|
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
|
:param string workout_short_id: workout short id
|
||||||
|
|
||||||
:statuscode 200: success
|
:statuscode 200: success
|
||||||
@ -746,7 +736,7 @@ def download_workout_gpx(
|
|||||||
"""
|
"""
|
||||||
workout_uuid = decode_short_id(workout_short_id)
|
workout_uuid = decode_short_id(workout_short_id)
|
||||||
workout = Workout.query.filter_by(
|
workout = Workout.query.filter_by(
|
||||||
uuid=workout_uuid, user_id=auth_user_id
|
uuid=workout_uuid, user_id=auth_user.id
|
||||||
).first()
|
).first()
|
||||||
if not workout:
|
if not workout:
|
||||||
return DataNotFoundErrorResponse(
|
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'])
|
@workouts_blueprint.route('/workouts', methods=['POST'])
|
||||||
@authenticate
|
@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
|
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"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
|
|
||||||
:form file: gpx file (allowed extensions: .gpx, .zip)
|
:form file: gpx file (allowed extensions: .gpx, .zip)
|
||||||
:form data: sport id and notes (example: ``{"sport_id": 1, "notes": ""}``)
|
: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']
|
workout_file = request.files['file']
|
||||||
upload_dir = os.path.join(
|
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 = {
|
folders = {
|
||||||
'extract_dir': os.path.join(upload_dir, 'extract'),
|
'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:
|
try:
|
||||||
new_workouts = process_files(
|
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:
|
if len(new_workouts) > 0:
|
||||||
response_object = {
|
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'])
|
@workouts_blueprint.route('/workouts/no_gpx', methods=['POST'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def post_workout_no_gpx(
|
def post_workout_no_gpx(
|
||||||
auth_user_id: int,
|
auth_user: User,
|
||||||
) -> Union[Tuple[Dict, int], HttpResponse]:
|
) -> Union[Tuple[Dict, int], HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Post an workout without gpx file
|
Post an workout without gpx file
|
||||||
@ -1114,8 +1102,6 @@ def post_workout_no_gpx(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
|
|
||||||
:<json string workout_date: workout date (format: ``%Y-%m-%d %H:%M``)
|
:<json string workout_date: workout date (format: ``%Y-%m-%d %H:%M``)
|
||||||
:<json float distance: workout distance in km
|
:<json float distance: workout distance in km
|
||||||
:<json integer duration: workout duration in seconds
|
:<json integer duration: workout duration in seconds
|
||||||
@ -1145,8 +1131,7 @@ def post_workout_no_gpx(
|
|||||||
return InvalidPayloadErrorResponse()
|
return InvalidPayloadErrorResponse()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(id=auth_user_id).first()
|
new_workout = create_workout(auth_user, workout_data)
|
||||||
new_workout = create_workout(user, workout_data)
|
|
||||||
db.session.add(new_workout)
|
db.session.add(new_workout)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
@ -1172,7 +1157,7 @@ def post_workout_no_gpx(
|
|||||||
)
|
)
|
||||||
@authenticate
|
@authenticate
|
||||||
def update_workout(
|
def update_workout(
|
||||||
auth_user_id: int, workout_short_id: str
|
auth_user: User, workout_short_id: str
|
||||||
) -> Union[Dict, HttpResponse]:
|
) -> Union[Dict, HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Update an workout
|
Update an workout
|
||||||
@ -1265,7 +1250,6 @@ def update_workout(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string workout_short_id: workout short id
|
:param string workout_short_id: workout short id
|
||||||
|
|
||||||
:<json string workout_date: workout date (format: ``%Y-%m-%d %H:%M``)
|
:<json string workout_date: workout date (format: ``%Y-%m-%d %H:%M``)
|
||||||
@ -1300,11 +1284,11 @@ def update_workout(
|
|||||||
if not workout:
|
if not workout:
|
||||||
return DataNotFoundErrorResponse('workouts')
|
return DataNotFoundErrorResponse('workouts')
|
||||||
|
|
||||||
response_object = can_view_workout(auth_user_id, workout.user_id)
|
response_object = can_view_workout(auth_user.id, workout.user_id)
|
||||||
if response_object:
|
if response_object:
|
||||||
return response_object
|
return response_object
|
||||||
|
|
||||||
workout = edit_workout(workout, workout_data, auth_user_id)
|
workout = edit_workout(workout, workout_data, auth_user.id)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
@ -1320,7 +1304,7 @@ def update_workout(
|
|||||||
)
|
)
|
||||||
@authenticate
|
@authenticate
|
||||||
def delete_workout(
|
def delete_workout(
|
||||||
auth_user_id: int, workout_short_id: str
|
auth_user: User, workout_short_id: str
|
||||||
) -> Union[Tuple[Dict, int], HttpResponse]:
|
) -> Union[Tuple[Dict, int], HttpResponse]:
|
||||||
"""
|
"""
|
||||||
Delete an workout
|
Delete an workout
|
||||||
@ -1339,7 +1323,6 @@ def delete_workout(
|
|||||||
HTTP/1.1 204 NO CONTENT
|
HTTP/1.1 204 NO CONTENT
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
||||||
:param string workout_short_id: workout short id
|
:param string workout_short_id: workout short id
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
@ -1359,7 +1342,7 @@ def delete_workout(
|
|||||||
workout = Workout.query.filter_by(uuid=workout_uuid).first()
|
workout = Workout.query.filter_by(uuid=workout_uuid).first()
|
||||||
if not workout:
|
if not workout:
|
||||||
return DataNotFoundErrorResponse('workouts')
|
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:
|
if error_response:
|
||||||
return error_response
|
return error_response
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user