Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to replace gpx title when adding a workout #635

Merged
merged 2 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fittrackee/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<link rel="stylesheet" href="/static/css/fork-awesome.min.css"/>
<link rel="stylesheet" href="/static/css/leaflet.css"/>
<title>FitTrackee</title>
<script type="module" crossorigin src="/static/index-BROICLJS.js"></script>
<script type="module" crossorigin src="/static/index-DuUOrRe4.js"></script>
<link rel="modulepreload" crossorigin href="/static/charts-lWJH0bM4.js">
<link rel="modulepreload" crossorigin href="/static/maps-BFpqWvfo.js">
<link rel="stylesheet" crossorigin href="/static/css/maps-HupOsEJb.css">
<link rel="stylesheet" crossorigin href="/static/css/index-G9nqqDAl.css">
<link rel="stylesheet" crossorigin href="/static/css/index-nH9XMQiq.css">
</head>
<body>
<div id="app"></div>
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions fittrackee/tests/workouts/test_workouts_api_1_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,36 @@ def test_it_adds_a_workout_with_gpx_without_name(
)
assert_workout_data_with_gpx(data)

def test_it_adds_a_workout_with_provided_title(
self,
app: Flask,
user_1: User,
sport_1_cycling: Sport,
gpx_file: str,
) -> None:
title = "some title"
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=f'{{"sport_id": 1, "title": "{title}"}}',
),
headers=dict(
content_type='multipart/form-data',
Authorization=f'Bearer {auth_token}',
),
)

data = json.loads(response.data.decode())
assert response.status_code == 201
assert 'created' in data['status']
assert len(data['data']['workouts']) == 1
assert data['data']['workouts'][0]['title'] == title

def test_it_adds_a_workout_with_gpx_without_name_timezone(
self,
app: Flask,
Expand Down
8 changes: 7 additions & 1 deletion fittrackee/workouts/utils/workouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,13 @@ def create_workout(
else timedelta(seconds=workout_data['duration'])
)
distance = gpx_data['distance'] if gpx_data else workout_data['distance']
title = gpx_data['name'] if gpx_data else workout_data.get('title', '')
title = (
workout_data.get('title', '')
if workout_data.get('title', '')
else gpx_data['name']
if gpx_data
else ''
)

new_workout = Workout(
user_id=user.id,
Expand Down
17 changes: 10 additions & 7 deletions fittrackee/workouts/workouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1043,21 +1043,24 @@ def post_workout(auth_user: User) -> Union[Tuple[Dict, int], HttpResponse]:
}
:form file: gpx file (allowed extensions: .gpx, .zip)
:form data: sport id, equipment id, description and notes, for example:
`{"sport_id": 1, "notes": "", "description": "", "equipment_ids": []}`.
Double quotes in notes and description must be escaped.
:form data: sport id, equipment id, description, title and notes,
for example:
``{"sport_id": 1, "notes": "", "title": "", "description": "",
"equipment_ids": []}``.
Double quotes in notes, description and title must be escaped.
The maximum length of notes is 500 characters and that of the
description is 10000 characters.
Otherwise, they will be truncated.
The maximum length is 500 characters for notes, 10000 characters for
description and 255 for title. Otherwise, they will be truncated.
When description and title are provided, they replace the description
and title from gpx file.
For `equipment_ids`, the id of the equipment to associate with
this workout.
**Note**: for now only one equipment can be associated.
If not provided and default equipment exists for sport,
default equipment will be associated.
Notes, description and equipment ids are not mandatory.
Notes, description, and title and equipment ids are not mandatory.
:reqheader Authorization: OAuth 2.0 Bearer Token
Expand Down
26 changes: 19 additions & 7 deletions fittrackee_client/src/components/Workout/WorkoutEdition.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
</div>
</div>
</div>
<div class="form-item" v-else>
<div class="form-item">
<label for="title"> {{ $t('workouts.TITLE') }}: </label>
<input
id="title"
Expand All @@ -105,6 +105,12 @@
v-model="workoutForm.title"
maxlength="255"
/>
<div class="filed-help" v-if="withGpx && isCreation">
<span class="info-box">
<i class="fa fa-info-circle" aria-hidden="true" />
{{ $t('workouts.TITLE_FIELD_HELP') }}
</span>
</div>
</div>
<div v-if="!withGpx">
<div class="workout-date-duration">
Expand Down Expand Up @@ -512,7 +518,6 @@
}
function formatPayload(payload: IWorkoutForm) {
payloadErrorMessages.value = []
payload.title = workoutForm.title
payload.duration =
+workoutForm.workoutDurationHour * 3600 +
+workoutForm.workoutDurationMinutes * 60 +
Expand Down Expand Up @@ -556,11 +561,10 @@
equipmentsForSelect.value.find((e) => e.id === workoutForm.equipment_id)
? [workoutForm.equipment_id]
: [],
title: workoutForm.title,
}
if (props.workout.id) {
if (props.workout.with_gpx) {
payload.title = workoutForm.title
} else {
if (!props.workout.with_gpx) {
formatPayload(payload)
}
if (payloadErrorMessages.value.length > 0) {
Expand Down Expand Up @@ -677,7 +681,8 @@
.form-item {
display: flex;
flex-direction: column;
padding: $default-padding;
padding: $default-padding * 0.5 $default-padding $default-padding *
0.25;
.workout-date-time {
display: flex;
Expand Down Expand Up @@ -710,15 +715,17 @@
.form-buttons {
display: flex;
justify-content: flex-end;
padding: $default-padding $default-padding * 0.5 0;
button {
margin: $default-padding * 0.5;
margin: $default-margin * 0.5;
}
}
.files-help {
display: flex;
justify-content: space-around;
margin-top: $default-margin;
padding: $default-padding * 0.75 $default-padding;
div {
display: flex;
@media screen and (max-width: $medium-limit) {
Expand All @@ -731,6 +738,11 @@
}
}
.filed-help {
display: flex;
margin-top: $default-margin * 0.5;
}
.workout-data {
display: flex;
flex-direction: row;
Expand Down
1 change: 1 addition & 0 deletions fittrackee_client/src/locales/en/workouts.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"START_AND_FINISH": "Start and finish",
"START_ELEVATION_AT_ZERO": "start elevation axis at zero",
"TITLE": "title",
"TITLE_FIELD_HELP": "if provided, the title replaces that of the gpx file.",
"TO": "to",
"TOTAL_DISTANCE": "total distance",
"TOTAL_DURATION": "total duration",
Expand Down
1 change: 1 addition & 0 deletions fittrackee_client/src/locales/fr/workouts.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"START_AND_FINISH": "Départ et arrivée",
"START_ELEVATION_AT_ZERO": "démarrer l'axe de l'altitude à 0",
"TITLE": "titre",
"TITLE_FIELD_HELP": "si fourni, le titre remplace celui du fichier gpx.",
"TO": "jusqu'au",
"TOTAL_DISTANCE": "distance totale",
"TOTAL_DURATION": "durée totale",
Expand Down
3 changes: 2 additions & 1 deletion fittrackee_client/src/store/modules/workouts/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,13 @@ export const actions: ActionTree<IWorkoutsState, IRootState> &
}
const notes = payload.notes.replace(/"/g, '\\"')
const description = payload.description.replace(/"/g, '\\"')
const title = payload.title.replace(/"/g, '\\"')
const form = new FormData()
form.append('file', payload.file)
form.append(
'data',
`{"sport_id": ${payload.sport_id}, "notes": "${notes}",` +
` "description": "${description}",` +
` "description": "${description}", "title": "${title}", ` +
` "equipment_ids": [${payload.equipment_ids.map((e) => `"${e}"`).join(',')}]}`
)
authApi
Expand Down
2 changes: 1 addition & 1 deletion fittrackee_client/src/types/workouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export interface IWorkoutObject {
export interface IWorkoutForm {
sport_id: number | null
notes: string
title?: string
title: string
workout_date?: string
distance?: number
duration?: number
Expand Down