from typing import Dict, Union from flask import Blueprint, request from sqlalchemy import exc from fittrackee import db from fittrackee.oauth2.server import require_auth from fittrackee.responses import ( DataNotFoundErrorResponse, HttpResponse, InvalidPayloadErrorResponse, handle_error_and_return_response, ) from fittrackee.users.models import User, UserSportPreference from .models import Sport sports_blueprint = Blueprint('sports', __name__) @sports_blueprint.route('/sports', methods=['GET']) @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**: - 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" } - 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 :statuscode 200: ``success`` :statuscode 401: - ``provide a valid auth token`` - ``signature expired, please log in again`` - ``invalid token, please log in again`` """ 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, ) ) return { 'status': 'success', 'data': {'sports': sports_data}, } @sports_blueprint.route('/sports/', methods=['GET']) @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**: - 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" } - 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" } - 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 :statuscode 200: ``success`` :statuscode 401: - ``provide a valid auth token`` - ``signature expired, please log in again`` - ``invalid token, please log in again`` :statuscode 404: ``sport not found`` """ 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() return { 'status': 'success', 'data': { 'sports': [ sport.serialize( is_admin=auth_user.admin, sport_preferences=sport_preferences.serialize() if sport_preferences else None, ) ] }, } return DataNotFoundErrorResponse('sports') @sports_blueprint.route('/sports/', methods=['PATCH']) @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**: .. sourcecode:: http PATCH /api/sports/1 HTTP/1.1 Content-Type: application/json **Example responses**: - success: .. 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 } ] }, "status": "success" } - 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 :