diff --git a/mpwo_api/mpwo_api/activities/models.py b/mpwo_api/mpwo_api/activities/models.py index 052cb06f..d7082ef2 100644 --- a/mpwo_api/mpwo_api/activities/models.py +++ b/mpwo_api/mpwo_api/activities/models.py @@ -3,7 +3,7 @@ import datetime from mpwo_api import db from sqlalchemy.dialects import postgresql from sqlalchemy.event import listens_for -from sqlalchemy.ext.hybrid import Comparator, hybrid_property +from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm.session import object_session from sqlalchemy.types import Enum @@ -40,9 +40,9 @@ def update_records(activity, sport_id, connection, session): for record_type, record_data in new_records.items(): if record_data['record_value']: record = Record.query.filter_by( - user_id=activity.user_id, - sport_id=activity.sport_id, - record_type=record_type, + user_id=activity.user_id, + sport_id=activity.sport_id, + record_type=record_type, ).first() if record: value = convert_value_to_integer( @@ -61,6 +61,14 @@ def update_records(activity, sport_id, connection, session): ) new_record.value = record_data['record_value'] session.add(new_record) + else: + connection.execute(record_table.delete().where( + record_table.c.user_id == activity.user_id, + ).where( + record_table.c.sport_id == sport_id, + ).where( + record_table.c.record_type == record_type, + )) class Sport(db.Model): @@ -167,7 +175,8 @@ class Activity(db.Model): "ave_speed": float(self.ave_speed) if self.ave_speed else None, "with_gpx": self.gpx is not None, "bounds": [float(bound) for bound in self.bounds] if self.bounds else [], # noqa - "segments": [segment.serialize() for segment in self.segments] + "segments": [segment.serialize() for segment in self.segments], + "records": [record.serialize() for record in self.records] } @classmethod @@ -206,16 +215,15 @@ def on_activity_insert(mapper, connection, activity): @listens_for(Activity, 'after_update') def on_activity_update(mapper, connection, activity): if object_session(activity).is_modified(activity, include_collections=True): # noqa - sports_list = [] - records = Record.query.filter_by( - activity_id=activity.id, - ).all() - for rec in records: - if rec.sport_id not in sports_list: - sports_list.append(rec.sport_id) - @listens_for(db.Session, 'after_flush', once=True) def receive_after_flush(session, context): + sports_list = [activity.sport_id] + records = Record.query.filter_by( + activity_id=activity.id, + ).all() + for rec in records: + if rec.sport_id not in sports_list: + sports_list.append(rec.sport_id) for sport_id in sports_list: update_records(activity, sport_id, connection, session) @@ -265,13 +273,6 @@ class ActivitySegment(db.Model): } -class ValueComparator(Comparator): - def operate(self, op, other): - if isinstance(other, datetime.timedelta): - other = convert_timedelta_to_integer(other) - return op(self.__clause_element__(), other) - - class Record(db.Model): __tablename__ = "records" __table_args__ = (db.UniqueConstraint( @@ -314,7 +315,6 @@ class Record(db.Model): def value(self): if self._value is None: return None - if self.record_type == 'LD': return datetime.timedelta(seconds=self._value) elif self.record_type in ['AS', 'MS']: @@ -326,10 +326,6 @@ class Record(db.Model): def value(self, val): self._value = convert_value_to_integer(self.record_type, val) - @value.comparator - def value(cls): - return ValueComparator(cls._value) - def serialize(self): if self.value is None: value = None diff --git a/mpwo_api/mpwo_api/tests/test_activities_api_1_post.py b/mpwo_api/mpwo_api/tests/test_activities_api_1_post.py index 9acd3ec8..b59f586a 100644 --- a/mpwo_api/mpwo_api/tests/test_activities_api_1_post.py +++ b/mpwo_api/mpwo_api/tests/test_activities_api_1_post.py @@ -34,6 +34,29 @@ def assert_activity_data_with_gpx(data): assert segment['moving'] == '0:04:10' assert segment['pauses'] is None + records = data['data']['activities'][0]['records'] + assert len(records) == 4 + assert records[0]['sport_id'] == 1 + assert records[0]['activity_id'] == 1 + assert records[0]['record_type'] == 'MS' + assert records[0]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[0]['value'] == 5.09 + assert records[1]['sport_id'] == 1 + assert records[1]['activity_id'] == 1 + assert records[1]['record_type'] == 'LD' + assert records[1]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[1]['value'] == '0:04:10' + assert records[2]['sport_id'] == 1 + assert records[2]['activity_id'] == 1 + assert records[2]['record_type'] == 'FD' + assert records[2]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[2]['value'] == 0.32 + assert records[3]['sport_id'] == 1 + assert records[3]['activity_id'] == 1 + assert records[3]['record_type'] == 'AS' + assert records[3]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[3]['value'] == 4.6 + def assert_activity_data_wo_gpx(data): assert 'creation_date' in data['data']['activities'][0] @@ -53,6 +76,31 @@ def assert_activity_data_wo_gpx(data): assert data['data']['activities'][0]['pauses'] is None assert data['data']['activities'][0]['with_gpx'] is False + assert len(data['data']['activities'][0]['segments']) == 0 + + records = data['data']['activities'][0]['records'] + assert len(records) == 4 + assert records[0]['sport_id'] == 1 + assert records[0]['activity_id'] == 1 + assert records[0]['record_type'] == 'MS' + assert records[0]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[0]['value'] == 10.0 + assert records[1]['sport_id'] == 1 + assert records[1]['activity_id'] == 1 + assert records[1]['record_type'] == 'LD' + assert records[1]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[1]['value'] == '1:00:00' + assert records[2]['sport_id'] == 1 + assert records[2]['activity_id'] == 1 + assert records[2]['record_type'] == 'FD' + assert records[2]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[2]['value'] == 10.0 + assert records[3]['sport_id'] == 1 + assert records[3]['activity_id'] == 1 + assert records[3]['record_type'] == 'AS' + assert records[3]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[3]['value'] == 10.0 + def test_add_an_activity_gpx(app, user_1, sport_1_cycling, gpx_file): client = app.test_client() diff --git a/mpwo_api/mpwo_api/tests/test_activities_api_2_patch.py b/mpwo_api/mpwo_api/tests/test_activities_api_2_patch.py index b02d56ba..10039548 100644 --- a/mpwo_api/mpwo_api/tests/test_activities_api_2_patch.py +++ b/mpwo_api/mpwo_api/tests/test_activities_api_2_patch.py @@ -18,6 +18,29 @@ def assert_activity_data_with_gpx(data): assert data['data']['activities'][0]['pauses'] is None assert data['data']['activities'][0]['with_gpx'] is True + records = data['data']['activities'][0]['records'] + assert len(records) == 4 + assert records[0]['sport_id'] == 2 + assert records[0]['activity_id'] == 1 + assert records[0]['record_type'] == 'MS' + assert records[0]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[0]['value'] == 5.09 + assert records[1]['sport_id'] == 2 + assert records[1]['activity_id'] == 1 + assert records[1]['record_type'] == 'LD' + assert records[1]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[1]['value'] == '0:04:10' + assert records[2]['sport_id'] == 2 + assert records[2]['activity_id'] == 1 + assert records[2]['record_type'] == 'FD' + assert records[2]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[2]['value'] == 0.32 + assert records[3]['sport_id'] == 2 + assert records[3]['activity_id'] == 1 + assert records[3]['record_type'] == 'AS' + assert records[3]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[3]['value'] == 4.6 + def test_edit_an_activity_with_gpx( app, user_1, sport_1_cycling, sport_2_running, gpx_file @@ -203,10 +226,8 @@ def test_edit_an_activity_with_gpx_incorrect_data( def test_edit_an_activity_wo_gpx( - app, user_1, sport_1_cycling, activity_cycling_user_1 + app, user_1, sport_1_cycling, sport_2_running ): - activity_cycling_user_1.title = 'cycling - 2018-01-01 00:00:00' - client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -216,14 +237,77 @@ def test_edit_an_activity_wo_gpx( )), content_type='application/json' ) - response = client.patch( - '/api/activities/1', + + response = client.post( + '/api/activities/no_gpx', content_type='application/json', data=json.dumps(dict( sport_id=1, duration=3600, + activity_date='2018-05-14 14:05', + distance=7, + title='Activity test' + )), + 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'] == 'Mon, 14 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]['title'] == 'Activity test' # noqa + assert data['data']['activities'][0]['ascent'] is None + assert data['data']['activities'][0]['ave_speed'] == 7.0 + assert data['data']['activities'][0]['descent'] is None + assert data['data']['activities'][0]['distance'] == 7.0 + assert data['data']['activities'][0]['max_alt'] is None + assert data['data']['activities'][0]['max_speed'] == 7.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 + + records = data['data']['activities'][0]['records'] + assert len(records) == 4 + assert records[0]['sport_id'] == 1 + assert records[0]['activity_id'] == 1 + assert records[0]['record_type'] == 'MS' + assert records[0]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[0]['value'] == 7.0 + assert records[1]['sport_id'] == 1 + assert records[1]['activity_id'] == 1 + assert records[1]['record_type'] == 'LD' + assert records[1]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[1]['value'] == '1:00:00' + assert records[2]['sport_id'] == 1 + assert records[2]['activity_id'] == 1 + assert records[2]['record_type'] == 'FD' + assert records[2]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[2]['value'] == 7.0 + assert records[3]['sport_id'] == 1 + assert records[3]['activity_id'] == 1 + assert records[3]['record_type'] == 'AS' + assert records[3]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[3]['value'] == 7.0 + + response = client.patch( + '/api/activities/1', + content_type='application/json', + data=json.dumps(dict( + sport_id=2, + duration=3600, activity_date='2018-05-15 14:05', - distance=10, + distance=8, title='Activity test' )), headers=dict( @@ -240,26 +324,47 @@ def test_edit_an_activity_wo_gpx( 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]['sport_id'] == 2 assert data['data']['activities'][0]['duration'] == '1:00:00' - assert data['data']['activities'][0]['title'] == 'Activity test' # noqa + assert data['data']['activities'][0]['title'] == 'Activity test' assert data['data']['activities'][0]['ascent'] is None - assert data['data']['activities'][0]['ave_speed'] == 10.0 + assert data['data']['activities'][0]['ave_speed'] == 8.0 assert data['data']['activities'][0]['descent'] is None - assert data['data']['activities'][0]['distance'] == 10.0 + assert data['data']['activities'][0]['distance'] == 8.0 assert data['data']['activities'][0]['max_alt'] is None - assert data['data']['activities'][0]['max_speed'] == 10.0 + assert data['data']['activities'][0]['max_speed'] == 8.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 + records = data['data']['activities'][0]['records'] + assert len(records) == 4 + assert records[0]['sport_id'] == 2 + assert records[0]['activity_id'] == 1 + assert records[0]['record_type'] == 'MS' + assert records[0]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[0]['value'] == 8.0 + assert records[1]['sport_id'] == 2 + assert records[1]['activity_id'] == 1 + assert records[1]['record_type'] == 'LD' + assert records[1]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[1]['value'] == '1:00:00' + assert records[2]['sport_id'] == 2 + assert records[2]['activity_id'] == 1 + assert records[2]['record_type'] == 'FD' + assert records[2]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[2]['value'] == 8.0 + assert records[3]['sport_id'] == 2 + assert records[3]['activity_id'] == 1 + assert records[3]['record_type'] == 'AS' + assert records[3]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[3]['value'] == 8.0 + def test_edit_an_activity_wo_gpx_partial( - app, user_1, sport_1_cycling, activity_cycling_user_1 + app, user_1, sport_1_cycling ): - activity_cycling_user_1.title = 'cycling - 2018-01-01 00:00:00' - client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -269,6 +374,68 @@ def test_edit_an_activity_wo_gpx_partial( )), 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-14 14:05', + distance=7 + )), + 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'] == 'Mon, 14 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]['title'] == 'Cycling - 2018-05-14 14:05:00' # noqa + assert data['data']['activities'][0]['ascent'] is None + assert data['data']['activities'][0]['ave_speed'] == 7.0 + assert data['data']['activities'][0]['descent'] is None + assert data['data']['activities'][0]['distance'] == 7.0 + assert data['data']['activities'][0]['max_alt'] is None + assert data['data']['activities'][0]['max_speed'] == 7.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 + + records = data['data']['activities'][0]['records'] + assert len(records) == 4 + assert records[0]['sport_id'] == 1 + assert records[0]['activity_id'] == 1 + assert records[0]['record_type'] == 'MS' + assert records[0]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[0]['value'] == 7.0 + assert records[1]['sport_id'] == 1 + assert records[1]['activity_id'] == 1 + assert records[1]['record_type'] == 'LD' + assert records[1]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[1]['value'] == '1:00:00' + assert records[2]['sport_id'] == 1 + assert records[2]['activity_id'] == 1 + assert records[2]['record_type'] == 'FD' + assert records[2]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[2]['value'] == 7.0 + assert records[3]['sport_id'] == 1 + assert records[3]['activity_id'] == 1 + assert records[3]['record_type'] == 'AS' + assert records[3]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[3]['value'] == 7.0 + response = client.patch( '/api/activities/1', content_type='application/json', @@ -289,22 +456,45 @@ def test_edit_an_activity_wo_gpx_partial( 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]['activity_date'] == 'Mon, 14 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'] == '0:17:04' - assert data['data']['activities'][0]['title'] == 'cycling - 2018-01-01 00:00:00' # noqa + assert data['data']['activities'][0]['duration'] == '1:00:00' + assert data['data']['activities'][0]['title'] == 'Cycling - 2018-05-14 14:05:00' # noqa assert data['data']['activities'][0]['ascent'] is None - assert data['data']['activities'][0]['ave_speed'] == 35.16 + 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'] == 35.16 + assert data['data']['activities'][0]['max_speed'] == 10.0 assert data['data']['activities'][0]['min_alt'] is None - assert data['data']['activities'][0]['moving'] is None # no calculated + 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 + records = data['data']['activities'][0]['records'] + assert len(records) == 4 + assert records[0]['sport_id'] == 1 + assert records[0]['activity_id'] == 1 + assert records[0]['record_type'] == 'MS' + assert records[0]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[0]['value'] == 10.0 + assert records[1]['sport_id'] == 1 + assert records[1]['activity_id'] == 1 + assert records[1]['record_type'] == 'LD' + assert records[1]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[1]['value'] == '1:00:00' + assert records[2]['sport_id'] == 1 + assert records[2]['activity_id'] == 1 + assert records[2]['record_type'] == 'FD' + assert records[2]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[2]['value'] == 10.0 + assert records[3]['sport_id'] == 1 + assert records[3]['activity_id'] == 1 + assert records[3]['record_type'] == 'AS' + assert records[3]['activity_date'] == 'Mon, 14 May 2018 14:05:00 GMT' + assert records[3]['value'] == 10.0 + def test_edit_an_activity_wo_gpx_invalid_payload( app, user_1, sport_1_cycling, activity_cycling_user_1