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): diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 5aa8720d..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) @@ -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) @@ -3015,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 @@ -3059,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/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 = { - ' {% if workout|previousworkout:rower.user %} - Previous  {% endif %} {% if workout|nextworkout:rower.user %} - Next {% endif %}

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 %} 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 }}

+ + + +{% 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..d9a2b063 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -3166,6 +3166,145 @@ 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 + 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={ + '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 +3407,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,