From 462a193d2e955f10fc633b25586b176b4d3f67fe Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Thu, 24 Mar 2022 12:17:44 -0400 Subject: [PATCH 01/17] Added ascent record to Dashboard --- .../23_cd0e6cf83207_add_ascent_record.py | 35 +++++++++++++++++++ fittrackee/workouts/models.py | 6 ++-- .../src/locales/en/workouts.json | 1 + .../src/locales/fr/workouts.json | 1 + fittrackee_client/src/utils/records.ts | 25 ++++++++----- 5 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 fittrackee/migrations/versions/23_cd0e6cf83207_add_ascent_record.py diff --git a/fittrackee/migrations/versions/23_cd0e6cf83207_add_ascent_record.py b/fittrackee/migrations/versions/23_cd0e6cf83207_add_ascent_record.py new file mode 100644 index 00000000..aef966c1 --- /dev/null +++ b/fittrackee/migrations/versions/23_cd0e6cf83207_add_ascent_record.py @@ -0,0 +1,35 @@ +"""add ascent record + +Revision ID: cd0e6cf83207 +Revises: e30007d681cb +Create Date: 2022-03-22 20:21:13.661883 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'cd0e6cf83207' +down_revision = 'e30007d681cb' +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute( + """ + ALTER TYPE record_types ADD VALUE 'HA'; + """ + ) + +def downgrade(): + op.execute("ALTER TYPE record_types RENAME TO record_types_old") + op.execute("CREATE TYPE record_types AS ENUM('AS', 'FD', 'LD', 'MS')") + op.execute( + """ + ALTER TABLE records ALTER COLUMN record_type TYPE record_types + USING record_type::text::record_types + """ + ) + op.execute("DROP TYPE record_types_old") diff --git a/fittrackee/workouts/models.py b/fittrackee/workouts/models.py index ac5e2273..d9089889 100644 --- a/fittrackee/workouts/models.py +++ b/fittrackee/workouts/models.py @@ -22,6 +22,7 @@ BaseModel: DeclarativeMeta = db.Model record_types = [ 'AS', # 'Best Average Speed' 'FD', # 'Farthest Distance' + 'HA', # 'Highest Ascent' 'LD', # 'Longest Duration' 'MS', # 'Max speed' ] @@ -322,6 +323,7 @@ class Workout(BaseModel): record_types_columns = { 'AS': 'ave_speed', # 'Average speed' 'FD': 'distance', # 'Farthest Distance' + 'HA': 'ascent', # 'Highest Ascent' 'LD': 'moving', # 'Longest Duration' 'MS': 'max_speed', # 'Max speed' } @@ -475,7 +477,7 @@ class Record(BaseModel): return datetime.timedelta(seconds=self._value) elif self.record_type in ['AS', 'MS']: return float(self._value / 100) - else: # 'FD' + else: # 'FD' or 'HA' return float(self._value / 1000) @value.setter # type: ignore @@ -485,7 +487,7 @@ class Record(BaseModel): def serialize(self) -> Dict: if self.value is None: value = None - elif self.record_type in ['AS', 'FD', 'MS']: + elif self.record_type in ['AS', 'FD', 'HA', 'MS']: value = float(self.value) # type: ignore else: # 'LD' value = str(self.value) # type: ignore diff --git a/fittrackee_client/src/locales/en/workouts.json b/fittrackee_client/src/locales/en/workouts.json index 2685ea39..474fa29c 100644 --- a/fittrackee_client/src/locales/en/workouts.json +++ b/fittrackee_client/src/locales/en/workouts.json @@ -43,6 +43,7 @@ "RECORD": "record | records", "RECORD_AS": "Ave. speed", "RECORD_FD": "Farest distance", + "RECORD_HA": "Highest ascent", "RECORD_LD": "Longest duration", "RECORD_MS": "Max. speed", "REMAINING_CHARS": "remaining characters", diff --git a/fittrackee_client/src/locales/fr/workouts.json b/fittrackee_client/src/locales/fr/workouts.json index 5d5f3858..9ecc2173 100644 --- a/fittrackee_client/src/locales/fr/workouts.json +++ b/fittrackee_client/src/locales/fr/workouts.json @@ -43,6 +43,7 @@ "RECORD": "record | records", "RECORD_AS": "Vitesse moy.", "RECORD_FD": "Distance la + longue", + "RECORD_HA": "dénivelé le plus positif", "RECORD_LD": "Durée la + longue", "RECORD_MS": "Vitesse max.", "REMAINING_CHARS": "nombre de caractères restants ", diff --git a/fittrackee_client/src/utils/records.ts b/fittrackee_client/src/utils/records.ts index abed185b..392e6e85 100644 --- a/fittrackee_client/src/utils/records.ts +++ b/fittrackee_client/src/utils/records.ts @@ -9,30 +9,37 @@ export const formatRecord = ( tz: string, useImperialUnits: boolean ): Record => { - const unitFrom: TUnit = 'km' - const unitTo: TUnit = useImperialUnits - ? units[unitFrom].defaultTarget - : unitFrom + const distanceUnitFrom: TUnit = 'km' + const distanceUnitTo: TUnit = useImperialUnits + ? units[distanceUnitFrom].defaultTarget + : distanceUnitFrom + const ascentUnitFrom: TUnit = 'm' + const ascentUnitTo: TUnit = useImperialUnits + ? units[ascentUnitFrom].defaultTarget + : ascentUnitFrom let value switch (record.record_type) { case 'AS': case 'MS': value = `${convertDistance( +record.value, - unitFrom, - unitTo, + distanceUnitFrom, + distanceUnitTo, 2 - )} ${unitTo}/h` + )} ${distanceUnitTo}/h` break case 'FD': - value = `${convertDistance(+record.value, unitFrom, unitTo, 3)} ${unitTo}` + value = `${convertDistance(+record.value, distanceUnitFrom, distanceUnitTo, 3)} ${distanceUnitTo}` + break + case 'HA': + value = `${convertDistance(+record.value, ascentUnitFrom, ascentUnitTo, 2)} ${ascentUnitTo}` break case 'LD': value = record.value break default: throw new Error( - `Invalid record type, expected: "AS", "FD", "LD", "MD", got: "${record.record_type}"` + `Invalid record type, expected: "AS", "FD", "HA", "LD", "MD", got: "${record.record_type}"` ) } return { From f49c4184b326ae5fc14443e8f90d87f1894b278f Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Mon, 18 Jul 2022 09:29:24 -0400 Subject: [PATCH 02/17] Added highest ascent tests --- .../tests/unit/utils/records.spec.ts | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/fittrackee_client/tests/unit/utils/records.spec.ts b/fittrackee_client/tests/unit/utils/records.spec.ts index 8f0d9d3d..0c5da38d 100644 --- a/fittrackee_client/tests/unit/utils/records.spec.ts +++ b/fittrackee_client/tests/unit/utils/records.spec.ts @@ -94,6 +94,28 @@ describe('formatRecord', () => { workout_id: 'hvYBqYBRa7wwXpaStWR4V2', }, }, + { + description: "return formatted record for 'Highest ascent'", + inputParams: { + record: { + id: 13, + record_type: 'HA', + sport_id: 1, + user: 'admin', + value: 100, + workout_date: 'Sun, 07 Jul 2019 08:00:00 GMT', + workout_id: 'hvYBqYBRa7wwXpaStWR4V2', + }, + timezone: 'Europe/Paris', + }, + expected: { + id: 13, + record_type: 'HA', + value: '100 m', + workout_date: '2019/07/07', + workout_id: 'hvYBqYBRa7wwXpaStWR4V2', + }, + }, ] testsParams.map((testParams) => { it(testParams.description, () => { @@ -199,6 +221,28 @@ describe('formatRecord after conversion', () => { workout_id: 'hvYBqYBRa7wwXpaStWR4V2', }, }, + { + description: "return formatted record for 'Highest ascent'", + inputParams: { + record: { + id: 13, + record_type: 'HA', + sport_id: 1, + user: 'admin', + value: 100, + workout_date: 'Sun, 07 Jul 2019 08:00:00 GMT', + workout_id: 'hvYBqYBRa7wwXpaStWR4V2', + }, + timezone: 'Europe/Paris', + }, + expected: { + id: 13, + record_type: 'HA', + value: '328.08 ft', + workout_date: '2019/07/07', + workout_id: 'hvYBqYBRa7wwXpaStWR4V2', + }, + }, ] testsParams.map((testParams) => { it(testParams.description, () => { @@ -231,7 +275,7 @@ describe('formatRecord (invalid record type)', () => { false ) ).to.throw( - 'Invalid record type, expected: "AS", "FD", "LD", "MD", got: "M"' + 'Invalid record type, expected: "AS", "FD", "LD", "HA", "MD", got: "M"' ) }) }) From 19d6a69813a701b345f744661372c71a792fe0f6 Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Mon, 18 Jul 2022 09:37:30 -0400 Subject: [PATCH 03/17] Update test message and record count for asserts --- fittrackee/tests/workouts/test_workouts_api_2_patch.py | 2 +- fittrackee_client/tests/unit/utils/records.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fittrackee/tests/workouts/test_workouts_api_2_patch.py b/fittrackee/tests/workouts/test_workouts_api_2_patch.py index cf3143bc..05657365 100644 --- a/fittrackee/tests/workouts/test_workouts_api_2_patch.py +++ b/fittrackee/tests/workouts/test_workouts_api_2_patch.py @@ -32,7 +32,7 @@ def assert_workout_data_with_gpx(data: Dict, sport_id: int) -> None: assert data['data']['workouts'][0]['with_gpx'] is True records = data['data']['workouts'][0]['records'] - assert len(records) == 4 + assert len(records) == 5 assert records[0]['sport_id'] == sport_id assert records[0]['workout_id'] == data['data']['workouts'][0]['id'] assert records[0]['record_type'] == 'MS' diff --git a/fittrackee_client/tests/unit/utils/records.spec.ts b/fittrackee_client/tests/unit/utils/records.spec.ts index 0c5da38d..09ca4bcd 100644 --- a/fittrackee_client/tests/unit/utils/records.spec.ts +++ b/fittrackee_client/tests/unit/utils/records.spec.ts @@ -275,7 +275,7 @@ describe('formatRecord (invalid record type)', () => { false ) ).to.throw( - 'Invalid record type, expected: "AS", "FD", "LD", "HA", "MD", got: "M"' + 'Invalid record type, expected: "AS", "FD", "HA", "LD", "MD", got: "M"' ) }) }) From a8d4c470bb0ac54b87596160c9b1525c1e1ae859 Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Mon, 18 Jul 2022 11:03:06 -0400 Subject: [PATCH 04/17] Moved FD test down, added AS test --- .../tests/workouts/test_workouts_api_2_patch.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fittrackee/tests/workouts/test_workouts_api_2_patch.py b/fittrackee/tests/workouts/test_workouts_api_2_patch.py index 05657365..be61a4a7 100644 --- a/fittrackee/tests/workouts/test_workouts_api_2_patch.py +++ b/fittrackee/tests/workouts/test_workouts_api_2_patch.py @@ -45,14 +45,18 @@ def assert_workout_data_with_gpx(data: Dict, sport_id: int) -> None: assert records[1]['value'] == '0:04:10' assert records[2]['sport_id'] == sport_id assert records[2]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[2]['record_type'] == 'FD' + assert records[2]['record_type'] == 'HA' assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' - assert records[2]['value'] == 0.32 assert records[3]['sport_id'] == sport_id assert records[3]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[3]['record_type'] == 'AS' + assert records[3]['record_type'] == 'FD' assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' - assert records[3]['value'] == 4.61 + assert records[3]['value'] == 0.32 + assert records[4]['sport_id'] == sport_id + assert records[4]['workout_id'] == data['data']['workouts'][0]['id'] + assert records[4]['record_type'] == 'AS' + assert records[4]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[4]['value'] == 4.61 class TestEditWorkoutWithGpx(ApiTestCaseMixin): From a22096e65244637375134a92af7a47057bd7a2c1 Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Mon, 18 Jul 2022 11:27:50 -0400 Subject: [PATCH 05/17] Update post tests for HA --- .../workouts/test_workouts_api_1_post.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/fittrackee/tests/workouts/test_workouts_api_1_post.py b/fittrackee/tests/workouts/test_workouts_api_1_post.py index 292a639a..6af76e19 100644 --- a/fittrackee/tests/workouts/test_workouts_api_1_post.py +++ b/fittrackee/tests/workouts/test_workouts_api_1_post.py @@ -133,7 +133,7 @@ def assert_workout_data_with_gpx_segments(data: Dict) -> None: assert segment['pauses'] is None records = data['data']['workouts'][0]['records'] - assert len(records) == 4 + assert len(records) == 5 assert records[0]['sport_id'] == 1 assert records[0]['workout_id'] == data['data']['workouts'][0]['id'] assert records[0]['record_type'] == 'MS' @@ -146,14 +146,18 @@ def assert_workout_data_with_gpx_segments(data: Dict) -> None: assert records[1]['value'] == '0:03:55' assert records[2]['sport_id'] == 1 assert records[2]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[2]['record_type'] == 'FD' + assert records[2]['record_type'] == 'HA' assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' - assert records[2]['value'] == 0.3 assert records[3]['sport_id'] == 1 assert records[3]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[3]['record_type'] == 'AS' + assert records[3]['record_type'] == 'FD' assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' - assert records[3]['value'] == 4.59 + assert records[3]['value'] == 0.3 + assert records[4]['sport_id'] == 1 + assert records[4]['workout_id'] == data['data']['workouts'][0]['id'] + assert records[4]['record_type'] == 'AS' + assert records[4]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[4]['value'] == 4.59 def assert_workout_data_wo_gpx(data: Dict) -> None: @@ -186,7 +190,7 @@ def assert_workout_data_wo_gpx(data: Dict) -> None: assert len(data['data']['workouts'][0]['segments']) == 0 records = data['data']['workouts'][0]['records'] - assert len(records) == 4 + assert len(records) == 5 assert records[0]['sport_id'] == 1 assert records[0]['workout_id'] == data['data']['workouts'][0]['id'] assert records[0]['record_type'] == 'MS' @@ -199,14 +203,18 @@ def assert_workout_data_wo_gpx(data: Dict) -> None: assert records[1]['value'] == '1:00:00' assert records[2]['sport_id'] == 1 assert records[2]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[2]['record_type'] == 'FD' + assert records[2]['record_type'] == 'HA' assert records[2]['workout_date'] == 'Tue, 15 May 2018 14:05:00 GMT' - assert records[2]['value'] == 10.0 assert records[3]['sport_id'] == 1 assert records[3]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[3]['record_type'] == 'AS' + assert records[3]['record_type'] == 'FD' assert records[3]['workout_date'] == 'Tue, 15 May 2018 14:05:00 GMT' assert records[3]['value'] == 10.0 + assert records[4]['sport_id'] == 1 + assert records[4]['workout_id'] == data['data']['workouts'][0]['id'] + assert records[4]['record_type'] == 'AS' + assert records[4]['workout_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[4]['value'] == 10.0 class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin): From a86e65f01526b167a9e55a6fd60d2194e6a8ae94 Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Mon, 18 Jul 2022 11:34:42 -0400 Subject: [PATCH 06/17] Remove HA from asserts w/o GPX --- .../tests/workouts/test_workouts_api_1_post.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/fittrackee/tests/workouts/test_workouts_api_1_post.py b/fittrackee/tests/workouts/test_workouts_api_1_post.py index 6af76e19..fcf84a13 100644 --- a/fittrackee/tests/workouts/test_workouts_api_1_post.py +++ b/fittrackee/tests/workouts/test_workouts_api_1_post.py @@ -190,7 +190,7 @@ def assert_workout_data_wo_gpx(data: Dict) -> None: assert len(data['data']['workouts'][0]['segments']) == 0 records = data['data']['workouts'][0]['records'] - assert len(records) == 5 + assert len(records) == 4 assert records[0]['sport_id'] == 1 assert records[0]['workout_id'] == data['data']['workouts'][0]['id'] assert records[0]['record_type'] == 'MS' @@ -203,18 +203,14 @@ def assert_workout_data_wo_gpx(data: Dict) -> None: assert records[1]['value'] == '1:00:00' assert records[2]['sport_id'] == 1 assert records[2]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[2]['record_type'] == 'HA' + assert records[2]['record_type'] == 'FD' assert records[2]['workout_date'] == 'Tue, 15 May 2018 14:05:00 GMT' + assert records[2]['value'] == 10.0 assert records[3]['sport_id'] == 1 assert records[3]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[3]['record_type'] == 'FD' + assert records[3]['record_type'] == 'AS' assert records[3]['workout_date'] == 'Tue, 15 May 2018 14:05:00 GMT' assert records[3]['value'] == 10.0 - assert records[4]['sport_id'] == 1 - assert records[4]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[4]['record_type'] == 'AS' - assert records[4]['workout_date'] == 'Tue, 15 May 2018 14:05:00 GMT' - assert records[4]['value'] == 10.0 class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin): From 397c711992d0cad3326b8d006cd4a0cd45a493a9 Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Mon, 18 Jul 2022 13:04:17 -0400 Subject: [PATCH 07/17] Added one mmore HA check for 5 records --- .../tests/workouts/test_workouts_api_1_post.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fittrackee/tests/workouts/test_workouts_api_1_post.py b/fittrackee/tests/workouts/test_workouts_api_1_post.py index fcf84a13..dadc8331 100644 --- a/fittrackee/tests/workouts/test_workouts_api_1_post.py +++ b/fittrackee/tests/workouts/test_workouts_api_1_post.py @@ -56,7 +56,7 @@ def assert_workout_data_with_gpx(data: Dict) -> None: assert segment['pauses'] is None records = data['data']['workouts'][0]['records'] - assert len(records) == 4 + assert len(records) == 5 assert records[0]['sport_id'] == 1 assert records[0]['workout_id'] == data['data']['workouts'][0]['id'] assert records[0]['record_type'] == 'MS' @@ -69,14 +69,18 @@ def assert_workout_data_with_gpx(data: Dict) -> None: assert records[1]['value'] == '0:04:10' assert records[2]['sport_id'] == 1 assert records[2]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[2]['record_type'] == 'FD' + assert records[2]['record_type'] == 'HA' assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' - assert records[2]['value'] == 0.32 assert records[3]['sport_id'] == 1 assert records[3]['workout_id'] == data['data']['workouts'][0]['id'] - assert records[3]['record_type'] == 'AS' + assert records[3]['record_type'] == 'FD' assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' - assert records[3]['value'] == 4.61 + assert records[3]['value'] == 0.32 + assert records[4]['sport_id'] == 1 + assert records[4]['workout_id'] == data['data']['workouts'][0]['id'] + assert records[4]['record_type'] == 'AS' + assert records[4]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + assert records[4]['value'] == 4.61 def assert_workout_data_with_gpx_segments(data: Dict) -> None: From e5a6ae4f18fa3659339f6d604749eb3477859e32 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 19 Jul 2022 10:26:21 +0200 Subject: [PATCH 08/17] API - fix down revision --- .../migrations/versions/24_cd0e6cf83207_add_ascent_record.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py b/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py index aef966c1..9b0b23c5 100644 --- a/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py +++ b/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py @@ -1,7 +1,7 @@ """add ascent record Revision ID: cd0e6cf83207 -Revises: e30007d681cb +Revises: 5e3a3a31c432 Create Date: 2022-03-22 20:21:13.661883 """ @@ -11,7 +11,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'cd0e6cf83207' -down_revision = 'e30007d681cb' +down_revision = '5e3a3a31c432' branch_labels = None depends_on = None @@ -23,6 +23,7 @@ def upgrade(): """ ) + def downgrade(): op.execute("ALTER TYPE record_types RENAME TO record_types_old") op.execute("CREATE TYPE record_types AS ENUM('AS', 'FD', 'LD', 'MS')") From 4488c44297294d703d6afe1b8da380259b785292 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 19 Jul 2022 10:31:47 +0200 Subject: [PATCH 09/17] Client - update french translation --- fittrackee_client/src/locales/fr/workouts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fittrackee_client/src/locales/fr/workouts.json b/fittrackee_client/src/locales/fr/workouts.json index 9ecc2173..1e4d59bf 100644 --- a/fittrackee_client/src/locales/fr/workouts.json +++ b/fittrackee_client/src/locales/fr/workouts.json @@ -43,7 +43,7 @@ "RECORD": "record | records", "RECORD_AS": "Vitesse moy.", "RECORD_FD": "Distance la + longue", - "RECORD_HA": "dénivelé le plus positif", + "RECORD_HA": "Dénivelé positif le + élevé", "RECORD_LD": "Durée la + longue", "RECORD_MS": "Vitesse max.", "REMAINING_CHARS": "nombre de caractères restants ", From 4322b01966b45412701d5d839ef8470d0753cc74 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 19 Jul 2022 10:42:37 +0200 Subject: [PATCH 10/17] API - fix HA record when workout w/o gpx already exists --- .../workouts/test_workouts_api_1_post.py | 34 +++++++++++++++++++ fittrackee/workouts/models.py | 10 +++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/fittrackee/tests/workouts/test_workouts_api_1_post.py b/fittrackee/tests/workouts/test_workouts_api_1_post.py index dadc8331..9ca5cadb 100644 --- a/fittrackee/tests/workouts/test_workouts_api_1_post.py +++ b/fittrackee/tests/workouts/test_workouts_api_1_post.py @@ -70,6 +70,7 @@ def assert_workout_data_with_gpx(data: Dict) -> None: assert records[2]['sport_id'] == 1 assert records[2]['workout_id'] == data['data']['workouts'][0]['id'] assert records[2]['record_type'] == 'HA' + assert records[2]['value'] == 0.4 assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[3]['sport_id'] == 1 assert records[3]['workout_id'] == data['data']['workouts'][0]['id'] @@ -260,6 +261,39 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin): assert 'just a workout' == data['data']['workouts'][0]['title'] assert_workout_data_with_gpx(data) + def test_it_returns_ha_record_when_a_workout_without_gpx_exists( + self, + app: Flask, + user_1: User, + sport_1_cycling: Sport, + gpx_file: str, + workout_cycling_user_1: Workout, + ) -> None: + client, auth_token = self.get_test_client_and_auth_token( + app, user_1.email + ) + + response = client.post( + '/api/workouts', + data=dict( + file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), + data='{"sport_id": 1}', + ), + headers=dict( + content_type='multipart/form-data', + Authorization=f'Bearer {auth_token}', + ), + ) + + data = json.loads(response.data.decode()) + records = data['data']['workouts'][0]['records'] + assert len(records) == 1 + assert records[0]['sport_id'] == 1 + assert records[0]['workout_id'] == data['data']['workouts'][0]['id'] + assert records[0]['record_type'] == 'HA' + assert records[0]['value'] == 0.4 + assert records[0]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' + def test_it_creates_workout_with_expecting_gpx_path( self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str ) -> None: diff --git a/fittrackee/workouts/models.py b/fittrackee/workouts/models.py index 318492b2..8c479285 100644 --- a/fittrackee/workouts/models.py +++ b/fittrackee/workouts/models.py @@ -320,6 +320,10 @@ class Workout(BaseModel): def get_user_workout_records( cls, user_id: int, sport_id: int, as_integer: Optional[bool] = False ) -> Dict: + """ + Note: + Values for ascent are null for workouts without gpx + """ record_types_columns = { 'AS': 'ave_speed', # 'Average speed' 'FD': 'distance', # 'Farthest Distance' @@ -331,7 +335,11 @@ class Workout(BaseModel): for record_type, column in record_types_columns.items(): column_sorted = getattr(getattr(Workout, column), 'desc')() record_workout = ( - Workout.query.filter_by(user_id=user_id, sport_id=sport_id) + Workout.query.filter( + Workout.user_id == user_id, + Workout.sport_id == sport_id, + getattr(Workout, column) != None, # noqa + ) .order_by(column_sorted, Workout.workout_date) .first() ) From d66f6828e47d8af8ac7cdb707021dde140e53ed8 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 19 Jul 2022 20:04:32 +0200 Subject: [PATCH 11/17] API - fix downgrade revision --- .../migrations/versions/24_cd0e6cf83207_add_ascent_record.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py b/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py index 9b0b23c5..1129588e 100644 --- a/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py +++ b/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py @@ -25,6 +25,7 @@ def upgrade(): def downgrade(): + op.execute("DELETE FROM records WHERE record_type = 'HA';") op.execute("ALTER TYPE record_types RENAME TO record_types_old") op.execute("CREATE TYPE record_types AS ENUM('AS', 'FD', 'LD', 'MS')") op.execute( From 06b7af126ab1bb3712ed105bd86b6d97207593eb Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 23 Jul 2022 08:09:45 +0200 Subject: [PATCH 12/17] API - add preferences for ascent record display --- .../versions/24_cd0e6cf83207_add_ascent_record.py | 8 ++++++++ fittrackee/tests/users/test_auth_api.py | 6 +++++- fittrackee/tests/users/test_users_model.py | 1 + fittrackee/users/auth.py | 3 +++ fittrackee/users/models.py | 2 ++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py b/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py index 1129588e..760ec9d6 100644 --- a/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py +++ b/fittrackee/migrations/versions/24_cd0e6cf83207_add_ascent_record.py @@ -23,8 +23,16 @@ def upgrade(): """ ) + op.add_column( + 'users', sa.Column('display_ascent', sa.Boolean(), nullable=True) + ) + op.execute("UPDATE users SET display_ascent = true") + op.alter_column('users', 'display_ascent', nullable=False) + def downgrade(): + op.drop_column('users', 'display_ascent') + op.execute("DELETE FROM records WHERE record_type = 'HA';") op.execute("ALTER TYPE record_types RENAME TO record_types_old") op.execute("CREATE TYPE record_types AS ENUM('AS', 'FD', 'LD', 'MS')") diff --git a/fittrackee/tests/users/test_auth_api.py b/fittrackee/tests/users/test_auth_api.py index 3404e14a..96ff3bf5 100644 --- a/fittrackee/tests/users/test_auth_api.py +++ b/fittrackee/tests/users/test_auth_api.py @@ -1272,6 +1272,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin): weekm=True, language=input_language, imperial_units=True, + display_ascent=False, ) ), headers=dict(Authorization=f'Bearer {auth_token}'), @@ -1281,8 +1282,11 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin): data = json.loads(response.data.decode()) assert data['status'] == 'success' assert data['message'] == 'user preferences updated' + assert data['data']['display_ascent'] is False + assert data['data']['imperial_units'] is True assert data['data']['language'] == expected_language - assert data['data'] == jsonify_dict(user_1.serialize(user_1)) + assert data['data']['timezone'] == 'America/New_York' + assert data['data']['weekm'] is True class TestUserSportPreferencesUpdate(ApiTestCaseMixin): diff --git a/fittrackee/tests/users/test_users_model.py b/fittrackee/tests/users/test_users_model.py index 93a5e0c1..54694205 100644 --- a/fittrackee/tests/users/test_users_model.py +++ b/fittrackee/tests/users/test_users_model.py @@ -66,6 +66,7 @@ class TestUserSerializeAsAuthUser(UserModelAssertMixin): assert serialized_user['language'] == user_1.language assert serialized_user['timezone'] == user_1.timezone assert serialized_user['weekm'] == user_1.weekm + assert serialized_user['display_ascent'] == user_1.display_ascent def test_it_returns_workouts_infos(self, app: Flask, user_1: User) -> None: serialized_user = user_1.serialize(user_1) diff --git a/fittrackee/users/auth.py b/fittrackee/users/auth.py index ddaf8511..080de45e 100644 --- a/fittrackee/users/auth.py +++ b/fittrackee/users/auth.py @@ -830,6 +830,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]: # get post data post_data = request.get_json() user_mandatory_data = { + 'display_ascent', 'imperial_units', 'language', 'timezone', @@ -838,12 +839,14 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]: if not post_data or not post_data.keys() >= user_mandatory_data: return InvalidPayloadErrorResponse() + display_ascent = post_data.get('display_ascent') imperial_units = post_data.get('imperial_units') language = get_language(post_data.get('language')) timezone = post_data.get('timezone') weekm = post_data.get('weekm') try: + auth_user.display_ascent = display_ascent auth_user.imperial_units = imperial_units auth_user.language = language auth_user.timezone = timezone diff --git a/fittrackee/users/models.py b/fittrackee/users/models.py index bc19df4c..b10541c2 100644 --- a/fittrackee/users/models.py +++ b/fittrackee/users/models.py @@ -50,6 +50,7 @@ class User(BaseModel): is_active = db.Column(db.Boolean, default=False, nullable=False) email_to_confirm = db.Column(db.String(255), nullable=True) confirmation_token = db.Column(db.String(255), nullable=True) + display_ascent = db.Column(db.Boolean, default=True, nullable=False) def __repr__(self) -> str: return f'' @@ -170,6 +171,7 @@ class User(BaseModel): serialized_user = { **serialized_user, **{ + 'display_ascent': self.display_ascent, 'imperial_units': self.imperial_units, 'language': self.language, 'timezone': self.timezone, From 81efdf53d51492348324bb9ad56f9d18756527a2 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 23 Jul 2022 08:17:37 +0200 Subject: [PATCH 13/17] Client - add preferences for ascent related data --- .../User/ProfileDisplay/UserPreferences.vue | 9 +++-- .../ProfileEdition/UserPreferencesEdition.vue | 34 +++++++++++++++++-- fittrackee_client/src/locales/en/common.json | 2 ++ fittrackee_client/src/locales/en/user.json | 1 + fittrackee_client/src/locales/fr/common.json | 2 ++ fittrackee_client/src/locales/fr/user.json | 1 + fittrackee_client/src/types/user.ts | 2 ++ 7 files changed, 46 insertions(+), 5 deletions(-) diff --git a/fittrackee_client/src/components/User/ProfileDisplay/UserPreferences.vue b/fittrackee_client/src/components/User/ProfileDisplay/UserPreferences.vue index 53caaefa..01f5ea9d 100644 --- a/fittrackee_client/src/components/User/ProfileDisplay/UserPreferences.vue +++ b/fittrackee_client/src/components/User/ProfileDisplay/UserPreferences.vue @@ -15,6 +15,8 @@ ) }} +
{{ $t('user.PROFILE.ASCENT_DATA') }}:
+
{{ $t(`common.${display_ascent}`) }}