FitTrackee/fittrackee/workouts/sports.py

414 lines
10 KiB
Python
Raw Normal View History

2021-01-02 19:28:03 +01:00
from typing import Dict, Union
2021-01-20 16:47:00 +01:00
from flask import Blueprint, request
from sqlalchemy import exc
2021-01-01 16:39:25 +01:00
from fittrackee import db
from fittrackee.oauth2.server import require_auth
2021-01-01 16:39:25 +01:00
from fittrackee.responses import (
DataNotFoundErrorResponse,
2021-01-02 19:28:03 +01:00
HttpResponse,
2021-01-01 16:39:25 +01:00
InvalidPayloadErrorResponse,
handle_error_and_return_response,
)
from fittrackee.users.models import User, UserSportPreference
2018-05-01 16:17:12 +02:00
from .models import Sport
sports_blueprint = Blueprint('sports', __name__)
@sports_blueprint.route('/sports', methods=['GET'])
2022-06-15 19:16:14 +02:00
@require_auth(scopes=['workouts:read'])
def get_sports(auth_user: User) -> Dict:
"""
Get all sports
**Scope**: ``workouts:read``
**Example request**:
.. sourcecode:: http
GET /api/sports HTTP/1.1
Content-Type: application/json
**Example response**:
2023-06-18 20:45:39 +02:00
- for non admin user:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"sports": [
{
"color": null,
"id": 1,
"is_active": true,
"is_active_for_user": true,
"label": "Cycling (Sport)",
"stopped_speed_threshold": 1
},
{
"color": null,
"id": 2,
"is_active": true,
"is_active_for_user": true,
"label": "Cycling (Transport)",
"stopped_speed_threshold": 1
},
{
"color": null,
"id": 3,
"is_active": true,
"is_active_for_user": true,
"label": "Hiking",
"stopped_speed_threshold": 0.1
},
{
"color": null,
"id": 4,
"is_active": true,
"is_active_for_user": true,
"label": "Mountain Biking",
"stopped_speed_threshold": 1
},
{
"color": null,
"id": 5,
"is_active": true,
"is_active_for_user": true,
"label": "Running",
"stopped_speed_threshold": 0.1
},
{
"color": null,
"id": 6,
"is_active": true,
"is_active_for_user": true,
"label": "Walking",
"stopped_speed_threshold": 0.1
}
]
},
"status": "success"
}
2023-06-18 20:45:39 +02:00
- for admin user:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"sports": [
{
"color": null,
"has_workouts": true,
"id": 1,
"is_active": true,
"is_active_for_user": true,
"label": "Cycling (Sport)",
"stopped_speed_threshold": 1
},
{
"color": null,
"has_workouts": false,
"id": 2,
"is_active": true,
"is_active_for_user": true,
"label": "Cycling (Transport)",
"stopped_speed_threshold": 1
},
{
"color": null,
"has_workouts": false,
"id": 3,
"is_active": true,
"is_active_for_user": true,
"label": "Hiking",
"stopped_speed_threshold": 0.1
},
{
"color": null,
"has_workouts": false,
"id": 4,
"is_active": true,
"is_active_for_user": true,
"label": "Mountain Biking",
"stopped_speed_threshold": 1
},
{
"color": null,
"has_workouts": false,
"id": 5,
"is_active": true,
"is_active_for_user": true,
"label": "Running",
"stopped_speed_threshold": 0.1
},
{
"color": null,
"has_workouts": false,
"id": 6,
"is_active": true,
"is_active_for_user": true,
"label": "Walking",
"stopped_speed_threshold": 0.1
}
]
},
"status": "success"
}
:reqheader Authorization: OAuth 2.0 Bearer Token
2023-06-18 20:45:39 +02:00
:statuscode 200: ``success``
:statuscode 401:
2023-06-18 20:45:39 +02:00
- ``provide a valid auth token``
- ``signature expired, please log in again``
- ``invalid token, please log in again``
"""
2018-05-01 16:17:12 +02:00
sports = Sport.query.order_by(Sport.id).all()
sports_data = []
for sport in sports:
sport_preferences = UserSportPreference.query.filter_by(
user_id=auth_user.id, sport_id=sport.id
).first()
sports_data.append(
sport.serialize(
is_admin=auth_user.admin,
sport_preferences=sport_preferences.serialize()
if sport_preferences
else None,
)
)
2021-01-01 16:39:25 +01:00
return {
2018-05-01 16:17:12 +02:00
'status': 'success',
'data': {'sports': sports_data},
2018-05-01 16:17:12 +02:00
}
@sports_blueprint.route('/sports/<int:sport_id>', methods=['GET'])
2022-06-15 19:16:14 +02:00
@require_auth(scopes=['workouts:read'])
def get_sport(auth_user: User, sport_id: int) -> Union[Dict, HttpResponse]:
"""
Get a sport
**Scope**: ``workouts:read``
**Example request**:
.. sourcecode:: http
GET /api/sports/1 HTTP/1.1
Content-Type: application/json
**Example response**:
2023-06-18 20:45:39 +02:00
- success for non admin user:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"sports": [
{
"color": null,
"id": 1,
"is_active": true,
"is_active_for_user": true,
"label": "Cycling (Sport)",
"stopped_speed_threshold": 1
}
]
},
"status": "success"
}
2023-06-18 20:45:39 +02:00
- success for admin user:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"sports": [
{
"color": null,
"has_workouts": false,
"id": 1,
"is_active": true,
"is_active_for_user": true,
"label": "Cycling (Sport)",
"stopped_speed_threshold": 1
}
]
},
"status": "success"
}
2023-06-18 20:45:39 +02:00
- sport not found:
.. sourcecode:: http
HTTP/1.1 404 NOT FOUND
Content-Type: application/json
{
"data": {
"sports": []
},
"status": "not found"
}
:param integer sport_id: sport id
:reqheader Authorization: OAuth 2.0 Bearer Token
2023-06-18 20:45:39 +02:00
:statuscode 200: ``success``
:statuscode 401:
2023-06-18 20:45:39 +02:00
- ``provide a valid auth token``
- ``signature expired, please log in again``
- ``invalid token, please log in again``
:statuscode 404: ``sport not found``
"""
2018-05-01 16:17:12 +02:00
sport = Sport.query.filter_by(id=sport_id).first()
if sport:
sport_preferences = UserSportPreference.query.filter_by(
user_id=auth_user.id, sport_id=sport.id
).first()
2021-01-01 16:39:25 +01:00
return {
2018-05-01 16:17:12 +02:00
'status': 'success',
'data': {
'sports': [
sport.serialize(
is_admin=auth_user.admin,
sport_preferences=sport_preferences.serialize()
if sport_preferences
else None,
)
]
},
2018-05-01 16:17:12 +02:00
}
2021-01-01 16:39:25 +01:00
return DataNotFoundErrorResponse('sports')
2018-05-01 16:17:12 +02:00
@sports_blueprint.route('/sports/<int:sport_id>', methods=['PATCH'])
2022-06-15 19:16:14 +02:00
@require_auth(scopes=['workouts:write'], as_admin=True)
def update_sport(auth_user: User, sport_id: int) -> Union[Dict, HttpResponse]:
"""
Update a sport.
Authenticated user must be an admin.
**Scope**: ``workouts:write``
**Example request**:
2019-08-28 13:25:39 +02:00
.. sourcecode:: http
2018-05-01 16:17:12 +02:00
PATCH /api/sports/1 HTTP/1.1
Content-Type: application/json
2018-05-01 16:17:12 +02:00
**Example responses**:
2018-05-01 16:17:12 +02:00
2023-06-18 20:45:39 +02:00
- success:
2018-05-01 16:17:12 +02:00
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"sports": [
{
"color": null,
"has_workouts": false,
"id": 1,
"is_active": false,
"is_active_for_user": false,
"label": "Cycling (Sport)",
"stopped_speed_threshold": 1
2018-05-01 16:17:12 +02:00
}
]
},
"status": "success"
}
2018-05-01 16:17:12 +02:00
2023-06-18 20:45:39 +02:00
- sport not found:
.. sourcecode:: http
HTTP/1.1 404 NOT FOUND
Content-Type: application/json
{
"data": {
"sports": []
},
"status": "not found"
}
:param integer sport_id: sport id
:<json string is_active: sport active status
:reqheader Authorization: OAuth 2.0 Bearer Token
:statuscode 200: sport updated
2023-06-18 20:45:39 +02:00
:statuscode 400: ``invalid payload``
:statuscode 401:
2023-06-18 20:45:39 +02:00
- ``provide a valid auth token``
- ``signature expired, please log in again``
- ``invalid token, please log in again``
:statuscode 403: ``you do not have permissions``
:statuscode 404: ``sport not found``
:statuscode 500: ``error, please try again or contact the administrator``
"""
sport_data = request.get_json()
if not sport_data or sport_data.get('is_active') is None:
2021-01-01 16:39:25 +01:00
return InvalidPayloadErrorResponse()
2018-05-01 16:17:12 +02:00
try:
sport = Sport.query.filter_by(id=sport_id).first()
2021-01-01 16:39:25 +01:00
if not sport:
return DataNotFoundErrorResponse('sports')
sport.is_active = sport_data.get('is_active')
db.session.commit()
sport_preferences = UserSportPreference.query.filter_by(
user_id=auth_user.id, sport_id=sport.id
).first()
2021-01-01 16:39:25 +01:00
return {
'status': 'success',
'data': {
'sports': [
sport.serialize(
is_admin=auth_user.admin,
sport_preferences=sport_preferences.serialize()
if sport_preferences
else None,
)
]
},
2018-05-01 16:17:12 +02:00
}
2021-01-01 16:39:25 +01:00
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
return handle_error_and_return_response(e, db=db)