Merge branch 'decorators_refacto' into dev

This commit is contained in:
Sam 2021-12-01 20:34:21 +01:00
commit eaa5eeb897
19 changed files with 143 additions and 247 deletions

View File

@ -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

View File

@ -191,13 +191,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request JSON Object</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request JSON Object</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>gpx_limit_import</strong> (<em>integer</em>) max number of files in zip archive</p></li>
<li><p><strong>is_registration_enabled</strong> (<em>boolean</em>) is registration enabled ?</p></li>
<li><p><strong>max_single_file_size</strong> (<em>integer</em>) max size of a single file</p></li>
@ -205,13 +200,13 @@
<li><p><strong>max_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>

View File

@ -212,18 +212,13 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>

View File

@ -270,18 +270,13 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
@ -368,7 +363,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li>
</ul>
</dd>
@ -444,7 +438,6 @@ Authenticated user must be an admin</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li>
</ul>
</dd>

View File

@ -206,7 +206,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul>
</dd>
@ -321,7 +320,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul>
</dd>
@ -378,18 +376,13 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>

View File

@ -242,13 +242,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Query Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Query Parameters</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li>
<li><p><strong>per_page</strong> (<em>integer</em>) number of users per page (default: 10, max: 50)</p></li>
<li><p><strong>q</strong> (<em>string</em>) query on user name</p></li>
@ -257,13 +252,13 @@
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">asc</span></code>)</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
@ -361,7 +356,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul>
</dd>
@ -507,7 +501,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>string</em>) user name</p></li>
</ul>
</dd>
@ -561,7 +554,6 @@ one admin</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>string</em>) user name</p></li>
</ul>
</dd>

View File

@ -241,13 +241,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Query Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Query Parameters</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li>
<li><p><strong>per_page</strong> (<em>integer</em>) number of workouts per page
(default: 5, max: 100)</p></li>
@ -265,13 +260,13 @@
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">desc</span></code>)</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
@ -355,7 +350,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -405,7 +399,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -478,7 +471,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -551,7 +543,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
<li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li>
</ul>
@ -603,7 +594,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
<li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li>
</ul>
@ -708,7 +698,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -820,24 +809,19 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Form Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Form Parameters</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>file</strong> gpx file (allowed extensions: .gpx, .zip)</p></li>
<li><p><strong>data</strong> sport id and notes (example: <code class="docutils literal notranslate"><span class="pre">{&quot;sport_id&quot;:</span> <span class="pre">1,</span> <span class="pre">&quot;notes&quot;:</span> <span class="pre">&quot;&quot;}</span></code>)</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
<li><p>invalid payload</p></li>
@ -948,13 +932,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request JSON Object</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request JSON Object</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>workout_date</strong> (<em>string</em>) workout date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span> <span class="pre">%H:%M</span></code>)</p></li>
<li><p><strong>distance</strong> (<em>float</em>) workout distance in km</p></li>
<li><p><strong>duration</strong> (<em>integer</em>) workout duration in seconds</p></li>
@ -963,13 +942,13 @@
<li><p><strong>title</strong> (<em>string</em>) workout title</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -1075,7 +1054,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -1131,7 +1109,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>

File diff suppressed because one or more lines are too long

View File

@ -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)
:<json integer gpx_limit_import: max number of files in zip archive
:<json boolean is_registration_enabled: is registration enabled ?
:<json integer max_single_file_size: max size of a single file

View File

@ -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,

View File

@ -224,7 +224,7 @@ def login_user() -> 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:

View File

@ -8,16 +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]:
verify_admin = False
response_object, resp = verify_user(request, verify_admin)
if response_object:
return response_object
return f(resp, *args, **kwargs)
return verify_auth_user(f, verify_admin, *args, **kwargs)
return decorated_function
@ -28,9 +34,6 @@ def authenticate_as_admin(f: Callable) -> Callable:
*args: Any, **kwargs: Any
) -> Union[Callable, HttpResponse]:
verify_admin = True
response_object, resp = verify_user(request, verify_admin)
if response_object:
return response_object
return f(resp, *args, **kwargs)
return verify_auth_user(f, verify_admin, *args, **kwargs)
return decorated_function

View File

@ -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/<user_name>', 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/<user_name>', 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
:<json boolean admin: does the user have administrator rights
@ -500,7 +494,7 @@ def update_user(
@users_blueprint.route('/users/<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

View File

@ -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
@ -62,10 +54,10 @@ 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
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')
@ -78,9 +70,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(

View File

@ -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()
)

View File

@ -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/<int:sport_id>', 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/<int:sport_id>', 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
:<json string is_active: sport active status
@ -387,7 +379,6 @@ def update_sport(
return InvalidPayloadErrorResponse()
try:
user = User.query.filter_by(id=int(auth_user_id)).first()
sport = Sport.query.filter_by(id=sport_id).first()
if not sport:
return DataNotFoundErrorResponse('sports')
@ -395,14 +386,14 @@ def update_sport(
sport.is_active = sport_data.get('is_active')
db.session.commit()
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,

View File

@ -179,7 +179,7 @@ def get_workouts(
@stats_blueprint.route('/stats/<user_name>/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/<user_name>/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

View File

@ -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'):
@ -299,9 +298,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 +310,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 +324,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 +379,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 +398,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 +408,7 @@ def process_files(
)
common_params = {
'user': user,
'auth_user': auth_user,
'workout_data': workout_data,
'file_path': file_path,
'sport_label': sport.label,

View File

@ -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
@ -373,7 +370,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 +388,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 +399,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 +413,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 +463,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 +490,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 +505,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 +513,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 +559,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 +574,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 +583,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 +610,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 +625,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 +635,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 +681,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 +697,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 +706,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 +724,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 +737,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 +843,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 +935,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 +972,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 +981,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, workout_data, workout_file, folders
)
if len(new_workouts) > 0:
response_object = {
@ -1021,7 +1010,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 +1103,6 @@ def post_workout_no_gpx(
"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 float distance: workout distance in km
:<json integer duration: workout duration in seconds
@ -1145,8 +1132,7 @@ def post_workout_no_gpx(
return InvalidPayloadErrorResponse()
try:
user = User.query.filter_by(id=auth_user_id).first()
new_workout = create_workout(user, workout_data)
new_workout = create_workout(auth_user, workout_data)
db.session.add(new_workout)
db.session.commit()
@ -1172,7 +1158,7 @@ def post_workout_no_gpx(
)
@authenticate
def update_workout(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[Dict, HttpResponse]:
"""
Update an workout
@ -1265,7 +1251,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
:<json string workout_date: workout date (format: ``%Y-%m-%d %H:%M``)
@ -1300,11 +1285,11 @@ def update_workout(
if not workout:
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:
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',
@ -1320,7 +1305,7 @@ def update_workout(
)
@authenticate
def delete_workout(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[Tuple[Dict, int], HttpResponse]:
"""
Delete an workout
@ -1339,7 +1324,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 +1343,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