From dfad4865c908abb4b8b87c6a25d8d698b307c21f Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 14 Dec 2024 13:58:23 +0100 Subject: [PATCH] ready for merge back --- rowers/dataprep.py | 4 +- rowers/forms.py | 20 +++++--- rowers/integrations/intervals.py | 1 + rowers/models.py | 2 +- rowers/templates/rower_exportsettings.html | 53 +++++++++------------ rowers/tests/testdata/testdata.tcx.gz | Bin 4000 -> 3999 bytes rowers/uploads.py | 36 +++++++------- rowers/views/userviews.py | 1 + rowers/views/workoutviews.py | 11 ----- static/img/intervals_logo_with_name.png | Bin 0 -> 18456 bytes 10 files changed, 61 insertions(+), 67 deletions(-) create mode 100644 static/img/intervals_logo_with_name.png diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 827a9717..28bf84be 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -369,7 +369,7 @@ def workout_summary_to_df( return df -def resample(id, r, parent, overwrite='copy'): +def resample(id, r, parent, overwrite=False): data, row = getrowdata_db(id=id) messages = [] @@ -393,7 +393,7 @@ def resample(id, r, parent, overwrite='copy'): data['pace'] = data['pace'] / 1000. data['time'] = data['time'] / 1000. - if overwrite == 'overwrite': + if overwrite == True: # remove CP data try: cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=parent.id) diff --git a/rowers/forms.py b/rowers/forms.py index 0ebc5fb3..506f900f 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -67,13 +67,12 @@ class FlexibleDecimalField(forms.DecimalField): class ResampleForm(forms.Form): - resamplechoices = ( - ('overwrite', 'Overwrite Workout'), - ('copy', 'Create a Duplicate Workout') - ) - + # add resamplechoice field, the result is a True or False boolean, labels are "overwrite" and "create copy" resamplechoice = forms.ChoiceField( - initial='copy', choices=resamplechoices, label='Copy behavior') + required=True, + choices=((True, 'overwrite'), (False, 'create copy')), + label='Resample choice', + widget=forms.RadioSelect) class TrainingZonesForm(forms.Form): @@ -582,6 +581,11 @@ class UploadOptionsForm(forms.Form): races = VirtualRace.objects.filter( registration_closure__gt=timezone.now()) + # set upload_to_X based on r.X_auto_export + for field in ['C2', 'Strava', 'SportTracks', 'TrainingPeaks', 'Intervals']: + if getattr(r, field.lower()+'_auto_export') and r.rowerplan in ['pro', 'plan','coach']: + self.fields['upload_to_'+field].initial = True + registrations = IndoorVirtualRaceResult.objects.filter( race__in=races, userid=r.id) @@ -665,6 +669,10 @@ class TeamUploadOptionsForm(forms.Form): upload_to_TrainingPeaks = forms.BooleanField(initial=False, required=False, label='Export to TrainingPeaks') + + upload_to_Intervals = forms.BooleanField(initial=False, + required=False, + label='Export to TrainingPeaks') # do_physics = forms.BooleanField(initial=False,required=False,label='Power Estimate (OTW)') makeprivate = forms.BooleanField(initial=False, required=False, label='Make Workout Private') diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py index 1cdcbfb0..7db883ae 100644 --- a/rowers/integrations/intervals.py +++ b/rowers/integrations/intervals.py @@ -17,6 +17,7 @@ import os from uuid import uuid4 from django.utils import timezone from datetime import timedelta +import rowers.dataprep as dataprep from rowsandall_app.settings import ( INTERVALS_CLIENT_ID, INTERVALS_REDIRECT_URI, INTERVALS_CLIENT_SECRET, SITE_URL diff --git a/rowers/models.py b/rowers/models.py index cd2500f7..047d8d0a 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -4561,6 +4561,7 @@ class RowerExportForm(ModelForm): 'rp3_auto_import', 'intervals_auto_import', 'intervals_auto_export', + 'intervals_resample_to_1s' ] class RowerExportFormStrava(ModelForm): @@ -4616,7 +4617,6 @@ class RowerExportFormTrainingPeaks(ModelForm): model = Rower fields = [ 'trainingpeaks_auto_export', - 'rp3_auto_import', ] class RowerExportFormRP3(ModelForm): diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html index 0d7d3858..13418d15 100644 --- a/rowers/templates/rower_exportsettings.html +++ b/rowers/templates/rower_exportsettings.html @@ -64,13 +64,12 @@ {% endif %}
  • -

    Intervals.icu

    +

    NK

    - {{ forms.intervals.as_table }} + {{ forms.nk.as_table }}
    -

    connect with intervals.icu

    +

    connect with NK Logbook

  • Concept2

    @@ -81,12 +80,27 @@

    connect with Concept2

  • -

    NK

    +

    RP3

    - {{ forms.nk.as_table }} + {{ forms.rp3.as_table }}
    -

    connect with NK Logbook

    +

    connect with RP3

    +
  • +
  • +

    Rojabo

    +

    connect with Rojabo

    +
  • +
  • +

    Intervals.icu

    + + {{ forms.intervals.as_table }} + +
    +

    connect with intervals.icu

  • SportTracks

    @@ -102,6 +116,8 @@ {{ forms.trainingpeaks.as_table }} +

    connect with Polar

  • Polar

    @@ -112,11 +128,6 @@

    connect with Polar

  • -
  • -

    Rojabo

    -

    connect with Rojabo

    -
  • Garmin Connect

    @@ -153,24 +164,6 @@

    -
  • -

    TrainingPeaks

    -
  • - {{ forms.trainingpeaks.as_table }} - -
    -

    connect with Polar

    -
  • -
  • -

    RP3

    - - {{ forms.rp3.as_table }} - -
    -

    connect with RP3

    -
  • {% if grants %}
  • Applications

    diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 3a4eca337f44e3c892acabb79b59b31fb7ee2684..dd7306f84921784d4337eb7cf60575abe39ca49f 100644 GIT binary patch delta 257 zcmV+c0sj7=AD<+lIJJZMCm_J{BTJ63+ zczBUGo?U#{_gR^Kd%F^qPsbfRc-_A`ySVb2 zJUBl;SsitK`stT1#^t%cI$8Ser`M~KmzO{HxAZ=yL$5rX4_lsg|4En3&Vs9OpTFL1 zwN9J8eA;ij;quXbasGoB>81~VU7jqv%`$PwpFTXgEBAHqq+1_9esuWrv&?4u=WhEi z=`DWt`t*-wx-)=#0K5MW7FWL5J^AfpI=r(*y;`T|@GzlVUOY-q2op#5N H#DD<+W`c@3 delta 258 zcmV+d0sa1;AD|xxABzYG+aFx92dNH!vHLS{=(;6*cijJQu-F}NXLqKLzcGKl{IuGA zfAH`kaXh>Du$`N`ZufR2DxZ!!c<{P^b#`&( zHFmSi+Z(A&*5Q0xx9Fkp2i>P(ua5c2dhPx I_QZez0LCki$p8QV diff --git a/rowers/uploads.py b/rowers/uploads.py index 71f07553..fae902d5 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -245,23 +245,6 @@ def do_sync(w, options, quick=False): dologging('c2_log.log','Error C2') pass - if do_strava_export: # pragma: no cover - strava_integration = StravaIntegration(w.user.user) - try: - id = strava_integration.workout_export(w) - dologging( - 'strava_export_log.log', - 'exporting workout {id} as {type}'.format( - id=w.id, - type=w.workouttype, - ) - ) - except NoTokenError: # pragma: no cover - id = 0 - message = "Please connect to Strava first" - except Exception as e: - dologging('stravalog.log', e) - if do_icu_export: intervals_integration = IntervalsIntegration(w.user.user) try: @@ -334,4 +317,23 @@ def do_sync(w, options, quick=False): dologging('tp_export.log','No Token Error') return 0 + # we do Strava last. + if do_strava_export: # pragma: no cover + strava_integration = StravaIntegration(w.user.user) + try: + id = strava_integration.workout_export(w) + dologging( + 'strava_export_log.log', + 'exporting workout {id} as {type}'.format( + id=w.id, + type=w.workouttype, + ) + ) + except NoTokenError: # pragma: no cover + id = 0 + message = "Please connect to Strava first" + except Exception as e: + dologging('stravalog.log', e) + + return 1 diff --git a/rowers/views/userviews.py b/rowers/views/userviews.py index d2d22e25..cf004032 100644 --- a/rowers/views/userviews.py +++ b/rowers/views/userviews.py @@ -465,6 +465,7 @@ def rower_exportsettings_view(request, userid=0): 'rp3_auto_import': 'rp3token', 'nk_auto_import': 'nktoken', 'intervals_auto_export': 'intervals_token', + 'intervals_resample_to_1s': 'intervals_token', } r = getrequestrowercoachee(request, userid=userid) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 14112726..0412c7ff 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -5609,17 +5609,6 @@ def workout_upload_view(request, return response else: if not is_ajax: - if r.c2_auto_export and ispromember(r.user): # pragma: no cover - uploadoptions['upload_to_C2'] = True - - if r.strava_auto_export and ispromember(r.user): # pragma: no cover - uploadoptions['upload_to_Strava'] = True - - if r.sporttracks_auto_export and ispromember(r.user): # pragma: no cover - uploadoptions['upload_to_SportTracks'] = True - - if r.trainingpeaks_auto_export and ispromember(r.user): # pragma: no cover - uploadoptions['upload_to_TrainingPeaks'] = True form = DocumentsForm(initial=docformoptions) optionsform = UploadOptionsForm(initial=uploadoptions, diff --git a/static/img/intervals_logo_with_name.png b/static/img/intervals_logo_with_name.png new file mode 100644 index 0000000000000000000000000000000000000000..b448dd4e6a12f8d5d9b8888035ce6ea20d3f3f26 GIT binary patch literal 18456 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 literal 0 HcmV?d00001