From 3b6c2cf84b618b47dfca091370fae8b0d0ae4e6b Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Mon, 8 Feb 2021 08:23:46 +0100
Subject: [PATCH 1/6] hr pie chart label now with new hR zones
---
rowers/interactiveplots.py | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index 9374b4eb..3887e29d 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -230,7 +230,7 @@ def interactive_hr_piechart(df,rower,title,totalseconds=0):
if totalseconds == 0:
totalseconds = sumtimehr
-
+ hrzones = rower.hrzones
qry = 'hr < {ut2}'.format(ut2=rower.ut2)
qrydata = df.query(qry)
@@ -253,12 +253,12 @@ def interactive_hr_piechart(df,rower,title,totalseconds=0):
frac_an = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
datadict = {
- '
Date: Tue, 9 Feb 2021 08:28:00 +0100
Subject: [PATCH 2/6] fix #607
---
rowers/templates/flexchartstacked.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rowers/templates/flexchartstacked.html b/rowers/templates/flexchartstacked.html
index 11a54331..665453ac 100644
--- a/rowers/templates/flexchartstacked.html
+++ b/rowers/templates/flexchartstacked.html
@@ -21,11 +21,11 @@
{% if workout|previousworkout:rower.user %}
- Previous
{% endif %}
{% if workout|nextworkout:rower.user %}
- Next
{% endif %}
From 4b463f472ab46bd5844f0dfb0d6c82a7946c9eee Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 9 Feb 2021 08:32:40 +0100
Subject: [PATCH 3/6] fix #605
---
rowers/dataprep.py | 3 +++
rowers/templates/splitworkout.html | 12 ++++++------
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index 5aa8720d..8a13960f 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -2255,6 +2255,7 @@ def new_workout_from_df(r, df,
boattype = parent.boattype
notes = parent.notes
summary = parent.summary
+ rpe = parent.rpe
if parent.privacy == 'hidden':
makeprivate = True
else:
@@ -2267,6 +2268,7 @@ def new_workout_from_df(r, df,
notes = ''
summary = ''
makeprivate = False
+ rpe = 0
if startdatetime == '':
startdatetime = timezone.now()
@@ -2305,6 +2307,7 @@ def new_workout_from_df(r, df,
inboard=inboard,
makeprivate=makeprivate,
dosmooth=False,
+ rpe=rpe,
consistencychecks=False)
job = myqueue(queuehigh,handle_calctrimp,id,csvfilename,r.ftp,r.sex,r.hrftp,r.max,r.rest)
diff --git a/rowers/templates/splitworkout.html b/rowers/templates/splitworkout.html
index b07c1a54..5c93f159 100644
--- a/rowers/templates/splitworkout.html
+++ b/rowers/templates/splitworkout.html
@@ -7,7 +7,7 @@
{% block main %}
Split Workout
-
+
{% localtime on %}
-
+
-
+
{{ thescript |safe }}
-
+
{{ thediv |safe }}
@@ -67,7 +67,7 @@
-
+
{% endblock %}
From 7295e0e70d31360d56f852511c0ba3ac05f1413d Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 9 Feb 2021 08:39:52 +0100
Subject: [PATCH 4/6] implemented subscription_cancel
---
rowers/braintreestuff.py | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py
index 3c7020f2..3bc7546b 100644
--- a/rowers/braintreestuff.py
+++ b/rowers/braintreestuff.py
@@ -64,6 +64,20 @@ def process_webhook(notification):
f.write(timestamp+' '+notification.kind+'\n')
if notification.kind == 'subscription_charged_successfully':
return send_invoice(notification.subscription)
+ if notification.kind == 'subscription_canceled':
+ subscription = notification.subscription
+ rs = Rower.objects.filter(subscription_id=subscription.id)
+ if rs.count() == 0:
+ return 0
+ r = rs[0]
+ result,mesg,errormsg = cancel_subscription(r,subscription.id)
+ if result:
+ with open('braintreewebhooks.log','a') as f:
+ f.write('Subscription canceled: '+subscription.id+'\n')
+ return subscription.id
+ with open('braintreewebhooks.log','a') as f:
+ f.write('Could not cancel Subscription: '+subscription.id+'\n')
+ return 0
return 0
def send_invoice(subscription):
From d0ecd7ceead8047cff142504ff4d7bd7ce35a67e Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 9 Feb 2021 17:32:55 +0100
Subject: [PATCH 5/6] first version erase column
---
rowers/templates/workout_data.html | 20 +++-
rowers/templates/workout_erase_column.html | 44 ++++++++
rowers/templatetags/rowerfilters.py | 11 ++
rowers/urls.py | 2 +
rowers/views/workoutviews.py | 120 +++++++++++++++++++++
5 files changed, 195 insertions(+), 2 deletions(-)
create mode 100644 rowers/templates/workout_erase_column.html
diff --git a/rowers/templates/workout_data.html b/rowers/templates/workout_data.html
index a259bb35..a5ce5581 100644
--- a/rowers/templates/workout_data.html
+++ b/rowers/templates/workout_data.html
@@ -17,8 +17,24 @@
-
- {{ htmltable|safe }}
+
+
+ |
+ {% for i in cols %}
+ | {{i}} erase |
+ {% endfor %}
+
+ {% for row in data.values.tolist %}
+
+ |
+ {{ forloop.counter0 }}
+ |
+ {% for value in row %}
+ {{ value }} |
+ {% endfor %}
+
+ {% endfor %}
+
diff --git a/rowers/templates/workout_erase_column.html b/rowers/templates/workout_erase_column.html
new file mode 100644
index 00000000..12d13549
--- /dev/null
+++ b/rowers/templates/workout_erase_column.html
@@ -0,0 +1,44 @@
+{% extends "newbase.html" %}
+{% load staticfiles %}
+{% load rowerfilters %}
+
+{% block title %}Workout Data{% endblock %}
+
+{% block main %}
+Erase {{ column }} for {{ workout.name }}
+
+
+ -
+
+ This will erase column {{ column }} from the following workout:
+
+
+
+ | Name: | {{ workout.name }} |
+
+ | Date: | {{ workout.date }} |
+
+ | Time: | {{ workout.starttime }} |
+
+ | Distance: | {{ workout.distance }}m |
+
+ | Duration: | {{ workout.duration |durationprint:"%H:%M:%S.%f" }} |
+
+
+
+ The data cannot be recovered. If you are sure, please confirm.
+
+
+ -
+
+
+
+
+{% endblock %}
+
+{% block sidebar %}
+{% include 'menu_workout.html' %}
+{% endblock %}
diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py
index dd33bcf1..7cc4d99c 100644
--- a/rowers/templatetags/rowerfilters.py
+++ b/rowers/templatetags/rowerfilters.py
@@ -85,6 +85,10 @@ def icon(s):
except KeyError:
return 'fa-chart-line'
+@register.filter
+def datarows(data):
+ return range(len(data))
+
@register.filter
def adaptive(s):
u = s
@@ -519,11 +523,18 @@ def mayeditplan(obj,request):
return mayedit
+@register.filter
+def iterrows(df):
+ return df.iterrows()
@register.filter(name='times')
def times(number):
return range(number)
+@register.simple_tag
+def get_df_iloc(data,i,j):
+ return data.iloc(i,j)
+
@register.simple_tag
def get_field_id(id,s,form):
field_name = s+str(id)
diff --git a/rowers/urls.py b/rowers/urls.py
index de7a0fb2..c3bda9e1 100644
--- a/rowers/urls.py
+++ b/rowers/urls.py
@@ -463,6 +463,8 @@ urlpatterns = [
re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/stats/$',views.workout_stats_view,name='workout_stats_view'),
re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/data/$',views.workout_data_view,
name='workout_data_view'),
+ re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/(?P\w+)/erase/$',views.workout_erase_column_view,
+ name='workout_erase_column_view'),
re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/zeropower-confirm/$',views.remove_power_confirm_view,
name='remove_power_confirm_view'),
re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/zeropower/$',views.remove_power_view,
diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py
index 867c5a20..bdc0a05c 100644
--- a/rowers/views/workoutviews.py
+++ b/rowers/views/workoutviews.py
@@ -3166,6 +3166,124 @@ def instroke_chart(request,id=0,metric=''):
return HttpResponseRedirect(url)
+# erase column
+@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
+def workout_erase_column_view(request, id=0,column=''):
+ r = getrower(request.user)
+ w = get_workoutuser(id,request)
+
+ protected = ['time','pace','velo','cumdist','ftime','fpace',]
+ if column in protected:
+ messages.error(request,'You cannot erase this protected column')
+ url = reverse('workout_data_view',kwargs={
+ 'id':encoder.encode_hex(w.id)
+ })
+
+ return HttpResponseRedirect(url)
+
+ try:
+ data = dataprep.getsmallrowdata_db([column],ids=[w.id])
+ except:
+ messages.error(request,'Invalid column')
+ url = reverse('workout_data_view',kwargs={
+ 'id':encoder.encode_hex(w.id)
+ })
+
+ return HttpResponseRedirect(url)
+
+ try:
+ cdata = data[column]
+ except KeyError:
+ url = reverse('workout_data_view',kwargs={
+ 'id':encoder.encode_hex(w.id)
+ })
+
+ return HttpResponseRedirect(url)
+
+
+ if not column:
+ url = reverse('workout_data_view',kwargs={
+ 'id':encoder.encode_hex(w.id)
+ })
+
+ return HttpResponseRedirect(url)
+
+ if request.method == 'POST':
+
+ mms = {}
+ for m in rowingmetrics:
+ mms[m[0]] = m[1]
+
+ try:
+ defaultvalue = mms[column]['default']
+ except KeyError:
+ if not mms[column]['null']:
+ messages.error(request,'You cannot erase this protected column')
+ url = reverse('workout_data_view',kwargs={
+ 'id':encoder.encode_hex(w.id)
+ })
+
+ return HttpResponseRedirect(url)
+ defaultvalue = 0
+
+ try:
+ columnl = dataprep.columndict[column]
+ except KeyError:
+ messages.error(request,'You cannot erase this column')
+ url = reverse('workout_data_view',kwargs={
+ 'id':encoder.encode_hex(w.id)
+ })
+
+ return HttpResponseRedirect(url)
+
+ row,workout = dataprep.getrowdata(id=w.id)
+ row.df[columnl] = defaultvalue
+ print(row.df[columnl])
+ row.write_csv(w.csvfilename,gzip=True)
+
+ datadf = dataprep.dataprep(row.df,id=w.id)
+
+
+ messages.info(request,'Data for column '+column+' have been erased')
+ url = reverse('workout_data_view',kwargs={
+ 'id':encoder.encode_hex(w.id)
+ })
+
+ return HttpResponseRedirect(url)
+
+
+ breadcrumbs = [
+ {
+ 'url':'/rowers/list-workouts/',
+ 'name':'Workouts'
+ },
+ {
+ 'url':get_workout_default_page(request,id),
+ 'name': w.name
+ },
+ {
+ 'url':reverse('workout_data_view',kwargs={'id':id}),
+ 'name': 'Data Explorer'
+ }
+
+ ]
+
+ return render(request,
+ 'workout_erase_column.html',
+ {
+ 'column':column,
+ 'teams':get_my_teams(request.user),
+ 'workout': w,
+ 'breadcrumbs': breadcrumbs,
+
+ }
+ )
+
+
+
+
+
+
# data explorer
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@@ -3268,6 +3386,8 @@ def workout_data_view(request, id=0):
'workout_data.html',
{
'htmltable': htmltable,
+ 'data':datadf,
+ 'cols':datadf.columns,
'form':form,
'teams':get_my_teams(request.user),
'workout': w,
From f1fb46d0e14411cc31ef8f5316bbf33f0ce9db30 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 9 Feb 2021 18:35:19 +0100
Subject: [PATCH 6/6] fix some bugs
---
rowers/dataprep.py | 12 ++++++------
rowers/views/workoutviews.py | 25 +++++++++++++++++++++++--
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index 8a13960f..b8ed1b36 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -1061,8 +1061,8 @@ def get_workoutsummaries(userid,startdate):
return df
-def workout_goldmedalstandard(workout):
- if workout.goldmedalstandard > 0:
+def workout_goldmedalstandard(workout,reset=False):
+ if workout.goldmedalstandard > 0 and not reset:
return workout.goldmedalstandard,workout.goldmedalseconds
if workout.workouttype in rowtypes:
goldmedalstandard,goldmedalseconds = calculate_goldmedalstandard(workout.user,workout)
@@ -3018,10 +3018,10 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
-def workout_trimp(w):
+def workout_trimp(w,reset=False):
r = w.user
- if w.trimp > 0:
+ if w.trimp > 0 and not reset:
return w.trimp,w.hrtss
r = w.user
@@ -3062,8 +3062,8 @@ def workout_trimp(w):
return 0,0
-def workout_rscore(w):
- if w.rscore > 0:
+def workout_rscore(w,reset=False):
+ if w.rscore > 0 and not reset:
return w.rscore,w.normp
r = w.user
diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py
index bdc0a05c..d9a2b063 100644
--- a/rowers/views/workoutviews.py
+++ b/rowers/views/workoutviews.py
@@ -3236,13 +3236,34 @@ def workout_erase_column_view(request, id=0,column=''):
return HttpResponseRedirect(url)
+
row,workout = dataprep.getrowdata(id=w.id)
row.df[columnl] = defaultvalue
- print(row.df[columnl])
- row.write_csv(w.csvfilename,gzip=True)
+ os.remove(w.csvfilename+'.gz')
+
+ row.write_csv(w.csvfilename,gzip=True)
+
+
+ row,workout = dataprep.getrowdata(id=w.id)
datadf = dataprep.dataprep(row.df,id=w.id)
+ if column == 'hr':
+ w.hrtss = 0
+ w.trimp = 0
+ w.save()
+
+ if column == 'power':
+ w.rscore = 0
+ w.normp = 0
+ w.goldmedalstandard = -1
+ w.goldmedalseconds = 0
+ w.save()
+
+ trimp,hrtss = dataprep.workout_trimp(w,reset=True)
+ rscore,normp = dataprep.workout_rscore(w,reset=True)
+ goldstandard,goldstandardduration = dataprep.workout_goldmedalstandard(w,reset=True)
+
messages.info(request,'Data for column '+column+' have been erased')
url = reverse('workout_data_view',kwargs={