Merge branch 'release/v23.1.14'
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
<section class="drop-zone">
|
||||
<h2>Training Steps for {{ ps.name }}</h2>
|
||||
<p>
|
||||
<form onsubmit="event.preventDefault(); saveSession();">
|
||||
<input id="hidden" type="hidden" value="">
|
||||
<input id="savebutton" type="submit" value="Save">
|
||||
<form target="/rowers/plans/stepadder/{{ ps.id}}/?save=1" onsubmit="event.preventDefault(); saveSession();">
|
||||
<input id="hidden" type="hidden" value="">
|
||||
<input id="savebutton" type="submit" value="Save">
|
||||
</form>
|
||||
</p>
|
||||
{% for step in currentsteps %}
|
||||
@@ -175,216 +175,219 @@
|
||||
descriptions["{{ key }}"] = "{{ value }}"
|
||||
{% endfor %}
|
||||
$(document).ready(function() {
|
||||
csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
});
|
||||
function csrfSafeMethod(method) {
|
||||
// these HTTP methods do not require CSRF protection
|
||||
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||
// these HTTP methods do not require CSRF protection
|
||||
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||
}
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let dragged;
|
||||
let origcolor;
|
||||
|
||||
function saveSession() {
|
||||
|
||||
|
||||
let dragged;
|
||||
let origcolor;
|
||||
|
||||
function saveSession() {
|
||||
|
||||
var list = [];
|
||||
steps = document.querySelector('.drop-zone');
|
||||
steps.childNodes.forEach(function(item) {
|
||||
if (item.className && item.className.includes("trainingstep")) {
|
||||
item.childNodes.forEach(function(child) {
|
||||
if (child.id && child.className == 'stepcontent') {
|
||||
list.push(child.id);
|
||||
}
|
||||
})
|
||||
}
|
||||
if (item.className && item.className.includes("trainingstep")) {
|
||||
item.childNodes.forEach(function(child) {
|
||||
if (child.id && child.className == 'stepcontent') {
|
||||
list.push(child.id);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
data: JSON.stringify(list),
|
||||
type: 'POST',
|
||||
url: '/rowers/plans/stepadder/{{ ps.id }}/?save=1',
|
||||
error: function(result) {
|
||||
$("#id_waiting").replaceWith(
|
||||
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
||||
);
|
||||
},
|
||||
success: function(result) {
|
||||
console.log(result)
|
||||
}
|
||||
})
|
||||
window.location.reload(true);
|
||||
}
|
||||
data: JSON.stringify(list),
|
||||
type: 'POST',
|
||||
url: '/rowers/plans/stepadder/{{ ps.id }}/?save=1',
|
||||
error: function(result) {
|
||||
$("#id_waiting").replaceWith(
|
||||
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
||||
);
|
||||
},
|
||||
success: function(result) {
|
||||
console.log(result)
|
||||
}
|
||||
})
|
||||
saveState();
|
||||
// reload the page
|
||||
location.reload();
|
||||
// window.location.reload(true);
|
||||
}
|
||||
|
||||
function saveState() {
|
||||
function saveState() {
|
||||
var cntr = 0;
|
||||
var list = [];
|
||||
steps = document.querySelector('.drop-zone');
|
||||
steps.childNodes.forEach(function(item) {
|
||||
if (item.className && item.className.includes("trainingstep")) {
|
||||
item.childNodes.forEach(function(child) {
|
||||
if (child.id && child.className == 'stepcontent') {
|
||||
list.push(child.id);
|
||||
}
|
||||
if (child.className == "stepid") {
|
||||
s = `(${cntr})`
|
||||
child.replaceWith(s);
|
||||
cntr++;
|
||||
}
|
||||
})
|
||||
}
|
||||
if (item.className && item.className.includes("trainingstep")) {
|
||||
item.childNodes.forEach(function(child) {
|
||||
if (child.id && child.className == 'stepcontent') {
|
||||
list.push(child.id);
|
||||
}
|
||||
if (child.className == "stepid") {
|
||||
s = `(${cntr})`
|
||||
child.replaceWith(s);
|
||||
cntr++;
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
data: JSON.stringify(list),
|
||||
type: 'POST',
|
||||
url: '/rowers/plans/stepadder/{{ ps.id }}/',
|
||||
error: function(result) {
|
||||
$("#id_waiting").replaceWith(
|
||||
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
||||
);
|
||||
},
|
||||
success: function(result) {
|
||||
console.log(result)
|
||||
}
|
||||
})
|
||||
data: JSON.stringify(list),
|
||||
type: 'POST',
|
||||
url: '/rowers/plans/stepadder/{{ ps.id }}/',
|
||||
error: function(result) {
|
||||
$("#id_waiting").replaceWith(
|
||||
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
||||
);
|
||||
},
|
||||
success: function(result) {
|
||||
console.log(result)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
function handleDragStart(event) {
|
||||
|
||||
function handleDragStart(event) {
|
||||
let target = event.target;
|
||||
if (target) {
|
||||
dragged = target;
|
||||
origcolor = dragged.style.backgroundColor;
|
||||
event.dataTransfer.setData('text', target.id);
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
// Make it half transparent
|
||||
event.target.style.opacity = .3;
|
||||
dragged = target;
|
||||
origcolor = dragged.style.backgroundColor;
|
||||
event.dataTransfer.setData('text', target.id);
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
// Make it half transparent
|
||||
event.target.style.opacity = .3;
|
||||
}
|
||||
}
|
||||
|
||||
function handleDragEnd(event) {
|
||||
}
|
||||
|
||||
function handleDragEnd(event) {
|
||||
if (event.target) {
|
||||
// Reset the transparency
|
||||
event.target.style.opacity = ''; // reset opacity when drag ends
|
||||
items.forEach(function (item) {
|
||||
item.classList.remove('over');
|
||||
});
|
||||
dragged = null;
|
||||
origcolor = null;
|
||||
// Reset the transparency
|
||||
event.target.style.opacity = ''; // reset opacity when drag ends
|
||||
items.forEach(function (item) {
|
||||
item.classList.remove('over');
|
||||
});
|
||||
dragged = null;
|
||||
origcolor = null;
|
||||
}
|
||||
saveState();
|
||||
}
|
||||
|
||||
function handleMouseOver(event) {
|
||||
}
|
||||
|
||||
function handleMouseOver(event) {
|
||||
if (event.preventDefault) {
|
||||
const id = event.target.id;
|
||||
if (id) {
|
||||
var name = mysteps[id]['name'];
|
||||
var txt = descriptions[id];
|
||||
var divstring = `<p>${name}</p><p>${txt}</p>`
|
||||
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 = `<p>${name}</p><p>${txt}</p>`
|
||||
const div = document.getElementById("stepinfo");
|
||||
div.innerHTML = divstring;
|
||||
}
|
||||
div.innerHTML = '<p>Hover over a step to get details</p>'
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleMouseLeave(event) {
|
||||
if (event.preventDefault) {
|
||||
const div = document.getElementById("stepinfo");
|
||||
div.innerHTML = '<p>Hover over a step to get details</p>'
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
|
||||
BIN
rowers/tests/testdata/testdata.tcx.gz
vendored
BIN
rowers/tests/testdata/testdata.tcx.gz
vendored
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user