From 3bbc014c42b1a747e7d607d567e76e49eda016bf Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 14 Jun 2018 08:35:52 +0200 Subject: [PATCH 1/4] user admin better organized --- rowers/admin.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/rowers/admin.py b/rowers/admin.py index f18a3760..cd14f468 100644 --- a/rowers/admin.py +++ b/rowers/admin.py @@ -18,10 +18,48 @@ class RowerInline(admin.StackedInline): verbose_name_plural = 'rower' filter_horizontal = ('team','friends') + fieldsets = ( + ('Rower Plan', + {'fields':('rowerplan','teamplanexpires','clubsize','protrialexpires','plantrialexpires',)}), + ('Rower Settings', + {'fields': + ('gdproptin','gdproptindate','weightcategory','sex','birthdate','getemailnotifications', + 'getimportantemails','emailbounced','defaultlandingpage', + 'defaulttimezone','showfavoritechartnotes')}), + ('Rower Zones', + {'fields': + ('ftp','otwslack','pw_ut2','pw_ut1','pw_at','pw_tr','pw_an','max', + 'rest','ut2','ut1','at','tr','an','hrftp',)}), + ('Import/Export Keys', + {'fields':('c2token','tokenexpirydate','c2refreshtoken','c2_auto_export', + 'sporttrackstoken','sporttrackstokenexpirydate','sporttracksrefreshtoken', + 'sporttracks_auto_export', + 'underarmourtoken','underarmourtokenexpirydate','underarmourrefreshtoken', + 'mapmyfitness_auto_export', + 'tptoken','tptokenexpirydate','tprefreshtoken', + 'trainingpeaks_auto_export', + 'polartoken','polartokenexpirydate','polarrefreshtoken','polaruserid', + 'polar_auto_import', + 'stravatoken','stravaexportas','strava_auto_export', + 'runkeepertoken','runkeeper_auto_export',)}), + ('Team', + {'fields':('friends','privacy','team')}), + ) + + #class UserAdmin(UserAdmin): class UserAdmin(admin.ModelAdmin): inlines = (RowerInline,) list_display = ('username','email','first_name','last_name','rowerplan') + + fieldsets = ( + ('Personal info', + {'fields': + ('first_name', 'last_name', 'email', 'date_joined', 'last_login',)}), + ('Permissions', + {'fields': + ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions',)}),) + search_fields = ["username","first_name","last_name","email"] def rowerplan(self, obj): From c1cb399ed06bb296aaf6e423aa539eef057736cb Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 14 Jun 2018 10:33:18 +0200 Subject: [PATCH 2/4] tried to customize password_reset.html --- .../templates/registration/password_reset.html | 18 ++++++++++++++++++ rowsandall_app/urls.py | 8 ++------ 2 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 rowers/templates/registration/password_reset.html diff --git a/rowers/templates/registration/password_reset.html b/rowers/templates/registration/password_reset.html new file mode 100644 index 00000000..1941a27b --- /dev/null +++ b/rowers/templates/registration/password_reset.html @@ -0,0 +1,18 @@ +{% load i18n %} + + + + Forgot your password? + + +

Forgot your password?

+
{% csrf_token %} +
+ {{ form.email.errors }} + + {{ form.email }} +
+ +
+ + diff --git a/rowsandall_app/urls.py b/rowsandall_app/urls.py index 5fdc8511..f129a657 100644 --- a/rowsandall_app/urls.py +++ b/rowsandall_app/urls.py @@ -34,11 +34,13 @@ handler500 = 'rowers.views.error500_view' urlpatterns = [ url(r'^admin/jsi18n', 'django.views.i18n.javascript_catalog'), + url('^', include('django.contrib.auth.urls')), url(r'^django-rq/',include('django_rq.urls')), url(r'^password_change_done/$',auth_views.password_change_done,name='password_change_done'), url(r'^password_change/$',auth_views.password_change), url(r'^password_reset/$', auth_views.password_reset, + {'template_name': 'rowers/templates/registration/password_reset.html'}, name='password_reset'), url(r'^password_reset/done/$', auth_views.password_reset_done, @@ -58,12 +60,6 @@ urlpatterns += [ url(r'^$',rootview), url(r'^login/',auth_views.login, name='login'), url(r'^logout/',auth_views.logout_then_login,name='logout'), -# url(r'^password_reset/$',auth_views.password_reset,name='password_reset'), -# url(r'^password_reset_done/$',auth_views.password_reset_done,name='password_reset_done'), -# url(r'^password_reset_confirm/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', auth_views.password_reset_confirm,name='password_reset_confirm'), -# url(r'^password_reset_confirm/$',auth_views.password_reset_confirm,name='password_reset_confirm'), -# url(r'^password_reset_complete/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', auth_views.password_reset_complete,name='password_reset_complete'), -# url(r'^password_reset_complete/$',auth_views.password_reset_complete,name='password_reset_complete'), url(r'^rowers/',include('rowers.urls')), url(r'^cvkbrno/',include('cvkbrno.urls')), url(r'^admin/rq/',include('django_rq_dashboard.urls')), From b1a8e84bd521961fcd17e0934e79e096c4738845 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 14 Jun 2018 11:38:00 +0200 Subject: [PATCH 3/4] improved form processing in summary edit --- rowers/dataprep.py | 20 +++++++ rowers/forms.py | 4 +- rowers/interactiveplots.py | 4 +- rowers/templates/summary_edit.html | 3 ++ rowers/views.py | 87 +++++++++++++++++++++++++++--- 5 files changed, 108 insertions(+), 10 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index ca63cac2..24869490 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -2364,3 +2364,23 @@ def workout_rscore(w): tss = 0 return tss,normp + +def workout_normv(w,pp=4.0): + df,row = getrowdata_db(id=w.id) + df = clean_df_stats(df,workstrokesonly=False) + if df.empty: + df,row = getrowdata_db(id=w.id) + df = clean_df_stats(df,workstrokesonly=False) + + df['deltat'] = df['time'].diff() + duration = df['time'].max()-df['time'].min() + duration /= 1.0e3 + df['v4'] = df['velo']**(pp) + v4mean = wavg(df,'v4','deltat') + normv = v4mean**(1./pp) + + if np.isnan(normv): + return 500./120. + + return normv + diff --git a/rowers/forms.py b/rowers/forms.py index 71c93283..ae4fcc53 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -488,8 +488,8 @@ class PowerIntervalUpdateForm(forms.Form): ('pace','Pace') ) - pace = forms.DurationField(label='Pace',required=False) - power = forms.IntegerField(label='Power',required=False) + pace = forms.DurationField(required=False,label='Pace (/500m)') + power = forms.IntegerField(required=False,label='Power (W)') selector = forms.ChoiceField(choices=selectorchoices, required=True, initial='power', diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index ba3eba9e..a8600598 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2138,8 +2138,8 @@ def interactive_chart(id=0,promember=0): try: spm = datadf['spm'] except KeyError: - datadf['spm'] = 0*datadf['pace'] - + datadf['spm'] = 0 + #datadf,row = dataprep.getrowdata_db(id=id) #if datadf.empty: #return "","No Valid Data Available" diff --git a/rowers/templates/summary_edit.html b/rowers/templates/summary_edit.html index 59510b18..3419f077 100644 --- a/rowers/templates/summary_edit.html +++ b/rowers/templates/summary_edit.html @@ -164,6 +164,9 @@ {% csrf_token %} + {% for key,value in formvalues.items %} + + {% endfor %} {% for field in detailform %} {{ field.as_hidden }} {% endfor %} diff --git a/rowers/views.py b/rowers/views.py index 8a4d22fe..d348ec90 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -11295,7 +11295,23 @@ def workout_summary_edit_view(request,id,message="",successmessage="" pass savebutton = 'nosavebutton' + formvalues = {} + form = SummaryStringForm() + tss,normp = dataprep.workout_rscore(row) + + normv = dataprep.workout_normv(row,pp=10.0) + + avpace = datetime.timedelta(seconds=int(500./normv)) + + data = { + 'power': int(normp), + 'pace': avpace, + 'selector': normp, + } + + powerupdateform = PowerIntervalUpdateForm(initial=data) + # We have submitted the mini language interpreter if request.method == 'POST' and "intervalstring" in request.POST: form = SummaryStringForm(request.POST) @@ -11310,7 +11326,58 @@ def workout_summary_edit_view(request,id,message="",successmessage="" itime,idist,itype = rowdata.intervalstats_values() nrintervals = len(idist) savebutton = 'savestringform' - + powerupdateform = PowerIntervalUpdateForm() + + # we are saving the results obtained from the split by power/pace interpreter + elif request.method == 'POST' and "savepowerpaceform" in request.POST: + powerorpace = request.POST['powerorpace'] + value_pace = request.POST['value_pace'] + value_power = request.POST['value_power'] + if powerorpace == 'power': + power = int(value_power) + pace_secs = 120.0 + else: + power = 0 + pace_secs = float(value_pace) + + if powerorpace == 'power' and power is not None: + try: + rowdata.updateinterval_metric(' Power (watts)',power,mode='larger', + debug=False,smoothwindow=15) + except: + messages.error(request,'Error updating power') + elif powerorpace == 'pace': + try: + velo = 500./pace_secs + rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',velo,mode='larger', + debug=False,smoothwindow=15) + except: + messages.error(request,'Error updating pace') + + intervalstats = rowdata.allstats() + itime,idist,itype = rowdata.intervalstats_values() + nrintervals = len(idist) + + row.summary = intervalstats + row.save() + + rowdata.write_csv(f1,gzip=True) + messages.info(request,"Updated interval data saved") + data = { + 'power': power, + 'pace': datetime.timedelta(seconds=int(pace_secs)), + 'selector': powerorpace + } + form = SummaryStringForm() + powerupdateform = PowerIntervalUpdateForm(initial=data) + savebutton = 'savepowerpaceform' + formvalues = { + 'powerorpace': powerorpace, + 'value_power': power, + 'value_pace': pace_secs + } + + # we are saving the results obtained from the mini language interpreter elif request.method == 'POST' and "savestringform" in request.POST: s = request.POST["savestringform"] @@ -11339,6 +11406,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" messages.info(request,"Updated interval data saved") data = {'intervalstring':s} form = SummaryStringForm(initial=data) + powerupdateform = PowerIntervalUpdateForm() savebutton = 'savestringform' # we are saving the results obtained from the power update form @@ -11371,8 +11439,14 @@ def workout_summary_edit_view(request,id,message="",successmessage="" intervalstats = rowdata.allstats() itime,idist,itype = rowdata.intervalstats_values() nrintervals = len(idist) - savebutton = 'savestringform' + savebutton = 'savepowerpaceform' + formvalues = { + 'powerorpace': powerorpace, + 'value_power': power, + 'value_pace': pace_secs + } powerupdateform = PowerIntervalUpdateForm(initial=cd) + form = SummaryStringForm() form = SummaryStringForm() @@ -11428,6 +11502,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" messages.info(request,"Updated interval data saved") form = SummaryStringForm() + powerupdateform = PowerIntervalUpdateForm() # we are processing the details form elif request.method == 'POST' and "nrintervals" in request.POST: @@ -11472,10 +11547,9 @@ def workout_summary_edit_view(request,id,message="",successmessage="" form = SummaryStringForm() - - else: - form = SummaryStringForm() - powerupdateform = PowerIntervalUpdateForm() + powerupdateform = PowerIntervalUpdateForm() + + initial = {} for i in xrange(nrintervals): @@ -11500,6 +11574,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" 'the_div':div, 'intervalstring':s, 'savebutton':savebutton, + 'formvalues':formvalues, }) # Page where user can manage his favorite charts From e3f6cf0e3fe4e2a3b2c9285d2e46aea9c73bbf90 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 14 Jun 2018 11:45:41 +0200 Subject: [PATCH 4/4] better value for normv --- rowers/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rowers/views.py b/rowers/views.py index d348ec90..f38426c7 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -11300,7 +11300,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" tss,normp = dataprep.workout_rscore(row) - normv = dataprep.workout_normv(row,pp=10.0) + normv = dataprep.workout_normv(row,pp=8.0) avpace = datetime.timedelta(seconds=int(500./normv))