diff --git a/rowers/forms.py b/rowers/forms.py
index 2db9b8bf..face5583 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -1232,10 +1232,11 @@ bulkactions = (
('unset commute','unset commute'),
)
destinations = (
- ('c2','c2'),
+ ('c2','concept2'),
('strava','strava'),
('sporttracks','sporttracks'),
- ('trainingpeaks','trainingpeaks')
+ ('trainingpeaks','trainingpeaks'),
+ ('intervals','intervals.icu')
)
class WorkoutBulkActions(forms.Form):
diff --git a/rowers/integrations/trainingpeaks.py b/rowers/integrations/trainingpeaks.py
index cd3b6bb4..e56095c7 100644
--- a/rowers/integrations/trainingpeaks.py
+++ b/rowers/integrations/trainingpeaks.py
@@ -79,13 +79,17 @@ class TPIntegration(SyncIntegration):
def workout_export(self, workout, *args, **kwargs) -> str:
thetoken = self.open()
tcxfilename = self.createworkoutdata(workout)
+ try:
+ wtype = tpmapping[workout.workouttype]
+ except KeyError:
+ wtype = 'rowing'
job = myqueue(
queue,
handle_workout_tp_upload,
workout,
thetoken,
tcxfilename,
- tpmapping[workout.workouttype]
+ wtype
)
return job.id
diff --git a/rowers/models.py b/rowers/models.py
index b805b234..b69cb380 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -2755,6 +2755,12 @@ class PlannedSessionStep(models.Model):
return d
+ # string
+ def __str__(self):
+ str = 'Step {id} {name} {intensity}'.format(id=self.pk, name=self.name, intensity=self.intensity)
+
+ return str
+
class StepEditorForm(ModelForm):
class Meta:
model = PlannedSessionStep
diff --git a/rowers/templates/stepeditor.html b/rowers/templates/stepeditor.html
index efc9daf1..9500219b 100644
--- a/rowers/templates/stepeditor.html
+++ b/rowers/templates/stepeditor.html
@@ -20,9 +20,9 @@
-Training Steps for {{ ps.name }}
${name}
${txt}
` + const div = document.getElementById("stepinfo"); + div.innerHTML = divstring; + } + } + + return false; + } + + function handleMouseLeave(event) { if (event.preventDefault) { - const id = event.target.id; - if (id) { - var name = mysteps[id]['name']; - var txt = descriptions[id]; - var divstring = `${name}
${txt}
` const div = document.getElementById("stepinfo"); - div.innerHTML = divstring; - } + div.innerHTML = 'Hover over a step to get details
' } return false; - } - - function handleMouseLeave(event) { - if (event.preventDefault) { - const div = document.getElementById("stepinfo"); - div.innerHTML = 'Hover over a step to get details
' - } - - return false; - } - - function handleDragOver(event) { + } + + function handleDragOver(event) { event.preventDefault(); - } - - function handleDragEnter(event) { + } + + function handleDragEnter(event) { this.classList.add('over'); const target = event.target; overcolor = event.target.style.backgroundColor; - + if (target && dragged) { - event.preventDefault(); - // Set the dropEffect to move - event.dataTransfer.dropEffect = 'move' - target.style.background = '#1f904e'; + event.preventDefault(); + // Set the dropEffect to move + event.dataTransfer.dropEffect = 'move' + target.style.background = '#1f904e'; } - } - - function handleDragLeave(event) { + } + + function handleDragLeave(event) { event.target.style.backgroundColor = ''; - + if (dragged.parentNode.className.includes("drop-zone")) { - trash(event); + trash(event); } saveState(); - } - - function trash(event) { + } + + function trash(event) { const target = event.target; event.target.style.backgroundColor = ''; if (target && dragged) { - event.preventDefault(); - if (dragged.parentNode.className.includes("drop-zone")) { - dragged.remove(); - } + event.preventDefault(); + if (dragged.parentNode.className.includes("drop-zone")) { + dragged.remove(); + } } - } - - function handleDrop(event) { + } + + function handleDrop(event) { const target = event.target; if (target && dragged) { - target.style.backgroundColor = ''; - event.preventDefault(); - // Get the id of the target and add the moved element to the target's DOM - // dragged.parentNode.removeChild(dragged); - if (target.nodeName == "SECTION") { - dragged.style.opacity = ''; - dragged.style.backgroundColor = origcolor; - var dropped = dragged.cloneNode(true); - dropped.id = 0; - target.appendChild(dropped); - } - if (target.nodeName == 'DIV') { - // insert after - dragged.style.opacity = ''; - dragged.style.backgroundColor = origcolor; - var dropped = dragged.cloneNode(true); - if (target.parentNode.nodeName == 'SECTION') { - target.after(dropped); + target.style.backgroundColor = ''; + event.preventDefault(); + // Get the id of the target and add the moved element to the targets DOM + // dragged.parentNode.removeChild(dragged); + if (target.nodeName == "SECTION") { + dragged.style.opacity = ''; + dragged.style.backgroundColor = origcolor; + var dropped = dragged.cloneNode(true); + dropped.id = 0; + target.appendChild(dropped); } - if (target.parentNode.parentNode.nodeName == 'SECTION') { - target.parentNode.after(dropped); + if (target.nodeName == 'DIV') { + // insert after + dragged.style.opacity = ''; + dragged.style.backgroundColor = origcolor; + var dropped = dragged.cloneNode(true); + if (target.parentNode.nodeName == 'SECTION') { + target.after(dropped); + } + if (target.parentNode.parentNode.nodeName == 'SECTION') { + target.parentNode.after(dropped); + } } - } } saveState(); } - + function noDrop(event) { - event.preventDefault(); + event.preventDefault(); } - - - let dropzone = document.querySelector('.drop-zone') - dropzone.addEventListener('dragenter', handleDragEnter); - dropzone.addEventListener('dragleave', handleDragLeave); - dropzone.addEventListener('drop', handleDrop) - dropzone.addEventListener('dragover', handleDragOver); - dropzone.addEventListener('dragstart', handleDragStart); - dropzone.addEventListener('dragend', handleDragEnd); - - let items = document.querySelectorAll('.stepcontainer .trainingstep'); - items.forEach(function(item) { + + + let dropzone = document.querySelector('.drop-zone') + dropzone.addEventListener('dragenter', handleDragEnter); + dropzone.addEventListener('dragleave', handleDragLeave); + dropzone.addEventListener('drop', handleDrop) + dropzone.addEventListener('dragover', handleDragOver); + dropzone.addEventListener('dragstart', handleDragStart); + dropzone.addEventListener('dragend', handleDragEnd); + + let items = document.querySelectorAll('.stepcontainer .trainingstep'); + items.forEach(function(item) { item.addEventListener('dragstart', handleDragStart); item.addEventListener('dragend', handleDragEnd); item.addEventListener('dragleave', handleDragLeave); @@ -392,10 +395,10 @@ item.addEventListener('dragenter',noDrop); item.addEventListener('mouseover',handleMouseOver); item.addEventListener('mouseleave',handleMouseLeave); - }); - - - + }); + + + {% endblock %} {% block sidebar %} diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 415ce353..8c06d57a 100644 Binary files a/rowers/tests/testdata/testdata.tcx.gz and b/rowers/tests/testdata/testdata.tcx.gz differ diff --git a/rowers/uploads.py b/rowers/uploads.py index 48f54ede..06273c63 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -130,6 +130,9 @@ def make_plot(r, w, f1, f2, plottype, title, imagename='', plotnr=0): def do_sync(w, options, quick=False): + if w.duplicate: + return 0 + do_strava_export = False if w.user.strava_auto_export is True: do_strava_export = True @@ -236,8 +239,6 @@ def do_sync(w, options, quick=False): except KeyError: pass - if w.duplicate: - return 0 if do_c2_export: # pragma: no cover dologging('c2_log.log','Exporting workout to C2 for user {user}'.format(user=w.user.user.id)) @@ -305,7 +306,6 @@ def do_sync(w, options, quick=False): except NoTokenError: dologging('st_export.log','No Token Error') - return 0 do_tp_export = w.user.trainingpeaks_auto_export try: @@ -315,6 +315,8 @@ def do_sync(w, options, quick=False): do_tp_export = upload_to_tp except KeyError: upload_to_st = False + + if do_tp_export: try: tp_integration = TPIntegration(w.user.user) @@ -327,7 +329,6 @@ def do_sync(w, options, quick=False): ) except NoTokenError: dologging('tp_export.log','No Token Error') - return 0 # we do Strava last. if do_strava_export: # pragma: no cover diff --git a/rowers/utils.py b/rowers/utils.py index 0072805b..070f1a45 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -740,6 +740,10 @@ def steps_write_fit(steps): # convert to json, value of keys called wkt_step_name to string for step in steps['steps']: step['wkt_step_name'] = str(step['wkt_step_name']) + # convert numerical values in the dict to integers + for key in step.keys(): + if isinstance(step[key], (int, float)): + step[key] = int(step[key]) response = requests.post(url=url, headers=headers, json=steps) diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index 33255a17..5833c5a5 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -3077,6 +3077,7 @@ def rower_create_trainingplan(request, id=0): 'old_targets': old_targets, }) +@csrf_exempt @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) @@ -3116,6 +3117,7 @@ def stepadder(request, id=0): 'message': 'permission denied for host '+hostt[0]} return JSONResponse(status=403, data=message) + if ps.steps: filename = ps.steps.get('filename','') sport = ps.steps.get('sport','rowing') @@ -3202,12 +3204,13 @@ def stepedit(request, id=0, psid=0): if form.cleaned_data['durationtype'] == 'Time': ss['durationValue'] = form.cleaned_data['durationvalue']*60000 elif form.cleaned_data['durationtype'] == 'Distance': - ss[durationValue] = form.cleaned_data['durationvalue']*100 + ss['durationValue'] = form.cleaned_data['durationvalue']*100 ss['durationValue'] = int(ss['durationValue']) ps.fitfile = None ps.interval_string = "" + ps.save() step.durationtype = form.cleaned_data['durationtype'] diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 31864c0d..b8dd6c72 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -2044,6 +2044,12 @@ def workouts_bulk_actions(request): workoutids = request.session.get('ids',[]) workouts = [] exportchoice = 'strava' + + # exportchoice = ExportChoices() + actionform = WorkoutBulkActions() + actionform.fields["action"].initial = action + assignchoices = AssignChoices() + try: for encid in workoutids: w = get_workout_by_opaqueid(request, encid) @@ -2286,8 +2292,7 @@ def workouts_view(request, message='', successmessage='', (Q(name__icontains=q) for q in query_list)) | reduce(operator.and_, (Q(notes__icontains=q) for q in query_list)), - exclude_strava=False, - ) + ).exclude(workoutsource='strava') searchform = SearchForm(initial={'q': query}) else: searchform = SearchForm()