API & Client: now activity w/ gpx can be modified

+ fix (source and tests)
This commit is contained in:
Sam 2018-05-11 17:55:46 +02:00
parent 288528716c
commit 74dcdc6840
14 changed files with 1298 additions and 1043 deletions

View File

@ -8,7 +8,7 @@ from sqlalchemy import exc
from ..users.utils import authenticate, verify_extension from ..users.utils import authenticate, verify_extension
from .models import Activity, Sport from .models import Activity, Sport
from .utils import ( from .utils import (
create_activity, edit_activity_wo_gpx, get_file_path, get_gpx_info, create_activity, edit_activity, get_file_path, get_gpx_info,
get_new_file_path get_new_file_path
) )
@ -225,10 +225,7 @@ def post_activity_no_gpx(auth_user_id):
def update_activity(auth_user_id, activity_id): def update_activity(auth_user_id, activity_id):
"""Update an activity""" """Update an activity"""
activity_data = request.get_json() activity_data = request.get_json()
if not activity_data or activity_data.get('sport_id') is None \ if not activity_data:
or activity_data.get('duration') is None \
or activity_data.get('distance') is None \
or activity_data.get('activity_date') is None:
response_object = { response_object = {
'status': 'error', 'status': 'error',
'message': 'Invalid payload.' 'message': 'Invalid payload.'
@ -238,16 +235,7 @@ def update_activity(auth_user_id, activity_id):
try: try:
activity = Activity.query.filter_by(id=activity_id).first() activity = Activity.query.filter_by(id=activity_id).first()
if activity: if activity:
if activity.gpx: activity = edit_activity(activity, activity_data)
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() db.session.commit()
response_object = { response_object = {
'status': 'success', 'status': 'success',

View File

@ -60,10 +60,11 @@ class Activity(db.Model):
return str(self.sports.label) + \ return str(self.sports.label) + \
" - " + self.activity_date.strftime('%Y-%m-%d') " - " + self.activity_date.strftime('%Y-%m-%d')
def __init__(self, user_id, sport_id, activity_date, duration): def __init__(self, user_id, sport_id, activity_date, distance, duration):
self.user_id = user_id self.user_id = user_id
self.sport_id = sport_id self.sport_id = sport_id
self.activity_date = activity_date self.activity_date = activity_date
self.distance = distance
self.duration = duration self.duration = duration
def serialize(self): def serialize(self):

View File

@ -16,11 +16,14 @@ def create_activity(
activity_data.get('activity_date'), '%Y-%m-%d %H:%M') activity_data.get('activity_date'), '%Y-%m-%d %H:%M')
duration = timedelta(seconds=gpx_data['duration']) if gpx_data \ duration = timedelta(seconds=gpx_data['duration']) if gpx_data \
else timedelta(seconds=activity_data.get('duration')) else timedelta(seconds=activity_data.get('duration'))
distance = gpx_data['distance'] if gpx_data \
else activity_data.get('distance')
new_activity = Activity( new_activity = Activity(
user_id=auth_user_id, user_id=auth_user_id,
sport_id=activity_data.get('sport_id'), sport_id=activity_data.get('sport_id'),
activity_date=activity_date, activity_date=activity_date,
distance=distance,
duration=duration duration=duration
) )
@ -28,7 +31,6 @@ def create_activity(
new_activity.gpx = gpx_data['filename'] new_activity.gpx = gpx_data['filename']
new_activity.pauses = timedelta(seconds=gpx_data['stop_time']) new_activity.pauses = timedelta(seconds=gpx_data['stop_time'])
new_activity.moving = timedelta(seconds=gpx_data['moving_time']) new_activity.moving = timedelta(seconds=gpx_data['moving_time'])
new_activity.distance = gpx_data['distance']
new_activity.min_alt = gpx_data['elevation_min'] new_activity.min_alt = gpx_data['elevation_min']
new_activity.max_alt = gpx_data['elevation_max'] new_activity.max_alt = gpx_data['elevation_max']
new_activity.descent = gpx_data['downhill'] new_activity.descent = gpx_data['downhill']
@ -37,23 +39,26 @@ def create_activity(
new_activity.ave_speed = gpx_data['average_speed'] new_activity.ave_speed = gpx_data['average_speed']
else: else:
new_activity.moving = duration new_activity.moving = duration
new_activity.distance = activity_data.get('distance')
new_activity.ave_speed = new_activity.distance / ( new_activity.ave_speed = new_activity.distance / (
duration.seconds / 3600) duration.seconds / 3600)
new_activity.max_speed = new_activity.ave_speed new_activity.max_speed = new_activity.ave_speed
return new_activity return new_activity
def edit_activity_wo_gpx(activity, activity_data): def edit_activity(activity, activity_data):
activity.sport_id = activity_data.get('sport_id') activity.sport_id = activity_data.get('sport_id')
activity.activity_date = datetime.strptime( if not activity.gpx:
activity_data.get('activity_date'), '%Y-%m-%d %H:%M') if activity_data.get('activity_date'):
activity.duration = timedelta(seconds=activity_data.get('duration')) activity.activity_date = datetime.strptime(
activity.moving = activity.duration activity_data.get('activity_date'), '%Y-%m-%d %H:%M')
activity.distance = activity_data.get('distance') if activity_data.get('duration'):
activity.ave_speed = activity.distance / ( activity.duration = timedelta(seconds=activity_data.get('duration')) # noqa
activity.duration.seconds / 3600) activity.moving = activity.duration
activity.max_speed = activity.ave_speed if activity_data.get('distance'):
activity.distance = activity_data.get('distance')
activity.ave_speed = activity.distance / (
activity.duration.seconds / 3600)
activity.max_speed = activity.ave_speed
return activity return activity
@ -121,7 +126,7 @@ def get_file_path(auth_user_id, activity_file):
def get_new_file_path(auth_user_id, activity_date, activity_file, sport): def get_new_file_path(auth_user_id, activity_date, activity_file, sport):
old_filename = secure_filename(activity_file.filename) old_filename = secure_filename(activity_file.filename)
extension = '.{}'.format(old_filename.rsplit('.', 1)[1].lower()) extension = '.{}'.format(old_filename.rsplit('.', 1)[1].lower())
fi, new_filename = tempfile.mkstemp( _, new_filename = tempfile.mkstemp(
prefix='{}_{}_'.format(activity_date, sport), prefix='{}_{}_'.format(activity_date, sport),
suffix=extension suffix=extension
) )
@ -129,5 +134,5 @@ def get_new_file_path(auth_user_id, activity_date, activity_file, sport):
current_app.config['UPLOAD_FOLDER'], 'activities', str(auth_user_id)) current_app.config['UPLOAD_FOLDER'], 'activities', str(auth_user_id))
if not os.path.exists(dir_path): if not os.path.exists(dir_path):
os.makedirs(dir_path) os.makedirs(dir_path)
file_path = os.path.join(dir_path, new_filename.replace('/tmp/', '')) file_path = os.path.join(dir_path, new_filename.replace('/tmp/', '')) # noqa
return file_path return file_path

View File

@ -1,977 +0,0 @@
import datetime
import json
import os
from io import BytesIO
from mpwo_api.tests.utils import (
add_activity, add_sport, add_user, get_gpx_filepath
)
from mpwo_api.tests.utils_gpx import gpx_file
def test_get_all_activities_for_authenticated_user(app):
add_user('test', 'test@test.com', '12345678')
add_user('toto', 'toto@toto.com', '12345678')
add_sport('cycling')
add_sport('running')
add_activity(
1,
2,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
add_activity(
2,
1,
datetime.datetime.strptime('23/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=3600))
add_activity(
1,
1,
datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=6000))
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.get(
'/api/activities',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 2
assert 'creation_date' in data['data']['activities'][0]
assert 'Sun, 01 Apr 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 1 == data['data']['activities'][0]['sport_id']
assert '1:40:00' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['with_gpx'] is False
assert 'creation_date' in data['data']['activities'][1]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][1]['activity_date'] # noqa
assert 1 == data['data']['activities'][1]['user_id']
assert 2 == data['data']['activities'][1]['sport_id']
assert '0:17:04' == data['data']['activities'][1]['duration']
assert data['data']['activities'][1]['with_gpx'] is False
def test_get_activities_for_authenticated_user_no_activity(app):
add_user('test', 'test@test.com', '12345678')
add_user('toto', 'toto@toto.com', '12345678')
add_sport('cycling')
add_sport('running')
add_activity(
1,
2,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
add_activity(
1,
1,
datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=6000))
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(
email='toto@toto.com',
password='12345678'
)),
content_type='application/json'
)
response = client.get(
'/api/activities',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 0
def test_get_activities_for_authenticated_user_no_authentication(app):
client = app.test_client()
response = client.get('/api/activities')
data = json.loads(response.data.decode())
assert response.status_code == 403
assert 'error' in data['status']
assert 'Provide a valid auth token.' in data['message']
def test_get_activities_pagination(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
1,
1,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
add_activity(
1,
1,
datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=6000))
add_activity(
1,
1,
datetime.datetime.strptime('20/03/2017', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
add_activity(
1,
1,
datetime.datetime.strptime('09/05/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=3000))
add_activity(
1,
1,
datetime.datetime.strptime('01/06/2017', '%d/%m/%Y'),
datetime.timedelta(seconds=3456))
add_activity(
1,
1,
datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=600))
add_activity(
1,
1,
datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1000))
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.get(
'/api/activities',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 5
assert 'creation_date' in data['data']['activities'][0]
assert 'Wed, 09 May 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert '0:50:00' == data['data']['activities'][0]['duration']
assert 'creation_date' in data['data']['activities'][4]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][4]['activity_date'] # noqa
assert '0:17:04' == data['data']['activities'][4]['duration']
response = client.get(
'/api/activities?page=1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 5
assert 'creation_date' in data['data']['activities'][0]
assert 'Wed, 09 May 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert '0:50:00' == data['data']['activities'][0]['duration']
assert 'creation_date' in data['data']['activities'][4]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][4]['activity_date'] # noqa
assert '0:17:04' == data['data']['activities'][4]['duration']
response = client.get(
'/api/activities?page=2',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 2
assert 'creation_date' in data['data']['activities'][0]
assert 'Thu, 01 Jun 2017 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert '0:57:36' == data['data']['activities'][0]['duration']
assert 'creation_date' in data['data']['activities'][1]
assert 'Mon, 20 Mar 2017 00:00:00 GMT' == data['data']['activities'][1]['activity_date'] # noqa
assert '0:17:04' == data['data']['activities'][1]['duration']
response = client.get(
'/api/activities?page=3',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 0
def test_add_an_activity_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',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
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 'Tue, 13 Mar 2018 12:44:45 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 1 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None
assert data['data']['activities'][0]['with_gpx'] is True
def test_add_an_activity_gpx_invalid_file(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',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.png'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert data['status'] == 'fail'
assert data['message'] == 'File extension not allowed.'
def test_add_an_activity_gpx_no_sport_id(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',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
def test_add_an_activity_gpx_no_file(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',
data=dict(
data='{}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert data['status'] == 'fail'
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='2018-05-15 14:05',
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 14:05: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
assert data['data']['activities'][0]['with_gpx'] is False
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')
add_activity(
1,
1,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
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.get(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 1
assert 'creation_date' in data['data']['activities'][0]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 1 == data['data']['activities'][0]['sport_id']
assert '0:17:04' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] is None
assert data['data']['activities'][0]['ave_speed'] is None
assert data['data']['activities'][0]['descent'] is None
assert data['data']['activities'][0]['distance'] is None
assert data['data']['activities'][0]['max_alt'] is None
assert data['data']['activities'][0]['max_speed'] is None
assert data['data']['activities'][0]['min_alt'] is None
assert data['data']['activities'][0]['moving'] is None
assert data['data']['activities'][0]['pauses'] is None
assert data['data']['activities'][0]['with_gpx'] is False
def test_get_an_activity_with_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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.get(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 1
assert 'creation_date' in data['data']['activities'][0]
assert 'Tue, 13 Mar 2018 12:44:45 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 1 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None
assert data['data']['activities'][0]['with_gpx'] is True
def test_edit_an_activity_wo_gpx(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
1,
1,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
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.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
duration=3600,
activity_date='2018-05-15 14:05',
distance=10
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' 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 14:05: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
assert data['data']['activities'][0]['with_gpx'] is False
def test_edit_an_activity_with_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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
duration=3600,
activity_date='2018-05-15 14:05',
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 'error' in data['status']
assert ('You can not modify an activity with gpx file. '
'Please delete and re-import the gpx file.') in data['message']
def test_edit_an_activity_wo_gpx_invalid_payload(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
1,
1,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
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.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
activity_date='2018-05-15 14:05',
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_edit_an_activity_wo_gpx_incorrect_data(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
1,
1,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
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.patch(
'/api/activities/1',
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 'error' in data['status']
assert 'Error. Please try again or contact the administrator.' \
in data['message']
def test_edit_an_activity_no_activity(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.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
duration=3600,
activity_date='2018-05-15 14:05',
distance=10
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 404
assert 'not found' in data['status']
assert len(data['data']['activities']) == 0
def test_delete_an_activity_with_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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.delete(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
assert response.status_code == 204
def test_delete_an_activity_wo_gpx(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
1,
1,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024))
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.delete(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
assert response.status_code == 204
def test_delete_an_activity_no_activityy(app):
add_user('test', 'test@test.com', '12345678')
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.delete(
'/api/activities/9999',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 404
assert 'not found' in data['status']
def test_delete_an_activity_with_gpx_invalid_file(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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
gpx_filepath = get_gpx_filepath(1)
os.remove(gpx_filepath)
response = client.delete(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 500
assert 'error' in data['status']
assert 'Error. Please try again or contact the administrator.' \
in data['message']

View File

@ -0,0 +1,260 @@
import datetime
import json
from mpwo_api.tests.utils import add_activity, add_sport, add_user
def test_get_all_activities_for_authenticated_user(app):
add_user('test', 'test@test.com', '12345678')
add_user('toto', 'toto@toto.com', '12345678')
add_sport('cycling')
add_sport('running')
add_activity(
user_id=1,
sport_id=2,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
add_activity(
user_id=2,
sport_id=1,
activity_date=datetime.datetime.strptime('23/01/2018', '%d/%m/%Y'),
distance=15,
duration=datetime.timedelta(seconds=3600),
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'),
distance=12,
duration=datetime.timedelta(seconds=6000)
)
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.get(
'/api/activities',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 2
assert 'creation_date' in data['data']['activities'][0]
assert 'Sun, 01 Apr 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 1 == data['data']['activities'][0]['sport_id']
assert 12.0 == data['data']['activities'][0]['distance']
assert '1:40:00' == data['data']['activities'][0]['duration']
assert 'creation_date' in data['data']['activities'][1]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][1]['activity_date'] # noqa
assert 1 == data['data']['activities'][1]['user_id']
assert 2 == data['data']['activities'][1]['sport_id']
assert 10.0 == data['data']['activities'][1]['distance']
assert '0:17:04' == data['data']['activities'][1]['duration']
def test_get_activities_for_authenticated_user_no_activity(app):
add_user('test', 'test@test.com', '12345678')
add_user('toto', 'toto@toto.com', '12345678')
add_sport('cycling')
add_sport('running')
add_activity(
user_id=1,
sport_id=2,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'),
distance=12,
duration=datetime.timedelta(seconds=6000)
)
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(
email='toto@toto.com',
password='12345678'
)),
content_type='application/json'
)
response = client.get(
'/api/activities',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 0
def test_get_activities_for_authenticated_user_no_authentication(app):
client = app.test_client()
response = client.get('/api/activities')
data = json.loads(response.data.decode())
assert response.status_code == 403
assert 'error' in data['status']
assert 'Provide a valid auth token.' in data['message']
def test_get_activities_pagination(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'),
distance=8,
duration=datetime.timedelta(seconds=6000)
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('20/03/2017', '%d/%m/%Y'),
distance=5,
duration=datetime.timedelta(seconds=1024)
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('09/05/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=3000)
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/06/2017', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=3456)
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'),
distance=1,
duration=datetime.timedelta(seconds=600)
)
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1000)
)
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.get(
'/api/activities',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 5
assert 'creation_date' in data['data']['activities'][0]
assert 'Wed, 09 May 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert '0:50:00' == data['data']['activities'][0]['duration']
assert 'creation_date' in data['data']['activities'][4]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][4]['activity_date'] # noqa
assert '0:17:04' == data['data']['activities'][4]['duration']
response = client.get(
'/api/activities?page=1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 5
assert 'creation_date' in data['data']['activities'][0]
assert 'Wed, 09 May 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert '0:50:00' == data['data']['activities'][0]['duration']
assert 'creation_date' in data['data']['activities'][4]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][4]['activity_date'] # noqa
assert '0:17:04' == data['data']['activities'][4]['duration']
response = client.get(
'/api/activities?page=2',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 2
assert 'creation_date' in data['data']['activities'][0]
assert 'Thu, 01 Jun 2017 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert '0:57:36' == data['data']['activities'][0]['duration']
assert 'creation_date' in data['data']['activities'][1]
assert 'Mon, 20 Mar 2017 00:00:00 GMT' == data['data']['activities'][1]['activity_date'] # noqa
assert '0:17:04' == data['data']['activities'][1]['duration']
response = client.get(
'/api/activities?page=3',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 0

View File

@ -0,0 +1,419 @@
import json
from io import BytesIO
from mpwo_api.tests.utils import add_sport, add_user
from mpwo_api.tests.utils_gpx import gpx_file
def test_add_an_activity_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',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
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 'Tue, 13 Mar 2018 12:44:45 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 1 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None
assert data['data']['activities'][0]['with_gpx'] is True
def test_get_an_activity_with_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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.get(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 1
assert 'creation_date' in data['data']['activities'][0]
assert 'Tue, 13 Mar 2018 12:44:45 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 1 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None
assert data['data']['activities'][0]['with_gpx'] is True
def test_add_an_activity_gpx_invalid_file(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',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.png'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert data['status'] == 'fail'
assert data['message'] == 'File extension not allowed.'
def test_add_an_activity_gpx_no_sport_id(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',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
def test_add_an_activity_gpx_incorrect_sport_id(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',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 2}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 500
assert data['status'] == 'error'
assert data['message'] == \
'Error during activity file save.'
def test_add_an_activity_gpx_no_file(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',
data=dict(
data='{}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert data['status'] == 'fail'
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='2018-05-15 14:05',
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 14:05: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
assert data['data']['activities'][0]['with_gpx'] is False
def test_get_an_activity_wo_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'
)
client.post(
'/api/activities/no_gpx',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
duration=3600,
activity_date='2018-05-15 14:05',
distance=10
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.get(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' 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 14:05: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
assert data['data']['activities'][0]['with_gpx'] is False
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']

View File

@ -0,0 +1,392 @@
import datetime
import json
from io import BytesIO
from mpwo_api.tests.utils import add_activity, add_sport, add_user
from mpwo_api.tests.utils_gpx import gpx_file
def test_edit_an_activity_with_gpx(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_sport('running')
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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=2,
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 1
assert 'creation_date' in data['data']['activities'][0]
assert 'Tue, 13 Mar 2018 12:44:45 GMT' == data['data']['activities'][0]['activity_date'] # noqa
assert 1 == data['data']['activities'][0]['user_id']
assert 2 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None
assert data['data']['activities'][0]['with_gpx'] is True
def test_edit_an_activity_with_gpx_invalid_payload(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_sport('running')
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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict()),
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_edit_an_activity_with_gpx_incorrect_data(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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=2,
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 500
assert 'error' in data['status']
assert 'Error. Please try again or contact the administrator.' in data['message'] # noqa
def test_edit_an_activity_wo_gpx(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
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.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
duration=3600,
activity_date='2018-05-15 14:05',
distance=10
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' 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 14:05: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
assert data['data']['activities'][0]['with_gpx'] is False
def test_edit_an_activity_wo_gpx_partial(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
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.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
distance=10
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['activities']) == 1
assert 'creation_date' in data['data']['activities'][0]
assert data['data']['activities'][0]['activity_date'] == 'Mon, 01 Jan 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'] == '0:17:04'
assert data['data']['activities'][0]['ascent'] is None
assert data['data']['activities'][0]['ave_speed'] == 35.16
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'] == 35.16
assert data['data']['activities'][0]['min_alt'] is None
assert data['data']['activities'][0]['moving'] is None # no calculate
assert data['data']['activities'][0]['pauses'] is None
assert data['data']['activities'][0]['with_gpx'] is False
def test_edit_an_activity_wo_gpx_invalid_payload(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
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.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict()),
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_edit_an_activity_wo_gpx_incorrect_data(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
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.patch(
'/api/activities/1',
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 'error' in data['status']
assert 'Error. Please try again or contact the administrator.' \
in data['message']
def test_edit_an_activity_no_activity(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.patch(
'/api/activities/1',
content_type='application/json',
data=json.dumps(dict(
sport_id=1,
duration=3600,
activity_date='2018-05-15 14:05',
distance=10
)),
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 404
assert 'not found' in data['status']
assert len(data['data']['activities']) == 0

View File

@ -0,0 +1,153 @@
import datetime
import json
import os
from io import BytesIO
from mpwo_api.tests.utils import (
add_activity, add_sport, add_user, get_gpx_filepath
)
from mpwo_api.tests.utils_gpx import gpx_file
def test_delete_an_activity_with_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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
response = client.delete(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
assert response.status_code == 204
def test_delete_an_activity_wo_gpx(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10,
duration=datetime.timedelta(seconds=1024)
)
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.delete(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
assert response.status_code == 204
def test_delete_an_activity_no_activityy(app):
add_user('test', 'test@test.com', '12345678')
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.delete(
'/api/activities/9999',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 404
assert 'not found' in data['status']
def test_delete_an_activity_with_gpx_invalid_file(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'
)
client.post(
'/api/activities',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
gpx_filepath = get_gpx_filepath(1)
os.remove(gpx_filepath)
response = client.delete(
'/api/activities/1',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
assert response.status_code == 500
assert 'error' in data['status']
assert 'Error. Please try again or contact the administrator.' \
in data['message']

View File

@ -256,10 +256,11 @@ def test_delete_a_sport_with_an_activity(app):
add_admin() add_admin()
add_sport('cycling') add_sport('cycling')
add_activity( add_activity(
1, user_id=1,
1, sport_id=1,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'), activity_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024) distance=10,
duration=datetime.timedelta(seconds=1024)
) )
client = app.test_client() client = app.test_client()

View File

@ -43,11 +43,12 @@ def add_sport(label):
return sport return sport
def add_activity(user_id, sport_id, activity_date, duration): def add_activity(user_id, sport_id, activity_date, distance, duration):
activity = Activity( activity = Activity(
user_id=user_id, user_id=user_id,
sport_id=sport_id, sport_id=sport_id,
activity_date=activity_date, activity_date=activity_date,
distance=distance,
duration=duration) duration=duration)
db.session.add(activity) db.session.add(activity)
db.session.commit() db.session.commit()

View File

@ -1,3 +1,5 @@
import shutil
from mpwo_api import create_app, db from mpwo_api import create_app, db
from mpwo_api.activities.models import Sport from mpwo_api.activities.models import Sport
from mpwo_api.users.models import User from mpwo_api.users.models import User
@ -12,6 +14,8 @@ def drop_db():
db.drop_all() db.drop_all()
db.session.commit() db.session.commit()
print('Database dropped.') print('Database dropped.')
shutil.rmtree(app.config['UPLOAD_FOLDER'], ignore_errors=True)
print('Uploaded files deleted.')
@app.cli.command() @app.cli.command()

View File

@ -46,13 +46,9 @@ export default class ActivityAddEdit extends React.Component {
<div className="card-body"> <div className="card-body">
{activity ? ( {activity ? (
activity.with_gpx ? ( activity.with_gpx ? (
'You can\'t modify this activity.' + <FormWithGpx activity={activity} sports={sports} />
' Please delete and re-import gpx file.'
) : ( ) : (
<FormWithoutGpx <FormWithoutGpx activity={activity} sports={sports} />
activity={activity}
sports={sports}
/>
) )
) : ( ) : (
<div> <div>

View File

@ -54,14 +54,12 @@ class ActivityDisplay extends React.Component {
{sports.filter(sport => sport.id === activity.sport_id) {sports.filter(sport => sport.id === activity.sport_id)
.map(sport => sport.label)} -{' '} .map(sport => sport.label)} -{' '}
{activity.activity_date}{' '} {activity.activity_date}{' '}
{!activity.with_gpx && ( <Link
<Link className="unlink"
className="unlink" to={`/activities/${activity.id}/edit`}
to={`/activities/${activity.id}/edit`} >
> <i className="fa fa-edit custom-fa" aria-hidden="true" />
<i className="fa fa-edit custom-fa" aria-hidden="true" /> </Link>
</Link>
)}
<i <i
className="fa fa-trash custom-fa" className="fa fa-trash custom-fa"
aria-hidden="true" aria-hidden="true"

View File

@ -1,12 +1,13 @@
import React from 'react' import React from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { addActivity } from '../../../actions/activities' import { addActivity, editActivity } from '../../../actions/activities'
import { history } from '../../../index' import { history } from '../../../index'
function FormWithGpx (props) { function FormWithGpx (props) {
const { onAddSport, sports } = props const { activity, onAddActivity, onEditActivity, sports } = props
const sportId = activity ? activity.sport_id : ''
return ( return (
<form <form
encType="multipart/form-data" encType="multipart/form-data"
@ -18,6 +19,7 @@ function FormWithGpx (props) {
Sport: Sport:
<select <select
className="form-control input-lg" className="form-control input-lg"
defaultValue={sportId}
name="sport" name="sport"
required required
> >
@ -30,22 +32,28 @@ function FormWithGpx (props) {
</select> </select>
</label> </label>
</div> </div>
<div className="form-group"> {!activity && (
<label> <div className="form-group">
GPX file: <label>
<input GPX file:
accept=".gpx" <input
className="form-control input-lg" accept=".gpx"
name="gpxFile" className="form-control input-lg"
required name="gpxFile"
type="file" required
/> type="file"
</label> />
</div> </label>
</div>
)}
<input <input
type="submit" type="submit"
className="btn btn-primary btn-lg btn-block" className="btn btn-primary btn-lg btn-block"
onClick={event => onAddSport(event)} onClick={
event => activity
? onEditActivity(event, activity)
: onAddActivity(event)
}
value="Submit" value="Submit"
/> />
<input <input
@ -61,13 +69,19 @@ function FormWithGpx (props) {
export default connect( export default connect(
() => ({ }), () => ({ }),
dispatch => ({ dispatch => ({
onAddSport: event => { onAddActivity: e => {
const form = new FormData() const form = new FormData()
form.append('file', event.target.form.gpxFile.files[0]) form.append('file', e.target.form.gpxFile.files[0])
form.append( form.append(
'data', `{"sport_id": ${event.target.form.sport.value}}` 'data', `{"sport_id": ${e.target.form.sport.value}}`
) )
dispatch(addActivity(form)) dispatch(addActivity(form))
}, },
onEditActivity: (e, activity) => {
dispatch(editActivity({
id: activity.id,
sport_id: +e.target.form.sport.value
}))
},
}) })
)(FormWithGpx) )(FormWithGpx)