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.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,
|
|
|
|
)
|
2021-01-20 16:47:00 +01:00
|
|
|
from fittrackee.users.decorators import authenticate, authenticate_as_admin
|
|
|
|
from fittrackee.users.models import User
|
2018-05-01 16:17:12 +02:00
|
|
|
|
|
|
|
from .models import Sport
|
|
|
|
|
|
|
|
sports_blueprint = Blueprint('sports', __name__)
|
|
|
|
|
|
|
|
|
|
|
|
@sports_blueprint.route('/sports', methods=['GET'])
|
|
|
|
@authenticate
|
2021-01-02 19:28:03 +01:00
|
|
|
def get_sports(auth_user_id: int) -> Dict:
|
2019-07-20 21:57:35 +02:00
|
|
|
"""
|
|
|
|
Get all sports
|
|
|
|
|
|
|
|
**Example request**:
|
|
|
|
|
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
GET /api/sports HTTP/1.1
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
**Example response**:
|
|
|
|
|
2019-09-23 14:09:26 +02:00
|
|
|
- for non admin user :
|
|
|
|
|
2019-07-20 21:57:35 +02:00
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
HTTP/1.1 200 OK
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"sports": [
|
|
|
|
{
|
|
|
|
"id": 1,
|
|
|
|
"img": "/img/sports/cycling-sport.png",
|
2019-09-22 23:03:56 +02:00
|
|
|
"is_active": true,
|
2019-07-20 21:57:35 +02:00
|
|
|
"label": "Cycling (Sport)"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"id": 2,
|
|
|
|
"img": "/img/sports/cycling-transport.png",
|
2019-09-22 23:03:56 +02:00
|
|
|
"is_active": true,
|
2019-07-20 21:57:35 +02:00
|
|
|
"label": "Cycling (Transport)"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"id": 3,
|
|
|
|
"img": "/img/sports/hiking.png",
|
2019-09-22 23:03:56 +02:00
|
|
|
"is_active": true,
|
2019-07-20 21:57:35 +02:00
|
|
|
"label": "Hiking"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"id": 4,
|
|
|
|
"img": "/img/sports/mountain-biking.png",
|
2019-09-22 23:03:56 +02:00
|
|
|
"is_active": true,
|
2019-07-20 21:57:35 +02:00
|
|
|
"label": "Mountain Biking"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"img": "/img/sports/running.png",
|
2019-09-22 23:03:56 +02:00
|
|
|
"is_active": true,
|
2019-07-20 21:57:35 +02:00
|
|
|
"label": "Running"
|
|
|
|
},
|
|
|
|
{
|
2019-09-23 14:09:26 +02:00
|
|
|
"id": 6,
|
|
|
|
"img": "/img/sports/walking.png",
|
|
|
|
"is_active": true,
|
|
|
|
"label": "Walking"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"status": "success"
|
|
|
|
}
|
|
|
|
|
|
|
|
- for admin user :
|
|
|
|
|
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
HTTP/1.1 200 OK
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"sports": [
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": true,
|
2019-09-23 14:09:26 +02:00
|
|
|
"id": 1,
|
|
|
|
"img": "/img/sports/cycling-sport.png",
|
|
|
|
"is_active": true,
|
|
|
|
"label": "Cycling (Sport)"
|
|
|
|
},
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": false,
|
2019-09-23 14:09:26 +02:00
|
|
|
"id": 2,
|
|
|
|
"img": "/img/sports/cycling-transport.png",
|
|
|
|
"is_active": true,
|
|
|
|
"label": "Cycling (Transport)"
|
|
|
|
},
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": false,
|
2019-09-23 14:09:26 +02:00
|
|
|
"id": 3,
|
|
|
|
"img": "/img/sports/hiking.png",
|
|
|
|
"is_active": true,
|
|
|
|
"label": "Hiking"
|
|
|
|
},
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": false,
|
2019-09-23 14:09:26 +02:00
|
|
|
"id": 4,
|
|
|
|
"img": "/img/sports/mountain-biking.png",
|
|
|
|
"is_active": true,
|
|
|
|
"label": "Mountain Biking"
|
|
|
|
},
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": false,
|
2019-09-23 14:09:26 +02:00
|
|
|
"id": 5,
|
|
|
|
"img": "/img/sports/running.png",
|
|
|
|
"is_active": true,
|
|
|
|
"label": "Running"
|
|
|
|
},
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": false,
|
2019-07-20 21:57:35 +02:00
|
|
|
"id": 6,
|
|
|
|
"img": "/img/sports/walking.png",
|
2019-09-22 23:03:56 +02:00
|
|
|
"is_active": true,
|
2019-07-20 21:57:35 +02:00
|
|
|
"label": "Walking"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"status": "success"
|
|
|
|
}
|
|
|
|
|
|
|
|
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
|
|
|
|
|
|
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
|
|
|
|
|
|
|
:statuscode 200: success
|
|
|
|
:statuscode 401:
|
2021-11-01 09:44:10 +01:00
|
|
|
- provide a valid auth token
|
|
|
|
- signature expired, please log in again
|
|
|
|
- invalid token, please log in again
|
2019-07-20 21:57:35 +02:00
|
|
|
|
|
|
|
"""
|
2019-09-23 14:09:26 +02:00
|
|
|
user = User.query.filter_by(id=int(auth_user_id)).first()
|
2018-05-01 16:17:12 +02:00
|
|
|
sports = Sport.query.order_by(Sport.id).all()
|
2021-01-01 16:39:25 +01:00
|
|
|
return {
|
2018-05-01 16:17:12 +02:00
|
|
|
'status': 'success',
|
2019-09-23 14:09:26 +02:00
|
|
|
'data': {'sports': [sport.serialize(user.admin) for sport in sports]},
|
2018-05-01 16:17:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@sports_blueprint.route('/sports/<int:sport_id>', methods=['GET'])
|
|
|
|
@authenticate
|
2021-01-02 19:28:03 +01:00
|
|
|
def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
|
2019-09-23 14:09:26 +02:00
|
|
|
"""
|
|
|
|
Get a sport
|
2019-07-20 21:57:35 +02:00
|
|
|
|
|
|
|
**Example request**:
|
|
|
|
|
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
GET /api/sports/1 HTTP/1.1
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
**Example response**:
|
|
|
|
|
2019-09-23 14:09:26 +02:00
|
|
|
- success for non admin user :
|
2019-07-20 21:57:35 +02:00
|
|
|
|
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
HTTP/1.1 200 OK
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"sports": [
|
|
|
|
{
|
2019-09-23 14:09:26 +02:00
|
|
|
"id": 1,
|
|
|
|
"img": "/img/sports/cycling-sport.png",
|
|
|
|
"is_active": true,
|
|
|
|
"label": "Cycling (Sport)"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"status": "success"
|
|
|
|
}
|
|
|
|
|
|
|
|
- success for admin user :
|
|
|
|
|
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
HTTP/1.1 200 OK
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"sports": [
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": false,
|
2019-07-20 21:57:35 +02:00
|
|
|
"id": 1,
|
|
|
|
"img": "/img/sports/cycling-sport.png",
|
2019-09-22 23:03:56 +02:00
|
|
|
"is_active": true,
|
2019-07-20 21:57:35 +02:00
|
|
|
"label": "Cycling (Sport)"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"status": "success"
|
|
|
|
}
|
|
|
|
|
|
|
|
- sport not found
|
|
|
|
|
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
HTTP/1.1 404 NOT FOUND
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"sports": []
|
|
|
|
},
|
|
|
|
"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
|
|
|
|
|
|
|
|
:statuscode 200: success
|
|
|
|
:statuscode 401:
|
2021-11-01 09:44:10 +01:00
|
|
|
- provide a valid auth token
|
|
|
|
- signature expired, please log in again
|
|
|
|
- invalid token, please log in again
|
2019-07-20 21:57:35 +02:00
|
|
|
:statuscode 404: sport not found
|
|
|
|
|
|
|
|
"""
|
2019-09-23 14:09:26 +02:00
|
|
|
user = User.query.filter_by(id=int(auth_user_id)).first()
|
2018-05-01 16:17:12 +02:00
|
|
|
sport = Sport.query.filter_by(id=sport_id).first()
|
|
|
|
if sport:
|
2021-01-01 16:39:25 +01:00
|
|
|
return {
|
2018-05-01 16:17:12 +02:00
|
|
|
'status': 'success',
|
2019-09-23 14:09:26 +02:00
|
|
|
'data': {'sports': [sport.serialize(user.admin)]},
|
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
|
|
|
|
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
@sports_blueprint.route('/sports/<int:sport_id>', methods=['PATCH'])
|
|
|
|
@authenticate_as_admin
|
2021-01-02 19:28:03 +01:00
|
|
|
def update_sport(
|
|
|
|
auth_user_id: int, sport_id: int
|
|
|
|
) -> Union[Dict, HttpResponse]:
|
2019-09-23 14:09:26 +02:00
|
|
|
"""
|
|
|
|
Update a sport
|
|
|
|
Authenticated user must be an admin
|
2019-07-20 21:57:35 +02:00
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
**Example request**:
|
2019-08-28 13:25:39 +02:00
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
.. sourcecode:: http
|
2018-05-01 16:17:12 +02:00
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
PATCH /api/sports/1 HTTP/1.1
|
|
|
|
Content-Type: application/json
|
2018-05-01 16:17:12 +02:00
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
**Example response**:
|
2018-05-01 16:17:12 +02:00
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
- success
|
2018-05-01 16:17:12 +02:00
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
HTTP/1.1 200 OK
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"sports": [
|
|
|
|
{
|
2021-01-10 11:16:43 +01:00
|
|
|
"has_workouts": false,
|
2019-09-22 23:03:56 +02:00
|
|
|
"id": 1,
|
|
|
|
"img": "/img/sports/cycling-sport.png",
|
|
|
|
"is_active": false,
|
|
|
|
"label": "Cycling (Sport)"
|
2018-05-01 16:17:12 +02:00
|
|
|
}
|
2019-09-22 23:03:56 +02:00
|
|
|
]
|
|
|
|
},
|
|
|
|
"status": "success"
|
|
|
|
}
|
2018-05-01 16:17:12 +02:00
|
|
|
|
2019-09-22 23:03:56 +02:00
|
|
|
- sport not found
|
|
|
|
|
|
|
|
.. sourcecode:: http
|
|
|
|
|
|
|
|
HTTP/1.1 404 NOT FOUND
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"sports": []
|
|
|
|
},
|
|
|
|
"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
|
|
|
|
|
|
|
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
|
|
|
|
|
|
|
:statuscode 200: sport updated
|
|
|
|
:statuscode 400: invalid payload
|
|
|
|
:statuscode 401:
|
2021-11-01 09:44:10 +01: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
|
2019-09-22 23:03:56 +02:00
|
|
|
:statuscode 404: sport not found
|
|
|
|
:statuscode 500:
|
|
|
|
|
|
|
|
"""
|
|
|
|
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()
|
|
|
|
return {
|
|
|
|
'status': 'success',
|
|
|
|
'data': {'sports': [sport.serialize(True)]},
|
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)
|