API - refactor api responses

This commit is contained in:
Sam
2021-01-01 16:39:25 +01:00
parent 21e79c8883
commit 4705393a08
15 changed files with 482 additions and 564 deletions

View File

@ -5,7 +5,15 @@ from datetime import datetime, timedelta
import requests
from fittrackee import appLog, db
from flask import Blueprint, Response, current_app, jsonify, request, send_file
from fittrackee.responses import (
DataInvalidPayloadErrorResponse,
DataNotFoundErrorResponse,
InternalServerErrorResponse,
InvalidPayloadErrorResponse,
NotFoundErrorResponse,
handle_error_and_return_response,
)
from flask import Blueprint, Response, current_app, request, send_file
from sqlalchemy import exc
from ..users.utils import (
@ -251,7 +259,7 @@ def get_activities(auth_user_id):
.paginate(page, per_page, False)
.items
)
response_object = {
return {
'status': 'success',
'data': {
'activities': [
@ -259,15 +267,8 @@ def get_activities(auth_user_id):
]
},
}
code = 200
except Exception as e:
appLog.error(e)
response_object = {
'status': 'error',
'message': 'Error. Please try again or contact the administrator.',
}
code = 500
return jsonify(response_object), code
return handle_error_and_return_response(e)
@activities_blueprint.route(
@ -360,27 +361,17 @@ def get_activity(auth_user_id, activity_short_id):
"""
activity_uuid = decode_short_id(activity_short_id)
activity = Activity.query.filter_by(uuid=activity_uuid).first()
activities_list = []
if not activity:
return DataNotFoundErrorResponse('activities')
if activity:
response_object, code = can_view_activity(
auth_user_id, activity.user_id
)
if response_object:
return jsonify(response_object), code
error_response = can_view_activity(auth_user_id, activity.user_id)
if error_response:
return error_response
activities_list.append(activity.serialize())
status = 'success'
code = 200
else:
status = 'not found'
code = 404
response_object = {
'status': status,
'data': {'activities': activities_list},
return {
'status': 'success',
'data': {'activities': [activity.serialize()]},
}
return jsonify(response_object), code
def get_activity_data(
@ -389,59 +380,44 @@ def get_activity_data(
"""Get data from an activity gpx file"""
activity_uuid = decode_short_id(activity_short_id)
activity = Activity.query.filter_by(uuid=activity_uuid).first()
content = ''
if activity:
response_object, code = can_view_activity(
auth_user_id, activity.user_id
if not activity:
return DataNotFoundErrorResponse(
data_type=data_type,
message=f'Activity not found (id: {activity_short_id})',
)
if response_object:
return jsonify(response_object), code
if not activity.gpx or activity.gpx == '':
message = (
f'No gpx file for this activity (id: {activity_short_id})'
)
response_object = {'status': 'error', 'message': message}
return jsonify(response_object), 404
try:
absolute_gpx_filepath = get_absolute_file_path(activity.gpx)
if data_type == 'chart':
content = get_chart_data(absolute_gpx_filepath, segment_id)
else: # data_type == 'gpx'
with open(absolute_gpx_filepath, encoding='utf-8') as f:
content = f.read()
if segment_id is not None:
content = extract_segment_from_gpx_file(
content, segment_id
)
except ActivityGPXException as e:
appLog.error(e.message)
response_object = {'status': e.status, 'message': e.message}
code = 404 if e.status == 'not found' else 500
return jsonify(response_object), code
except Exception as e:
appLog.error(e)
response_object = {'status': 'error', 'message': 'internal error'}
return jsonify(response_object), 500
error_response = can_view_activity(auth_user_id, activity.user_id)
if error_response:
return error_response
if not activity.gpx or activity.gpx == '':
return NotFoundErrorResponse(
f'No gpx file for this activity (id: {activity_short_id})'
)
status = 'success'
message = ''
code = 200
else:
status = 'not found'
message = f'Activity not found (id: {activity_short_id})'
code = 404
try:
absolute_gpx_filepath = get_absolute_file_path(activity.gpx)
if data_type == 'chart_data':
content = get_chart_data(absolute_gpx_filepath, segment_id)
else: # data_type == 'gpx'
with open(absolute_gpx_filepath, encoding='utf-8') as f:
content = f.read()
if segment_id is not None:
content = extract_segment_from_gpx_file(
content, segment_id
)
except ActivityGPXException as e:
appLog.error(e.message)
if e.status == 'not found':
return NotFoundErrorResponse(e.message)
return InternalServerErrorResponse(e.message)
except Exception as e:
return handle_error_and_return_response(e)
response_object = {
'status': status,
'message': message,
'data': (
{'chart_data': content}
if data_type == 'chart'
else {'gpx': content}
),
return {
'status': 'success',
'message': '',
'data': ({data_type: content}),
}
return jsonify(response_object), code
@activities_blueprint.route(
@ -558,7 +534,7 @@ def get_activity_chart_data(auth_user_id, activity_short_id):
:statuscode 500:
"""
return get_activity_data(auth_user_id, activity_short_id, 'chart')
return get_activity_data(auth_user_id, activity_short_id, 'chart_data')
@activities_blueprint.route(
@ -681,7 +657,7 @@ def get_segment_chart_data(auth_user_id, activity_short_id, segment_id):
"""
return get_activity_data(
auth_user_id, activity_short_id, 'chart', segment_id
auth_user_id, activity_short_id, 'chart_data', segment_id
)
@ -718,18 +694,11 @@ def get_map(map_id):
try:
activity = Activity.query.filter_by(map_id=map_id).first()
if not activity:
response_object = {
'status': 'error',
'message': 'Map does not exist',
}
return jsonify(response_object), 404
else:
absolute_map_filepath = get_absolute_file_path(activity.map)
return send_file(absolute_map_filepath)
return NotFoundErrorResponse('Map does not exist.')
absolute_map_filepath = get_absolute_file_path(activity.map)
return send_file(absolute_map_filepath)
except Exception as e:
appLog.error(e)
response_object = {'status': 'error', 'message': 'internal error.'}
return jsonify(response_object), 500
return handle_error_and_return_response(e)
@activities_blueprint.route(
@ -887,16 +856,13 @@ def post_activity(auth_user_id):
:statuscode 500:
"""
response_object, response_code = verify_extension_and_size(
'activity', request
)
if response_object['status'] != 'success':
return jsonify(response_object), response_code
error_response = verify_extension_and_size('activity', request)
if error_response:
return error_response
activity_data = json.loads(request.form['data'])
if not activity_data or activity_data.get('sport_id') is None:
response_object = {'status': 'error', 'message': 'Invalid payload.'}
return jsonify(response_object), 400
return InvalidPayloadErrorResponse()
activity_file = request.files['file']
upload_dir = os.path.join(
@ -921,20 +887,19 @@ def post_activity(auth_user_id):
]
},
}
code = 201
else:
response_object = {'status': 'fail', 'data': {'activities': []}}
code = 400
return DataInvalidPayloadErrorResponse('activities', 'fail')
except ActivityException as e:
db.session.rollback()
if e.e:
appLog.error(e.e)
response_object = {'status': e.status, 'message': e.message}
code = 500 if e.status == 'error' else 400
if e.status == 'error':
return InternalServerErrorResponse(e.message)
return InvalidPayloadErrorResponse(e.message)
shutil.rmtree(folders['extract_dir'], ignore_errors=True)
shutil.rmtree(folders['tmp_dir'], ignore_errors=True)
return jsonify(response_object), code
return response_object, 201
@activities_blueprint.route('/activities/no_gpx', methods=['POST'])
@ -1059,8 +1024,7 @@ def post_activity_no_gpx(auth_user_id):
or activity_data.get('distance') is None
or activity_data.get('activity_date') is None
):
response_object = {'status': 'error', 'message': 'Invalid payload.'}
return jsonify(response_object), 400
return InvalidPayloadErrorResponse()
try:
user = User.query.filter_by(id=auth_user_id).first()
@ -1068,20 +1032,21 @@ def post_activity_no_gpx(auth_user_id):
db.session.add(new_activity)
db.session.commit()
response_object = {
'status': 'created',
'data': {'activities': [new_activity.serialize()]},
}
return jsonify(response_object), 201
return (
{
'status': 'created',
'data': {'activities': [new_activity.serialize()]},
},
201,
)
except (exc.IntegrityError, ValueError) as e:
db.session.rollback()
appLog.error(e)
response_object = {
'status': 'fail',
'message': 'Error during activity save.',
}
return jsonify(response_object), 500
return handle_error_and_return_response(
error=e,
message='Error during activity save.',
status='fail',
db=db,
)
@activities_blueprint.route(
@ -1207,41 +1172,27 @@ def update_activity(auth_user_id, activity_short_id):
"""
activity_data = request.get_json()
if not activity_data:
response_object = {'status': 'error', 'message': 'Invalid payload.'}
return jsonify(response_object), 400
return InvalidPayloadErrorResponse()
try:
activity_uuid = decode_short_id(activity_short_id)
activity = Activity.query.filter_by(uuid=activity_uuid).first()
if activity:
response_object, code = can_view_activity(
auth_user_id, activity.user_id
)
if response_object:
return jsonify(response_object), code
if not activity:
return DataNotFoundErrorResponse('activities')
activity = edit_activity(activity, activity_data, auth_user_id)
db.session.commit()
response_object = {
'status': 'success',
'data': {'activities': [activity.serialize()]},
}
code = 200
else:
response_object = {
'status': 'not found',
'data': {'activities': []},
}
code = 404
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
db.session.rollback()
appLog.error(e)
response_object = {
'status': 'error',
'message': 'Error. Please try again or contact the administrator.',
response_object = can_view_activity(auth_user_id, activity.user_id)
if response_object:
return response_object
activity = edit_activity(activity, activity_data, auth_user_id)
db.session.commit()
return {
'status': 'success',
'data': {'activities': [activity.serialize()]},
}
code = 500
return jsonify(response_object), code
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
return handle_error_and_return_response(e)
@activities_blueprint.route(
@ -1284,34 +1235,19 @@ def delete_activity(auth_user_id, activity_short_id):
try:
activity_uuid = decode_short_id(activity_short_id)
activity = Activity.query.filter_by(uuid=activity_uuid).first()
if activity:
response_object, code = can_view_activity(
auth_user_id, activity.user_id
)
if response_object:
return jsonify(response_object), code
if not activity:
return DataNotFoundErrorResponse('activities')
error_response = can_view_activity(auth_user_id, activity.user_id)
if error_response:
return error_response
db.session.delete(activity)
db.session.commit()
response_object = {'status': 'no content'}
code = 204
else:
response_object = {
'status': 'not found',
'data': {'activities': []},
}
code = 404
db.session.delete(activity)
db.session.commit()
return {'status': 'no content'}, 204
except (
exc.IntegrityError,
exc.OperationalError,
ValueError,
OSError,
) as e:
db.session.rollback()
appLog.error(e)
response_object = {
'status': 'error',
'message': 'Error. Please try again or contact the administrator.',
}
code = 500
return jsonify(response_object), code
return handle_error_and_return_response(e, db=db)

View File

@ -1,4 +1,4 @@
from flask import Blueprint, jsonify
from flask import Blueprint
from ..users.utils import authenticate
from .models import Record
@ -103,14 +103,12 @@ def get_records(auth_user_id):
- Invalid token. Please log in again.
"""
records = (
Record.query.filter_by(user_id=auth_user_id)
.order_by(Record.sport_id.asc(), Record.record_type.asc())
.all()
)
response_object = {
return {
'status': 'success',
'data': {'records': [record.serialize() for record in records]},
}
return jsonify(response_object), 200

View File

@ -1,5 +1,10 @@
from fittrackee import appLog, db
from flask import Blueprint, jsonify, request
from fittrackee import db
from fittrackee.responses import (
DataNotFoundErrorResponse,
InvalidPayloadErrorResponse,
handle_error_and_return_response,
)
from flask import Blueprint, request
from sqlalchemy import exc
from ..users.models import User
@ -143,14 +148,12 @@ def get_sports(auth_user_id):
- 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()
response_object = {
return {
'status': 'success',
'data': {'sports': [sport.serialize(user.admin) for sport in sports]},
}
return jsonify(response_object), 200
@sports_blueprint.route('/sports/<int:sport_id>', methods=['GET'])
@ -238,19 +241,14 @@ def get_sport(auth_user_id, sport_id):
: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:
response_object = {
return {
'status': 'success',
'data': {'sports': [sport.serialize(user.admin)]},
}
code = 200
else:
response_object = {'status': 'not found', 'data': {'sports': []}}
code = 404
return jsonify(response_object), code
return DataNotFoundErrorResponse('sports')
@sports_blueprint.route('/sports/<int:sport_id>', methods=['PATCH'])
@ -325,28 +323,19 @@ def update_sport(auth_user_id, sport_id):
"""
sport_data = request.get_json()
if not sport_data or sport_data.get('is_active') is None:
response_object = {'status': 'error', 'message': 'Invalid payload.'}
return jsonify(response_object), 400
return InvalidPayloadErrorResponse()
try:
sport = Sport.query.filter_by(id=sport_id).first()
if sport:
sport.is_active = sport_data.get('is_active')
db.session.commit()
response_object = {
'status': 'success',
'data': {'sports': [sport.serialize(True)]},
}
code = 200
else:
response_object = {'status': 'not found', 'data': {'sports': []}}
code = 404
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
db.session.rollback()
appLog.error(e)
response_object = {
'status': 'error',
'message': 'Error. Please try again or contact the administrator.',
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)]},
}
code = 500
return jsonify(response_object), code
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
return handle_error_and_return_response(e, db=db)

View File

@ -1,7 +1,13 @@
from datetime import datetime, timedelta
from fittrackee import appLog, db
from flask import Blueprint, jsonify, request
from fittrackee import db
from fittrackee.responses import (
InvalidPayloadErrorResponse,
NotFoundErrorResponse,
UserNotFoundErrorResponse,
handle_error_and_return_response,
)
from flask import Blueprint, request
from sqlalchemy import func
from ..users.models import User
@ -17,11 +23,7 @@ def get_activities(user_name, filter_type):
try:
user = User.query.filter_by(username=user_name).first()
if not user:
response_object = {
'status': 'not found',
'message': 'User does not exist.',
}
return jsonify(response_object), 404
return UserNotFoundErrorResponse()
params = request.args.copy()
date_from = params.get('from')
@ -42,11 +44,7 @@ def get_activities(user_name, filter_type):
if sport_id:
sport = Sport.query.filter_by(id=sport_id).first()
if not sport:
response_object = {
'status': 'not found',
'message': 'Sport does not exist.',
}
return jsonify(response_object), 404
return NotFoundErrorResponse('Sport does not exist.')
activities = (
Activity.query.filter(
@ -103,11 +101,9 @@ def get_activities(user_name, filter_type):
activity.activity_date, "%Y"
)
else:
response_object = {
'status': 'fail',
'message': 'Invalid time period.',
}
return jsonify(response_object), 400
return InvalidPayloadErrorResponse(
'Invalid time period.', 'fail'
)
sport_id = activity.sport_id
if time_period not in activities_list:
activities_list[time_period] = {}
@ -125,19 +121,12 @@ def get_activities(user_name, filter_type):
'total_duration'
] += convert_timedelta_to_integer(activity.moving)
response_object = {
return {
'status': 'success',
'data': {'statistics': activities_list},
}
code = 200
except Exception as e:
appLog.error(e)
response_object = {
'status': 'error',
'message': 'Error. Please try again or contact the administrator.',
}
code = 500
return jsonify(response_object), code
return handle_error_and_return_response(e)
@stats_blueprint.route('/stats/<user_name>/by_time', methods=['GET'])
@ -371,7 +360,7 @@ def get_application_stats(auth_user_id):
.group_by(Activity.sport_id)
.count()
)
response_object = {
return {
'status': 'success',
'data': {
'activities': nb_activities,
@ -380,4 +369,3 @@ def get_application_stats(auth_user_id):
'uploads_dir_size': get_upload_dir_size(),
},
}
return jsonify(response_object), 200