2018-05-01 17:51:38 +02:00
|
|
|
import json
|
2018-05-09 18:54:30 +02:00
|
|
|
import os
|
2018-01-21 17:43:13 +01:00
|
|
|
|
2018-05-09 18:23:17 +02:00
|
|
|
from flask import Blueprint, jsonify, request
|
2018-05-01 17:51:38 +02:00
|
|
|
from mpwo_api import appLog, db
|
|
|
|
from sqlalchemy import exc
|
|
|
|
|
|
|
|
from ..users.utils import authenticate, verify_extension
|
2018-05-01 16:17:12 +02:00
|
|
|
from .models import Activity
|
2018-05-09 18:23:17 +02:00
|
|
|
from .utils import (
|
2018-05-10 10:21:58 +02:00
|
|
|
create_activity, edit_activity_wo_gpx, get_file_path, get_gpx_info
|
2018-05-09 18:23:17 +02:00
|
|
|
)
|
2018-01-21 17:43:13 +01:00
|
|
|
|
|
|
|
activities_blueprint = Blueprint('activities', __name__)
|
|
|
|
|
|
|
|
|
|
|
|
@activities_blueprint.route('/activities', methods=['GET'])
|
|
|
|
@authenticate
|
2018-01-21 19:45:13 +01:00
|
|
|
def get_activities(auth_user_id):
|
2018-05-08 14:44:51 +02:00
|
|
|
"""Get all activities for authenticated user"""
|
2018-05-10 23:39:59 +02:00
|
|
|
try:
|
|
|
|
params = request.args.copy()
|
|
|
|
page = 1 if len(params) == 0 else int(params.pop('page'))
|
|
|
|
activities = Activity.query.filter_by(user_id=auth_user_id)\
|
|
|
|
.order_by(Activity.activity_date.desc()).paginate(
|
|
|
|
page, 5, False).items
|
|
|
|
activities_list = []
|
|
|
|
for activity in activities:
|
|
|
|
activities_list.append(activity.serialize())
|
|
|
|
response_object = {
|
|
|
|
'status': 'success',
|
|
|
|
'data': {
|
|
|
|
'activities': activities_list
|
|
|
|
}
|
2018-01-21 17:43:13 +01:00
|
|
|
}
|
2018-05-10 23:39:59 +02:00
|
|
|
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
|
2018-05-01 17:51:38 +02:00
|
|
|
|
|
|
|
|
2018-05-01 21:26:17 +02:00
|
|
|
@activities_blueprint.route('/activities/<int:activity_id>', methods=['GET'])
|
|
|
|
@authenticate
|
|
|
|
def get_activity(auth_user_id, activity_id):
|
|
|
|
"""Get an activity"""
|
|
|
|
activity = Activity.query.filter_by(id=activity_id).first()
|
|
|
|
activities_list = []
|
|
|
|
|
|
|
|
if activity:
|
|
|
|
activities_list.append(activity.serialize())
|
2018-05-02 17:01:31 +02:00
|
|
|
status = 'success'
|
2018-05-01 21:26:17 +02:00
|
|
|
code = 200
|
|
|
|
else:
|
2018-05-02 17:01:31 +02:00
|
|
|
status = 'not found'
|
2018-05-01 21:26:17 +02:00
|
|
|
code = 404
|
2018-05-02 17:01:31 +02:00
|
|
|
|
|
|
|
response_object = {
|
|
|
|
'status': status,
|
|
|
|
'data': {
|
|
|
|
'activities': activities_list
|
|
|
|
}
|
|
|
|
}
|
2018-05-01 21:26:17 +02:00
|
|
|
return jsonify(response_object), code
|
|
|
|
|
|
|
|
|
2018-05-03 21:42:54 +02:00
|
|
|
@activities_blueprint.route(
|
2018-05-09 18:54:30 +02:00
|
|
|
'/activities/<int:activity_id>/gpx', methods=['GET']
|
2018-05-03 21:42:54 +02:00
|
|
|
)
|
|
|
|
@authenticate
|
|
|
|
def get_activity_gpx(auth_user_id, activity_id):
|
|
|
|
"""Get gpx file for an activity"""
|
|
|
|
activity = Activity.query.filter_by(id=activity_id).first()
|
|
|
|
if activity:
|
|
|
|
if not activity.gpx or activity.gpx == '':
|
|
|
|
response_object = {
|
|
|
|
'status': 'fail',
|
|
|
|
'message': 'No gpx file for this activity (id: {})'.format(
|
|
|
|
activity_id
|
|
|
|
)
|
|
|
|
}
|
2018-05-09 16:32:06 +02:00
|
|
|
return jsonify(response_object), 400
|
2018-05-03 21:42:54 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
with open(activity.gpx, encoding='utf-8') as f:
|
2018-05-09 16:32:06 +02:00
|
|
|
gpx_content = f.read()
|
2018-05-03 21:42:54 +02:00
|
|
|
except Exception as e:
|
|
|
|
appLog.error(e)
|
2018-05-09 16:32:06 +02:00
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'internal error',
|
|
|
|
'data': {
|
|
|
|
'gpx': ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 500
|
2018-05-03 21:42:54 +02:00
|
|
|
|
|
|
|
status = 'success'
|
2018-05-09 16:32:06 +02:00
|
|
|
message = ''
|
2018-05-03 21:42:54 +02:00
|
|
|
code = 200
|
|
|
|
else:
|
2018-05-09 16:32:06 +02:00
|
|
|
gpx_content = ''
|
2018-05-03 21:42:54 +02:00
|
|
|
status = 'not found'
|
|
|
|
message = 'Activity not found (id: {})'.format(activity_id)
|
|
|
|
code = 404
|
|
|
|
|
|
|
|
response_object = {
|
|
|
|
'status': status,
|
|
|
|
'message': message,
|
|
|
|
'data': {
|
|
|
|
'gpx': gpx_content
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return jsonify(response_object), code
|
|
|
|
|
|
|
|
|
2018-05-01 17:51:38 +02:00
|
|
|
@activities_blueprint.route('/activities', methods=['POST'])
|
|
|
|
@authenticate
|
|
|
|
def post_activity(auth_user_id):
|
|
|
|
"""Post an activity"""
|
|
|
|
response_object = verify_extension('activity', request)
|
|
|
|
if response_object['status'] != 'success':
|
2018-05-09 16:32:06 +02:00
|
|
|
return jsonify(response_object), 400
|
2018-05-01 17:51:38 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
activity_file = request.files['file']
|
2018-05-09 16:32:06 +02:00
|
|
|
file_path = get_file_path(auth_user_id, activity_file)
|
2018-05-01 17:51:38 +02:00
|
|
|
|
|
|
|
try:
|
2018-05-09 16:32:06 +02:00
|
|
|
activity_file.save(file_path)
|
|
|
|
gpx_data = get_gpx_info(file_path)
|
2018-05-01 17:51:38 +02:00
|
|
|
except Exception as e:
|
|
|
|
appLog.error(e)
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Error during activity file save.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 500
|
|
|
|
|
|
|
|
try:
|
2018-05-10 10:21:58 +02:00
|
|
|
new_activity = create_activity(
|
|
|
|
auth_user_id, activity_data, gpx_data, file_path)
|
2018-05-01 19:29:21 +02:00
|
|
|
db.session.add(new_activity)
|
2018-05-01 17:51:38 +02:00
|
|
|
db.session.commit()
|
|
|
|
response_object = {
|
|
|
|
'status': 'created',
|
2018-05-02 17:01:31 +02:00
|
|
|
'data': {
|
|
|
|
'activities': [new_activity.serialize()]
|
|
|
|
}
|
2018-05-01 17:51:38 +02:00
|
|
|
}
|
|
|
|
return jsonify(response_object), 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
|
2018-05-08 15:46:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
@activities_blueprint.route('/activities/no_gpx', methods=['POST'])
|
|
|
|
@authenticate
|
|
|
|
def post_activity_no_gpx(auth_user_id):
|
|
|
|
"""Post an activity without gpx file"""
|
|
|
|
activity_data = request.get_json()
|
|
|
|
if not activity_data or activity_data.get('sport_id') is None \
|
|
|
|
or activity_data.get('duration') is None \
|
|
|
|
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
|
|
|
|
|
|
|
|
try:
|
2018-05-10 10:21:58 +02:00
|
|
|
new_activity = create_activity(auth_user_id, activity_data)
|
2018-05-08 15:46:54 +02:00
|
|
|
db.session.add(new_activity)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
response_object = {
|
|
|
|
'status': 'created',
|
|
|
|
'data': {
|
|
|
|
'activities': [new_activity.serialize()]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 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
|
2018-05-09 18:54:30 +02:00
|
|
|
|
|
|
|
|
2018-05-09 20:45:01 +02:00
|
|
|
@activities_blueprint.route('/activities/<int:activity_id>', methods=['PATCH'])
|
|
|
|
@authenticate
|
|
|
|
def update_activity(auth_user_id, activity_id):
|
|
|
|
"""Update an activity"""
|
|
|
|
activity_data = request.get_json()
|
|
|
|
if not activity_data or activity_data.get('sport_id') is None \
|
|
|
|
or activity_data.get('duration') is None \
|
|
|
|
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
|
|
|
|
|
|
|
|
try:
|
|
|
|
activity = Activity.query.filter_by(id=activity_id).first()
|
|
|
|
if activity:
|
|
|
|
if activity.gpx:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'You can not modify an activity with gpx file. '
|
|
|
|
'Please delete and re-import the gpx file.'
|
|
|
|
}
|
|
|
|
code = 500
|
|
|
|
return jsonify(response_object), code
|
|
|
|
|
|
|
|
activity = edit_activity_wo_gpx(activity, activity_data)
|
|
|
|
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.'
|
|
|
|
}
|
|
|
|
code = 500
|
|
|
|
return jsonify(response_object), code
|
|
|
|
|
|
|
|
|
2018-05-09 18:54:30 +02:00
|
|
|
@activities_blueprint.route(
|
|
|
|
'/activities/<int:activity_id>', methods=['DELETE']
|
|
|
|
)
|
|
|
|
@authenticate
|
|
|
|
def delete_activity(auth_user_id, activity_id):
|
|
|
|
"""Delete an activity"""
|
|
|
|
try:
|
|
|
|
activity = Activity.query.filter_by(id=activity_id).first()
|
|
|
|
if activity:
|
|
|
|
gpx_filepath = activity.gpx
|
|
|
|
db.session.delete(activity)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
if gpx_filepath:
|
|
|
|
os.remove(gpx_filepath)
|
|
|
|
|
|
|
|
response_object = {
|
|
|
|
'status': 'no content'
|
|
|
|
}
|
|
|
|
code = 204
|
|
|
|
else:
|
|
|
|
response_object = {
|
|
|
|
'status': 'not found',
|
|
|
|
'data': {
|
|
|
|
'activities': []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
code = 404
|
|
|
|
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
|