From 7c32299887b68716140110b64f67f0c1ad7b00b0 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 9 Mar 2026 19:50:16 +0100 Subject: [PATCH 1/5] v1 --- rowers/tests/testdata/testdata.tcx.gz | Bin 3989 -> 3989 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index badd3b34ad1d668d4b5cbe5e09887b9468fa7fb7..ddb3077e2ea22513d60805d46af3486a7e6e8966 100644 GIT binary patch delta 16 XcmbO#KUJPxzMF&NyYTvr?0x(ID=P&! delta 16 XcmbO#KUJPxzMF$%$*0vD+57kbE(`_0 From 93c5dc228d07bf1e65006c18309944fb8ec6b442 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 9 Mar 2026 20:29:33 +0100 Subject: [PATCH 2/5] tested --- rowers/tests/testdata/testdata.tcx.gz | Bin 3989 -> 3989 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index ddb3077e2ea22513d60805d46af3486a7e6e8966..eac06beed11781e4ac2edb5a9989c64821c4d285 100644 GIT binary patch delta 15 WcmbO#KUJPhzMF$XS9T*?KR*B;_5;WO delta 15 WcmbO#KUJPhzMF&NyYNP~etrNXfCPvD From 3a0fe7103ae3f55927fa7b702faaeff69ccd00c7 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 13 Mar 2026 10:48:33 +0100 Subject: [PATCH 3/5] adding FIT export --- rowers/templates/menu_workout.html | 5 +++++ rowers/urls.py | 2 ++ rowers/views/exportviews.py | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/rowers/templates/menu_workout.html b/rowers/templates/menu_workout.html index ea138baf..a503805f 100644 --- a/rowers/templates/menu_workout.html +++ b/rowers/templates/menu_workout.html @@ -260,6 +260,11 @@ TCX +
  • + + FIT + +
  • diff --git a/rowers/urls.py b/rowers/urls.py index b6e01143..14e77eb0 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -494,6 +494,8 @@ urlpatterns = [ name='workout_comment_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/emailtcx/$', views.workout_tcxemail_view, name='workout_tcxemail_view'), + re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/emailfit/$', views.workout_fitemail_view, + name='workout_fitemail_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/emailgpx/$', views.workout_gpxemail_view, name='workout_gpxemail_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/emailcsv/$', views.workout_csvemail_view, diff --git a/rowers/views/exportviews.py b/rowers/views/exportviews.py index e2aa4a00..0b62bdc2 100644 --- a/rowers/views/exportviews.py +++ b/rowers/views/exportviews.py @@ -22,6 +22,27 @@ def workout_tcxemail_view(request, id=0): os.remove(tcxfilename) return response +@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True) +def workout_fitemail_view(request, id=0): + w = get_workout(id) + + row = rdata(csvfile=w.csvfilename) + + code = str(uuid4()) + fitfilename = code+'.fit' + + workouttype = mytypes.fitmapping.get(w.workouttype, 'generic') + + row.exporttofit(fitfilename, sport=workouttype, notes=w.name) + + with open(fitfilename, 'rb') as f: + response = HttpResponse(f) + response['Content-Disposition'] = 'attachment; filename="%s"' % fitfilename + response['Content-Type'] = 'application/octet-stream' + + os.remove(fitfilename) + return response + @login_required() def plannedsessions_icsemail_view(request, userid=0): From 1e8945351aa0710f36a79dd3886677fb595acbe8 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 13 Mar 2026 11:09:21 +0100 Subject: [PATCH 4/5] bulk export through fit files --- rowers/tasks.py | 19 +++++++------------ rowers/tests/testdata/testdata.tcx.gz | Bin 3989 -> 3989 bytes 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/rowers/tasks.py b/rowers/tasks.py index 2e1db4e7..b571261c 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -386,18 +386,13 @@ def email_all_user_workouts_zip(rower, start_date=None, end_date=None, debug=Fal for workout in workouts: try: rowdata = rdata(csvfile=workout.csvfilename) - rowdate = rowdata.rowdatetime - starttimeunix = arrow.get(rowdate).timestamp() - df = rowdata.df - - try: - df[' ElapsedTime (sec)'] = df['TimeStamp (sec)'] - df['TimeStamp (sec)'] = df['TimeStamp (sec)'] + starttimeunix - except KeyError: - pass - - csv_filename = f"workout_{workout.id}_{workout.date.strftime('%Y%m%d')}.csv" - zip_file.writestr(csv_filename, df.to_csv(index=False)) + workouttype = mytypes.fitmapping.get(workout.workouttype, 'generic') + + fit_filename = f"workout_{workout.id}_{workout.date.strftime('%Y%m%d')}.fit" + # exporttofit creates a file, we need to add it to the zip_file + rowdata.exporttofit(fit_filename, sport=workouttype, notes=workout.name) + zip_file.write(fit_filename, arcname=fit_filename) + os.remove(fit_filename) except Exception as e: # pragma: no cover dologging('export_all_workouts.log', f"Error exporting workout {workout.id}: {str(e)}") continue diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index eac06beed11781e4ac2edb5a9989c64821c4d285..c8bcbb3d16ccc60652a5aa9fc56ff5a9a56ed919 100644 GIT binary patch delta 16 XcmbO#KUJPxzMF%C_1@- Date: Fri, 13 Mar 2026 11:21:58 +0100 Subject: [PATCH 5/5] fix --- rowers/tests/testdata/testdata.tcx.gz | Bin 3989 -> 3989 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index c8bcbb3d16ccc60652a5aa9fc56ff5a9a56ed919..d87ca6f9821415ac106ec8fe292127b1b6e76a3f 100644 GIT binary patch delta 15 WcmbO#KUJPhzMF&N_M?q#{rmtY;{`ha delta 15 WcmbO#KUJPhzMF%C_1;FdetrNV%LHKn