Merge branch 'release/v23.1.6'
This commit is contained in:
+31
-1
@@ -1274,7 +1274,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
pass
|
||||
|
||||
# recalculate power data
|
||||
if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides':
|
||||
if workouttype in otetypes:
|
||||
try:
|
||||
if r.erg_recalculatepower:
|
||||
row.erg_recalculatepower()
|
||||
@@ -1282,6 +1282,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
|
||||
@@ -1451,6 +1452,35 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
_ = update_wps(r, mytypes.otwtypes)
|
||||
_ = update_wps(r, mytypes.otetypes)
|
||||
|
||||
# set user running wps
|
||||
if not duplicate and workouttype in otetypes:
|
||||
cntr = Workout.objects.filter(user=r, workouttype__in=otetypes,
|
||||
startdatetime__gt=tz.now()-tz.timedelta(days=42),
|
||||
duplicate=False).count()
|
||||
new_value = (cntr*r.running_wps_erg + row.df['driveenergy'].mean())/(cntr+1.0)
|
||||
# if new_value is not zero or infinite or -inf, r.running_wps can be set to value
|
||||
if not (math.isnan(new_value) or math.isinf(new_value) or new_value == 0):
|
||||
r.running_wps_erg = new_value
|
||||
elif not (math.isnan(r.running_wps_erg) or math.isinf(r.running_wps_erg) or r.running_wps_erg == 0):
|
||||
pass
|
||||
else:
|
||||
r.running_wps_erg = 600.
|
||||
r.save()
|
||||
|
||||
if not duplicate and workouttype in otwtypes:
|
||||
cntr = Workout.objects.filter(user=r, workouttype__in=otwtypes,
|
||||
startdatetime__gt=tz.now()-tz.timedelta(days=42),
|
||||
duplicate=False).count()
|
||||
new_value = (cntr*r.running_wps_erg + row.df['driveenergy'].mean())/(cntr+1.0)
|
||||
if not (math.isnan(new_value) or math.isinf(new_value) or new_value == 0):
|
||||
r.running_wps = new_value
|
||||
elif not (math.isnan(r.running_wps) or math.isinf(r.running_wps) or r.running_wps == 0):
|
||||
pass
|
||||
else:
|
||||
r.running_wps = 400.
|
||||
r.save()
|
||||
|
||||
|
||||
_ = myqueue(queuehigh, handle_calctrimp, w.id, f2,
|
||||
r.ftp, r.sex, r.hrftp, r.max, r.rest)
|
||||
|
||||
|
||||
@@ -1226,6 +1226,10 @@ bulkactions = (
|
||||
('remove','remove'),
|
||||
('export','export'),
|
||||
('rower assign','rower assign'),
|
||||
('set commute','set commute'),
|
||||
('set private','set private'),
|
||||
('set public','set public'),
|
||||
('unset commute','unset commute'),
|
||||
)
|
||||
destinations = (
|
||||
('c2','c2'),
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ def create_contact(rower):
|
||||
|
||||
if res.status_code not in [200, 201]:
|
||||
dologging('idoklad.log','Contact Created - reason '+str(res.reason)+'\n')
|
||||
_ = myqueue.enqueue(
|
||||
_ = myqueue(
|
||||
queuehigh, handle_send_email_noinvoice,
|
||||
rower.user.email,
|
||||
rower.user.first_name,
|
||||
|
||||
@@ -1257,6 +1257,7 @@ class Rower(models.Model):
|
||||
verbose_name='Receive email notifications')
|
||||
|
||||
imports_are_private = models.BooleanField(default=False, verbose_name='Make imports private by default')
|
||||
show_commutes = models.BooleanField(default=False, verbose_name='Show commutes in workout list')
|
||||
|
||||
# Friends/Team
|
||||
friends = models.ManyToManyField("self", blank=True)
|
||||
@@ -1295,6 +1296,9 @@ class Rower(models.Model):
|
||||
fastpaceotw = models.DurationField(
|
||||
default=otwpacefast, verbose_name='Fastest OTW Pace')
|
||||
|
||||
running_wps = models.FloatField(default=400.0, verbose_name='Running Work per Stroke')
|
||||
running_wps_erg = models.FloatField(default=500.0, verbose_name='Running Work per Stroke (ergometer)')
|
||||
|
||||
fav_analysis = models.CharField(default='compare', choices=favanalysischoices,
|
||||
max_length=100,
|
||||
verbose_name='Favorite Analysis')
|
||||
@@ -5177,6 +5181,7 @@ class AccountRowerForm(ModelForm):
|
||||
'defaultlandingpage',
|
||||
'defaultlandingpage2',
|
||||
'defaultlandingpage3',
|
||||
'show_commutes',
|
||||
'offercoaching', 'autojoin', 'emailalternatives']
|
||||
|
||||
widgets = {
|
||||
|
||||
@@ -104,11 +104,15 @@
|
||||
{% endif %}
|
||||
|
||||
{% for workout in workouts %}
|
||||
{% if not workout.is_commute %}
|
||||
<li class="grid_4 divlines">
|
||||
{% if request.GET.selectworkouts %}
|
||||
<input type="checkbox" id="workoutid" value={{ workout.id|encode }} name="workoutid" />
|
||||
{% endif %}
|
||||
{{ workout.date|date:"Y-m-d" }} {{ workout.starttime|date:"H:i" }}
|
||||
{% if workout.privacy == 'hidden' %}
|
||||
<span style="font-size: smaller"><i class="fa-solid fa-eye-slash"></i></span>
|
||||
{% endif %}
|
||||
{% if workout.duplicate %}
|
||||
<span style="font-size: smaller"><i class="fal fa-angle-double-up"></i></span>
|
||||
{% endif %}
|
||||
@@ -198,6 +202,51 @@
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% elif user.rower.show_commutes %}
|
||||
<li class="grid_4 divlines">
|
||||
<div class="workoutcontainer">
|
||||
<div class="workoutelement">
|
||||
<span style="font-size: smaller"><i class="fa-solid fa-train"></i></span>
|
||||
</div>
|
||||
|
||||
<div class="workoutelement">
|
||||
<span style="color:#555">Distance</span>
|
||||
{{ workout.distance|distanceprint }}
|
||||
</div>
|
||||
<div class="workoutelement">
|
||||
<span style="color:#555">Time</span>
|
||||
{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
|
||||
</div>
|
||||
<div class="workoutelement">
|
||||
{% if workout|may_edit:request %}
|
||||
<a class="small"
|
||||
href={% url rower.defaultlandingpage id=workout.id|encode %}
|
||||
title="{{ rower.defaultlandingpage|verbose }}">
|
||||
<i class="{{ rower.defaultlandingpage|landingicon }}"></i></a>
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="workoutelement">
|
||||
{% if workout|may_edit:request %}
|
||||
{% if rower.defaultlandingpage2 != 'workout_delete' %}
|
||||
<a class="small"
|
||||
href={% url rower.defaultlandingpage2 id=workout.id|encode %}
|
||||
title="{{ rower.defaultlandingpage2|verbose }}">
|
||||
<i class="{{ rower.defaultlandingpage2|landingicon }}"></i></a>
|
||||
{% else %}
|
||||
<a class="small"
|
||||
href={% url rower.defaultlandingpage2 id=workout.id|encode %}
|
||||
title="{{ rower.defaultlandingpage2|verbose }}">
|
||||
<i class="{{ rower.defaultlandingpage2|landingicon }}"></i></a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
@@ -40,41 +40,58 @@
|
||||
<table class="listtable shortpadded" width=100%>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID </th><th>Zone Name</th><th>Lower Boundary (Watt) </th><th>Lower Boundary (Watt)</th>
|
||||
<th>ID </th>
|
||||
<th>Zone Name</th>
|
||||
<th>Lower Boundary (Watt) </th>
|
||||
<th>Lower Boundary (Watt)</th>
|
||||
<th>Target SPM</th>
|
||||
<th>Target SPM</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th><th></th><th>Indoor</th><th>OTW</th>
|
||||
<th></th><th></th><th>Indoor</th><th>OTW</th><th>Indoor</th><th>OTW</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td><td>{{ user.rower.powerzones.0 }}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td><td>{{ user.rower.powerzones.1 }}</td>
|
||||
<td>{{ user.rower.pw_ut2 }}</td>
|
||||
<td>{{ user.rower.pw_ut2|otwslack:user }}</td>
|
||||
<td><{{ user.rower.pw_ut1|target_spm_erg:user }}</td>
|
||||
<td><{{ user.rower.pw_ut1|target_spm_otw:user }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td><td>{{ user.rower.powerzones.2 }}</td>
|
||||
<td>{{ user.rower.pw_ut1 }}</td>
|
||||
<td>{{ user.rower.pw_ut1|otwslack:user }}</td>
|
||||
<td>{{ user.rower.pw_ut1|target_spm_erg:user }}-{{ user.rower.pw_at|target_spm_erg:user }}</td>
|
||||
<td>{{ user.rower.pw_ut1|target_spm_otw:user }}-{{ user.rower.pw_at|target_spm_otw:user }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td><td>{{ user.rower.powerzones.3 }}</td>
|
||||
<td>{{ user.rower.pw_at }}</td>
|
||||
<td>{{ user.rower.pw_at|otwslack:user }}</td>
|
||||
<td>{{ user.rower.pw_at|target_spm_erg:user }}-{{ user.rower.pw_tr|target_spm_erg:user }}</td>
|
||||
<td>{{ user.rower.pw_at|target_spm_otw:user }}-{{ user.rower.pw_tr|target_spm_otw:user }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td><td>{{ user.rower.powerzones.4 }}</td>
|
||||
<td>{{ user.rower.pw_tr }}</td>
|
||||
<td>{{ user.rower.pw_tr|otwslack:user }}</td>
|
||||
<td>{{ user.rower.pw_tr|target_spm_erg:user }}-{{ user.rower.pw_an|target_spm_erg:user }}</td>
|
||||
<td>{{ user.rower.pw_tr|target_spm_otw:user }}-{{ user.rower.pw_an|target_spm_otw:user }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>6</td><td>{{ user.rower.powerzones.5 }}</td>
|
||||
<td>{{ user.rower.pw_an }}</td>
|
||||
<td>{{ user.rower.pw_an|otwslack:user }}</td>
|
||||
<td>>{{ user.rower.pw_an|target_spm_erg:user }}</td>
|
||||
<td>>{{ user.rower.pw_an|target_spm_otw:user }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1065,3 +1065,15 @@ def previousworkout(workout, user):
|
||||
def otwslack(value, user):
|
||||
r = Rower.objects.get(user=user)
|
||||
return int(value*(100.-r.otwslack)/100.)
|
||||
|
||||
@register.filter
|
||||
def target_spm_erg(value, user):
|
||||
r = Rower.objects.get(user=user)
|
||||
value = 1.0*value
|
||||
return int(value*60/r.running_wps_erg)
|
||||
|
||||
@register.filter
|
||||
def target_spm_otw(value, user):
|
||||
r = Rower.objects.get(user=user)
|
||||
value = value*(100.-r.otwslack)/100.
|
||||
return int(value*60/r.running_wps)
|
||||
|
||||
BIN
Binary file not shown.
@@ -605,13 +605,11 @@ def strokedata_fit(request):
|
||||
name=title,
|
||||
date=startdate,
|
||||
)
|
||||
# workouttype='water',)
|
||||
|
||||
uploadoptions = {
|
||||
'secret': UPLOAD_SERVICE_SECRET,
|
||||
'user': request.user.id,
|
||||
'file': fit_filename,
|
||||
'workouttype': 'water',
|
||||
'boattype': '1x',
|
||||
'title': title,
|
||||
'rpe': 0,
|
||||
|
||||
@@ -429,12 +429,6 @@ def rower_exportsettings_view(request, userid=0):
|
||||
}
|
||||
if form.is_valid():
|
||||
cd = form.cleaned_data
|
||||
if r.rowerplan == 'basic': # pragma: no cover
|
||||
messages.error(
|
||||
request, 'This setting will only be effective if you are a user \
|
||||
on one of the <a href="/rowers/paidplans">paid plans</a> \
|
||||
or part of a coaching group.')
|
||||
|
||||
for attr, value in cd.items():
|
||||
doset = True
|
||||
try:
|
||||
|
||||
@@ -2067,6 +2067,22 @@ def workouts_bulk_actions(request):
|
||||
for w in workouts:
|
||||
messages.info(request,'Removed workout '+str(encoder.encode_hex(w.id)))
|
||||
w.delete()
|
||||
elif action == 'set private':
|
||||
for w in workouts:
|
||||
w.privacy = 'private'
|
||||
w.save()
|
||||
elif action == 'set commute':
|
||||
for w in workouts:
|
||||
w.is_commute = True
|
||||
w.save()
|
||||
elif action == 'unset commute':
|
||||
for w in workouts:
|
||||
w.is_commute = False
|
||||
w.save()
|
||||
elif action == 'set public':
|
||||
for w in workouts:
|
||||
w.privacy = 'public'
|
||||
w.save()
|
||||
elif action == 'export':
|
||||
exportchoice = ExportChoices(request.POST)
|
||||
if exportchoice.is_valid():
|
||||
|
||||
Reference in New Issue
Block a user