From 9b1335233d9f6cd899c6155bd424777ca770bb26 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 8 May 2018 15:46:54 +0200 Subject: [PATCH] API: add an activity w/o gpx file --- mpwo_api/mpwo_api/activities/activities.py | 51 ++++++++- mpwo_api/mpwo_api/activities/models.py | 14 +-- mpwo_api/mpwo_api/tests/test_activities.py | 126 ++++++++++++++++++++- 3 files changed, 179 insertions(+), 12 deletions(-) diff --git a/mpwo_api/mpwo_api/activities/activities.py b/mpwo_api/mpwo_api/activities/activities.py index 23dc1b2b..c5b9b68d 100644 --- a/mpwo_api/mpwo_api/activities/activities.py +++ b/mpwo_api/mpwo_api/activities/activities.py @@ -1,6 +1,6 @@ import json import os -from datetime import timedelta +from datetime import datetime, timedelta from flask import Blueprint, current_app, jsonify, request from mpwo_api import appLog, db @@ -185,3 +185,52 @@ def post_activity(auth_user_id): 'message': 'Error during activity save.' } return jsonify(response_object), 500 + + +@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: + new_activity = Activity( + user_id=auth_user_id, + sport_id=activity_data.get('sport_id'), + activity_date=datetime.strptime( + activity_data.get('activity_date'), '%d/%m/%Y'), + duration=timedelta(seconds=activity_data.get('duration')) + ) + new_activity.moving = new_activity.duration + new_activity.distance = activity_data.get('distance') + new_activity.ave_speed = new_activity.distance / ( + new_activity.duration.seconds / 3600) + new_activity.max_speed = new_activity.ave_speed + 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 diff --git a/mpwo_api/mpwo_api/activities/models.py b/mpwo_api/mpwo_api/activities/models.py index 9b9c0234..c30edb27 100644 --- a/mpwo_api/mpwo_api/activities/models.py +++ b/mpwo_api/mpwo_api/activities/models.py @@ -41,13 +41,13 @@ class Activity(db.Model): duration = db.Column(db.Interval, nullable=False) pauses = db.Column(db.Interval, nullable=True) moving = db.Column(db.Interval, nullable=True) - distance = db.Column(db.Numeric(5, 2), nullable=True) - min_alt = db.Column(db.Numeric(5, 2), nullable=True) - max_alt = db.Column(db.Numeric(5, 2), nullable=True) - descent = db.Column(db.Numeric(5, 2), nullable=True) - ascent = db.Column(db.Numeric(5, 2), nullable=True) - max_speed = db.Column(db.Numeric(5, 2), nullable=True) - ave_speed = db.Column(db.Numeric(5, 2), nullable=True) + distance = db.Column(db.Numeric(5, 2), nullable=True) # kilometers + min_alt = db.Column(db.Numeric(5, 2), nullable=True) # meters + max_alt = db.Column(db.Numeric(5, 2), nullable=True) # meters + descent = db.Column(db.Numeric(5, 2), nullable=True) # meters + ascent = db.Column(db.Numeric(5, 2), nullable=True) # meters + max_speed = db.Column(db.Numeric(5, 2), nullable=True) # km/h + ave_speed = db.Column(db.Numeric(5, 2), nullable=True) # km/h def __str__(self): return str(self.sports.label) + \ diff --git a/mpwo_api/mpwo_api/tests/test_activities.py b/mpwo_api/mpwo_api/tests/test_activities.py index d464a00d..ccee96f0 100644 --- a/mpwo_api/mpwo_api/tests/test_activities.py +++ b/mpwo_api/mpwo_api/tests/test_activities.py @@ -103,7 +103,7 @@ def test_get_activities_for_authenticated_user_no_activity(app): assert len(data['data']['activities']) == 0 -def test_add_an_activity(app): +def test_add_an_activity_gpx(app): add_user('test', 'test@test.com', '12345678') add_sport('cycling') @@ -135,7 +135,7 @@ def test_add_an_activity(app): assert 'created' in data['status'] -def test_add_an_activity_invalid_file(app): +def test_add_an_activity_gpx_invalid_file(app): add_user('test', 'test@test.com', '12345678') add_sport('cycling') @@ -168,7 +168,7 @@ def test_add_an_activity_invalid_file(app): assert data['message'] == 'File extension not allowed.' -def test_add_an_activity_no_sport_id(app): +def test_add_an_activity_gpx_no_sport_id(app): add_user('test', 'test@test.com', '12345678') add_sport('cycling') @@ -201,7 +201,7 @@ def test_add_an_activity_no_sport_id(app): assert data['message'] == 'Invalid payload.' -def test_add_an_activity_no_file(app): +def test_add_an_activity_gpx_no_file(app): add_user('test', 'test@test.com', '12345678') add_sport('cycling') @@ -233,6 +233,124 @@ def test_add_an_activity_no_file(app): assert data['message'] == 'No file part.' +def test_add_an_activity_no_gpx(app): + add_user('test', 'test@test.com', '12345678') + add_sport('cycling') + + client = app.test_client() + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.post( + '/api/activities/no_gpx', + content_type='application/json', + data=json.dumps(dict( + sport_id=1, + duration=3600, + activity_date='15/05/2018', + distance=10 + )), + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) + data = json.loads(response.data.decode()) + + assert response.status_code == 201 + assert 'created' in data['status'] + assert len(data['data']['activities']) == 1 + assert 'creation_date' in data['data']['activities'][0] + assert data['data']['activities'][0]['activity_date'] == 'Tue, 15 May 2018 00:00:00 GMT' # noqa + assert data['data']['activities'][0]['user_id'] == 1 + assert data['data']['activities'][0]['sport_id'] == 1 + assert data['data']['activities'][0]['duration'] == '1:00:00' + assert data['data']['activities'][0]['ascent'] is None + assert data['data']['activities'][0]['ave_speed'] == 10.0 + assert data['data']['activities'][0]['descent'] is None + assert data['data']['activities'][0]['distance'] == 10.0 + assert data['data']['activities'][0]['max_alt'] is None + assert data['data']['activities'][0]['max_speed'] == 10.0 + assert data['data']['activities'][0]['min_alt'] is None + assert data['data']['activities'][0]['moving'] == '1:00:00' + assert data['data']['activities'][0]['pauses'] is None + + +def test_add_an_activity_no_gpx_invalid_payload(app): + add_user('test', 'test@test.com', '12345678') + add_sport('cycling') + + client = app.test_client() + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.post( + '/api/activities/no_gpx', + content_type='application/json', + data=json.dumps(dict( + sport_id=1, + duration=3600, + distance=10 + )), + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) + data = json.loads(response.data.decode()) + + assert response.status_code == 400 + assert 'error' in data['status'] + assert 'Invalid payload.' in data['message'] + + +def test_add_an_activity_no_gpx_error(app): + add_user('test', 'test@test.com', '12345678') + add_sport('cycling') + + client = app.test_client() + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.post( + '/api/activities/no_gpx', + content_type='application/json', + data=json.dumps(dict( + sport_id=1, + duration=3600, + activity_date='15/2018', + distance=10 + )), + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) + data = json.loads(response.data.decode()) + + assert response.status_code == 500 + assert 'fail' in data['status'] + assert 'Error during activity save.' in data['message'] + + def test_get_an_activity_without_gpx(app): add_user('test', 'test@test.com', '12345678') add_sport('cycling')