API: add notes to activities - #10
This commit is contained in:
parent
0729f3d074
commit
47fc2ab830
@ -123,6 +123,7 @@ class Activity(db.Model):
|
|||||||
map_id = db.Column(db.String(50), nullable=True)
|
map_id = db.Column(db.String(50), nullable=True)
|
||||||
weather_start = db.Column(JSON, nullable=True)
|
weather_start = db.Column(JSON, nullable=True)
|
||||||
weather_end = db.Column(JSON, nullable=True)
|
weather_end = db.Column(JSON, nullable=True)
|
||||||
|
notes = db.Column(db.String(500), nullable=True)
|
||||||
segments = db.relationship('ActivitySegment',
|
segments = db.relationship('ActivitySegment',
|
||||||
lazy=True,
|
lazy=True,
|
||||||
cascade='all, delete',
|
cascade='all, delete',
|
||||||
@ -238,7 +239,8 @@ class Activity(db.Model):
|
|||||||
"records": [record.serialize() for record in self.records],
|
"records": [record.serialize() for record in self.records],
|
||||||
"map": self.map_id if self.map else None,
|
"map": self.map_id if self.map else None,
|
||||||
"weather_start": self.weather_start,
|
"weather_start": self.weather_start,
|
||||||
"weather_end": self.weather_end
|
"weather_end": self.weather_end,
|
||||||
|
"notes": self.notes
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -73,6 +73,7 @@ def create_activity(
|
|||||||
distance=distance,
|
distance=distance,
|
||||||
duration=duration
|
duration=duration
|
||||||
)
|
)
|
||||||
|
new_activity.notes = activity_data.get('notes')
|
||||||
|
|
||||||
if title is not None and title != '':
|
if title is not None and title != '':
|
||||||
new_activity.title = title
|
new_activity.title = title
|
||||||
@ -116,6 +117,8 @@ def edit_activity(activity, activity_data, auth_user_id):
|
|||||||
activity.sport_id = activity_data.get('sport_id')
|
activity.sport_id = activity_data.get('sport_id')
|
||||||
if activity_data.get('title'):
|
if activity_data.get('title'):
|
||||||
activity.title = activity_data.get('title')
|
activity.title = activity_data.get('title')
|
||||||
|
if activity_data.get('notes'):
|
||||||
|
activity.notes = activity_data.get('notes')
|
||||||
if not activity.gpx:
|
if not activity.gpx:
|
||||||
if activity_data.get('activity_date'):
|
if activity_data.get('activity_date'):
|
||||||
activity_date = datetime.strptime(
|
activity_date = datetime.strptime(
|
||||||
|
@ -23,6 +23,9 @@ def assert_activity_data_with_gpx(data):
|
|||||||
assert data['data']['activities'][0]['pauses'] is None
|
assert data['data']['activities'][0]['pauses'] is None
|
||||||
assert data['data']['activities'][0]['with_gpx'] is True
|
assert data['data']['activities'][0]['with_gpx'] is True
|
||||||
assert data['data']['activities'][0]['map'] is not None
|
assert data['data']['activities'][0]['map'] is not None
|
||||||
|
assert data['data']['activities'][0]['weather_start'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_end'] is None
|
||||||
|
assert data['data']['activities'][0]['notes'] is None
|
||||||
assert len(data['data']['activities'][0]['segments']) == 1
|
assert len(data['data']['activities'][0]['segments']) == 1
|
||||||
|
|
||||||
segment = data['data']['activities'][0]['segments'][0]
|
segment = data['data']['activities'][0]['segments'][0]
|
||||||
@ -81,6 +84,9 @@ def assert_activity_data_wo_gpx(data):
|
|||||||
assert data['data']['activities'][0]['pauses'] is None
|
assert data['data']['activities'][0]['pauses'] is None
|
||||||
assert data['data']['activities'][0]['with_gpx'] is False
|
assert data['data']['activities'][0]['with_gpx'] is False
|
||||||
assert data['data']['activities'][0]['map'] is None
|
assert data['data']['activities'][0]['map'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_start'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_end'] is None
|
||||||
|
assert data['data']['activities'][0]['notes'] is None
|
||||||
|
|
||||||
assert len(data['data']['activities'][0]['segments']) == 0
|
assert len(data['data']['activities'][0]['segments']) == 0
|
||||||
|
|
||||||
@ -305,6 +311,48 @@ def test_add_an_activity_with_gpx_without_name(
|
|||||||
assert_activity_data_with_gpx(data)
|
assert_activity_data_with_gpx(data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_an_activity_with_gpx_notes(
|
||||||
|
app, user_1, sport_1_cycling, gpx_file
|
||||||
|
):
|
||||||
|
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, "notes": "test activity"}'
|
||||||
|
),
|
||||||
|
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 'just an activity' == data['data']['activities'][0]['title']
|
||||||
|
assert 'test activity' == data['data']['activities'][0]['notes']
|
||||||
|
|
||||||
|
|
||||||
def test_add_an_activity_with_gpx_invalid_file(
|
def test_add_an_activity_with_gpx_invalid_file(
|
||||||
app, user_1, sport_1_cycling, gpx_file_wo_track
|
app, user_1, sport_1_cycling, gpx_file_wo_track
|
||||||
):
|
):
|
||||||
@ -570,6 +618,48 @@ def test_get_an_activity_wo_gpx(app, user_1, sport_1_cycling):
|
|||||||
assert_activity_data_wo_gpx(data)
|
assert_activity_data_wo_gpx(data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_an_activity_wo_gpx_notes(app, user_1, sport_1_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,
|
||||||
|
notes="new test with notes"
|
||||||
|
)),
|
||||||
|
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 'new test with notes' == data['data']['activities'][0]['notes']
|
||||||
|
|
||||||
|
|
||||||
def test_get_an_activity_wo_gpx_with_timezone(app, user_1, sport_1_cycling):
|
def test_get_an_activity_wo_gpx_with_timezone(app, user_1, sport_1_cycling):
|
||||||
user_1.timezone = 'Europe/Paris'
|
user_1.timezone = 'Europe/Paris'
|
||||||
client = app.test_client()
|
client = app.test_client()
|
||||||
|
@ -89,6 +89,26 @@ def test_edit_an_activity_with_gpx(
|
|||||||
assert data['data']['activities'][0]['title'] == 'Activity test'
|
assert data['data']['activities'][0]['title'] == 'Activity test'
|
||||||
assert_activity_data_with_gpx(data)
|
assert_activity_data_with_gpx(data)
|
||||||
|
|
||||||
|
response = client.patch(
|
||||||
|
'/api/activities/1',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
notes="test notes"
|
||||||
|
)),
|
||||||
|
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 data['data']['activities'][0]['title'] == 'Activity test'
|
||||||
|
assert data['data']['activities'][0]['notes'] == 'test notes'
|
||||||
|
|
||||||
|
|
||||||
def test_edit_an_activity_with_gpx_partial(
|
def test_edit_an_activity_with_gpx_partial(
|
||||||
app, user_1, sport_1_cycling, sport_2_running, gpx_file
|
app, user_1, sport_1_cycling, sport_2_running, gpx_file
|
||||||
@ -276,6 +296,10 @@ def test_edit_an_activity_wo_gpx(
|
|||||||
assert data['data']['activities'][0]['moving'] == '1:00:00'
|
assert data['data']['activities'][0]['moving'] == '1:00:00'
|
||||||
assert data['data']['activities'][0]['pauses'] is None
|
assert data['data']['activities'][0]['pauses'] is None
|
||||||
assert data['data']['activities'][0]['with_gpx'] is False
|
assert data['data']['activities'][0]['with_gpx'] is False
|
||||||
|
assert data['data']['activities'][0]['map'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_start'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_end'] is None
|
||||||
|
assert data['data']['activities'][0]['notes'] is None
|
||||||
|
|
||||||
records = data['data']['activities'][0]['records']
|
records = data['data']['activities'][0]['records']
|
||||||
assert len(records) == 4
|
assert len(records) == 4
|
||||||
@ -337,6 +361,71 @@ def test_edit_an_activity_wo_gpx(
|
|||||||
assert data['data']['activities'][0]['moving'] == '1:00:00'
|
assert data['data']['activities'][0]['moving'] == '1:00:00'
|
||||||
assert data['data']['activities'][0]['pauses'] is None
|
assert data['data']['activities'][0]['pauses'] is None
|
||||||
assert data['data']['activities'][0]['with_gpx'] is False
|
assert data['data']['activities'][0]['with_gpx'] is False
|
||||||
|
assert data['data']['activities'][0]['map'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_start'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_end'] is None
|
||||||
|
assert data['data']['activities'][0]['notes'] is None
|
||||||
|
|
||||||
|
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 15: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 15: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 15: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 15:05:00 GMT'
|
||||||
|
assert records[3]['value'] == 8.0
|
||||||
|
|
||||||
|
response = client.patch(
|
||||||
|
'/api/activities/1',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
notes='test notes'
|
||||||
|
)),
|
||||||
|
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 15:05:00 GMT' # noqa
|
||||||
|
assert data['data']['activities'][0]['user_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'
|
||||||
|
assert data['data']['activities'][0]['ascent'] is None
|
||||||
|
assert data['data']['activities'][0]['ave_speed'] == 8.0
|
||||||
|
assert data['data']['activities'][0]['descent'] is None
|
||||||
|
assert data['data']['activities'][0]['distance'] == 8.0
|
||||||
|
assert data['data']['activities'][0]['max_alt'] is None
|
||||||
|
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
|
||||||
|
assert data['data']['activities'][0]['map'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_start'] is None
|
||||||
|
assert data['data']['activities'][0]['weather_end'] is None
|
||||||
|
assert data['data']['activities'][0]['notes'] == 'test notes'
|
||||||
|
|
||||||
records = data['data']['activities'][0]['records']
|
records = data['data']['activities'][0]['records']
|
||||||
assert len(records) == 4
|
assert len(records) == 4
|
||||||
|
@ -40,6 +40,7 @@ def test_add_activity(
|
|||||||
assert serialized_activity['map'] is None
|
assert serialized_activity['map'] is None
|
||||||
assert serialized_activity['weather_start'] is None
|
assert serialized_activity['weather_start'] is None
|
||||||
assert serialized_activity['weather_end'] is None
|
assert serialized_activity['weather_end'] is None
|
||||||
|
assert serialized_activity['notes'] is None
|
||||||
|
|
||||||
|
|
||||||
def test_add_segment(
|
def test_add_segment(
|
||||||
|
28
fittrackee_api/migrations/versions/096dd0b43beb_.py
Normal file
28
fittrackee_api/migrations/versions/096dd0b43beb_.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 096dd0b43beb
|
||||||
|
Revises: 71093ac9ca44
|
||||||
|
Create Date: 2018-06-13 17:56:20.359884
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '096dd0b43beb'
|
||||||
|
down_revision = '71093ac9ca44'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('activities', sa.Column('notes', sa.String(length=500), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('activities', 'notes')
|
||||||
|
# ### end Alembic commands ###
|
Loading…
x
Reference in New Issue
Block a user