From 6ff73c44c43a815d187f359a814b799004e615b2 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 8 Feb 2018 23:11:26 +0100 Subject: [PATCH 1/4] improved date behavior for cloning --- rowers/dataprep.py | 6 +++--- rowers/views.py | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 9c891dd9..e738b735 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -2226,11 +2226,11 @@ def workout_trimp(workout): return trimp def workout_rscore(w): - r = workout.user - df,row = getrowdata_db(id=workout.id) + r = w.user + df,row = getrowdata_db(id=w.id) df = clean_df_stats(df) if df.empty: - df,row = getrowdata_db(id=workout.id) + df,row = getrowdata_db(id=w.id) df = clean_df_stats(df,workstrokesonly=False) duration = df['time'].max()-df['time'].min() diff --git a/rowers/views.py b/rowers/views.py index f16dcdae..f6943094 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -11969,8 +11969,10 @@ def plannedsession_clone_view(request,id=0,rowerid=0, ps.pk = None + deltadays = ps.enddate-ps.startdate + ps.startdate = timezone.now() - ps.enddate = timezone.now() + ps.enddate = timezone.now()+deltadays ps.name += ' (copy)' ps.save() From a32eb965671eb741457cf4826a2ec674c567147d Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 8 Feb 2018 23:15:54 +0100 Subject: [PATCH 2/4] add rower select to session edit --- rowers/templates/plannedsessionedit.html | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/rowers/templates/plannedsessionedit.html b/rowers/templates/plannedsessionedit.html index 7990d726..8bf00feb 100644 --- a/rowers/templates/plannedsessionedit.html +++ b/rowers/templates/plannedsessionedit.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% load staticfiles %} +{% load rowerfilters %} {% block title %}Update Planned Session{% endblock %} @@ -13,7 +14,7 @@

Edit Session {{ thesession.name }}

+{% if user.is_authenticated and user|is_manager %} + +{% endif %}
From 71ad6a0dee29a2de9868a6f37999dd957a094fb4 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 9 Feb 2018 10:26:54 +0100 Subject: [PATCH 3/4] implemented Pro trial period --- rowers/models.py | 2 ++ rowers/templates/advancededit.html | 16 +++++----- rowers/templates/advancedotw.html | 22 ++++++------- rowers/templates/analysis.html | 14 ++++----- rowers/templates/bases.html | 5 +-- rowers/templates/histo.html | 46 ++++++++++++++-------------- rowers/templates/otwgeeky.html | 8 ++--- rowers/templates/planmembership.html | 2 +- rowers/templates/promembership.html | 20 +++++++++--- rowers/templatetags/rowerfilters.py | 33 +++++++++++++++++++- rowers/urls.py | 1 + rowers/views.py | 32 ++++++++++++++++++- templates/basebase.html | 14 +++++++-- 13 files changed, 149 insertions(+), 66 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 74373e98..bed877e9 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -502,6 +502,8 @@ class Rower(models.Model): planexpires = models.DateField(default=timezone.now) teamplanexpires = models.DateField(default=timezone.now) clubsize = models.IntegerField(default=0) + protrialexpires = models.DateField(blank=True,null=True) + plantrialexpires = models.DateField(blank=True,null=True) # Friends/Team diff --git a/rowers/templates/advancededit.html b/rowers/templates/advancededit.html index be762e3d..e8a7e2e0 100644 --- a/rowers/templates/advancededit.html +++ b/rowers/templates/advancededit.html @@ -60,7 +60,7 @@
- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Compare Workouts {% else %} Compare Workouts @@ -80,7 +80,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Edit Intervals {% else %} Edit Intervals @@ -97,7 +97,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Dist Metrics Plot {% else %} Dist Metrics Plot @@ -109,7 +109,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Time Metrics Plot {% else %} Time Metrics Plot @@ -121,7 +121,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Power Histogram {% else %} Power Histogram @@ -135,7 +135,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Glue {% else %} Glue @@ -148,7 +148,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Sensor Fusion {% else %} Sensor Fusion @@ -160,7 +160,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Split Workout {% else %} Split Workout diff --git a/rowers/templates/advancedotw.html b/rowers/templates/advancedotw.html index e6ace0a9..f22a9a44 100644 --- a/rowers/templates/advancedotw.html +++ b/rowers/templates/advancedotw.html @@ -56,7 +56,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Compare Workouts {% else %} Compare Workouts @@ -78,7 +78,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Edit Intervals {% else %} Edit Intervals @@ -95,7 +95,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} CrewNerd Summary {% else %} CrewNerd Summary @@ -109,7 +109,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Stroke Profile (Empower) {% else %} Stroke Profile (Empower) @@ -122,7 +122,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} OTW Power Plot {% else %} OTW Power Plot @@ -142,7 +142,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Geeky Stuff {% else %} Geeky Stuff @@ -157,7 +157,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Smooth out Pace Data {% else %} Smooth out Pace Data @@ -174,7 +174,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Raw Data {% else %} Reset Smoothing @@ -189,7 +189,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Glue {% else %} Glue @@ -201,7 +201,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Sensor Fusion {% else %} Sensor Fusion @@ -213,7 +213,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Split Workout {% else %} Split Workout diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html index 6f7a3531..da1726ee 100644 --- a/rowers/templates/analysis.html +++ b/rowers/templates/analysis.html @@ -41,7 +41,7 @@

Pro

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Power Histogram {% else %} Power Histogram @@ -53,7 +53,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Statistics {% else %} Statistics @@ -65,7 +65,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Box Chart {% else %} Box Chart @@ -90,7 +90,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} OTW Critical Power {% else %} OTW Critical Power @@ -102,7 +102,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Multi Compare {% else %} Multi Compare @@ -114,7 +114,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Trend Flex {% else %} Trend Flex @@ -128,7 +128,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} OTE Critical Power {% else %} OTE Critical Power diff --git a/rowers/templates/bases.html b/rowers/templates/bases.html index 8daf8b52..6b242cf2 100644 --- a/rowers/templates/bases.html +++ b/rowers/templates/bases.html @@ -1,3 +1,4 @@ +{% load rowerfilters %} @@ -19,7 +20,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %}
Pro Member
{% else %}

 

diff --git a/rowers/templates/histo.html b/rowers/templates/histo.html index 95980f07..5de2516b 100644 --- a/rowers/templates/histo.html +++ b/rowers/templates/histo.html @@ -56,24 +56,24 @@ {{ interactiveplot |safe }} - + // Set things up to resize the plot on a window resize. You can play with + // the arguments of resize_width_height() to change the plot's behavior. + var plot_resize_setup = function () { + var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot + var plot = Bokeh.index[plotid]; + var plotresizer = function() { + // arguments: use width, use height, maintain aspect ratio + plot.resize_width_height(true, false, false); + }; + window.addEventListener('resize', plotresizer); + plotresizer(); + }; + window.addEventListener('load', plot_resize_setup); + +
@@ -97,8 +97,8 @@
{% else %}   - {% endif %}
+ {% endif %}
@@ -144,7 +144,7 @@
- +

Summary for {{ theuser.first_name }} {{ theuser.last_name }} @@ -153,9 +153,9 @@

- - {{ the_div|safe }} - + + {{ the_div|safe }} +
{% endblock %} diff --git a/rowers/templates/otwgeeky.html b/rowers/templates/otwgeeky.html index 14699098..aecd9c95 100644 --- a/rowers/templates/otwgeeky.html +++ b/rowers/templates/otwgeeky.html @@ -57,7 +57,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Edit Wind Data {% else %} Edit Wind Data @@ -70,7 +70,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Edit Stream Data {% else %} Edit Stream Data @@ -83,7 +83,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} OTW Power {% else %} OTW Power @@ -100,7 +100,7 @@

- {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + {% if user|is_promember %} Corrected Pace Plot {% else %} Corrected Pace Plot diff --git a/rowers/templates/planmembership.html b/rowers/templates/planmembership.html index 55d599e8..6a3dc73c 100644 --- a/rowers/templates/planmembership.html +++ b/rowers/templates/planmembership.html @@ -1,6 +1,6 @@ {% extends "base.html" %} - {% block title %}About us{% endblock title %} + {% block title %}Rowsandall Plan Membership{% endblock title %} {% block content %}

diff --git a/rowers/templates/promembership.html b/rowers/templates/promembership.html index bb89c13d..bd98a21f 100644 --- a/rowers/templates/promembership.html +++ b/rowers/templates/promembership.html @@ -1,7 +1,8 @@ {% extends "base.html" %} - {% block title %}About us{% endblock title %} + {% block title %}Rowsandall Pro Membership{% endblock title %} {% block content %} +{% load rowerfilters %}

Pro Membership

@@ -24,12 +25,21 @@ website.

Your payment will be valid for one year with automatic renewal which you can stop at any time. You will be taken to the secure PayPal payment site.

+{% if user.rower.rowerplan == 'basic' and user.rower.protrialexpires|date_dif == 1 %} +

+ You qualify for a 14 day free trial. No credit card needed. + Try out Pro membership for two weeks. Click the button below to + sign up for the trial. After your trial period expires, you will be + automatically reset to the Basic plan, unless you upgrade to Pro. +

+ +{% endif %}

Recurring Payment

You need a Paypal account for this

-
+

{% if user.is_authenticated %} @@ -38,16 +48,16 @@ You will be taken to the secure PayPal payment site. {% endif %} -

+

One Year Subscription

Only a credit card needed. Will not automatically renew

-
+

-

+

Payment Processing

After you do the payment, we will manually change your membership to diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 8661e00f..bfdf2751 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -3,7 +3,7 @@ from django.utils.safestring import mark_safe from time import strftime import dateutil.parser import json - +import datetime register = template.Library() def strfdelta(tdelta): @@ -41,6 +41,10 @@ def secondstotimestring(tdelta): return res +@register.filter +def ddays(ddelta): + return ddelta.days+1 + @register.filter def spacetohtml(t): return t.replace(" ","%20") @@ -107,6 +111,11 @@ def get_field_id(id,s,form): from rowers.models import Rower,Team +from rowers.views import ispromember +@register.filter +def is_promember(user): + return ispromember(user) + @register.filter def is_manager(user): r = Rower.objects.get(user=user) @@ -183,3 +192,25 @@ def verbosetimeperiod(timeperiod): return verbose +from datetime import date + +@ register.filter +def future_date_only(the_date): + if the_date > date.today(): + return the_date + else: + return None + + +@register.filter +def is_future_date(the_date): + return the_date >= date.today() + +@register.filter +def date_dif(the_date): + if the_date: + return the_date - date.today() + else: + return 1 + + diff --git a/rowers/urls.py b/rowers/urls.py index 2d42ea30..aa23fbc8 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -382,6 +382,7 @@ urlpatterns = [ url(r'^videos', TemplateView.as_view(template_name='videos.html'),name='videos'), url(r'^analysis', TemplateView.as_view(template_name='analysis.html'),name='analysis'), url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'), + url(r'^starttrial$',views.start_trial_view), url(r'^planmembership', TemplateView.as_view(template_name='planmembership.html'),name='planmembership'), url(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'), url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'), diff --git a/rowers/views.py b/rowers/views.py index f16dcdae..a056ad00 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -800,6 +800,8 @@ def ispromember(user): r.save() result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach' or r.rowerplan=='plan') + if not result and r.protrialexpires: + result = user.is_authenticated() and r.rowerplan=='basic' and r.protrialexpires >= datetime.date.today() else: result = False return result @@ -930,6 +932,33 @@ def sendmail(request): else: return HttpResponseRedirect('/rowers/email/') +@login_required() +def start_trial_view(request): + r = getrower(request.user) + + if r.protrialexpires is not None: + messages.error(request,'You do not qualify for a trial') + url = '/rowers/promembership' + return HttpResponseRedirect(url) + + r.protrialexpires = datetime.date.today()+datetime.timedelta(13) + r.save() + + url = reverse(workouts_view) + + messages.info(request,'We have started your 14 day trial period') + + subject2 = "User started Pro Trial" + message2 = "User Started Pro Trial.\n" + message2 += request.user.email + "\n" + message2 += "User name: "+request.user.username + + send_mail(subject2, message2, + 'Rowsandall Server ', + ['roosendaalsander@gmail.com']) + + return HttpResponseRedirect(url) + # Create workout data from Strava or Concept2 # data and create the associated Workout object and save it def add_workout_from_strokedata(user,importid,data,strokedata, @@ -5060,7 +5089,8 @@ def team_comparison_select(request, theteam = 0 if r.rowerplan == 'basic' and theteam==0: - raise Http404("Not allowed") + if r.protrialexpires is None or r.protrialexpires

@@ -238,6 +241,11 @@ {{ WARNING_MESSAGE }}

{% endif %} + {% if user.rower.protrialexpires and user.rower.protrialexpires|is_future_date %} +

+ {{ user.rower.protrialexpires|date_dif|ddays }} days left in Pro trial +

+ {% endif %} {% if messages %} {% for message in messages %} {% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %} From cd134a40fd761cc18aefe47258a54ac1bc622fe7 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 9 Feb 2018 16:40:47 +0100 Subject: [PATCH 4/4] edit and create team sessions --- rowers/forms.py | 25 +- rowers/models.py | 5 +- rowers/plannedsessions.py | 13 +- rowers/templates/plannedsessioncreate.html | 4 +- rowers/templates/plannedsessionedit.html | 13 +- rowers/templates/plannedsessions.html | 51 ++++ rowers/templates/plannedsessionsmanage.html | 4 +- .../templates/plannedsessionteamcreate.html | 121 +++++++++ rowers/templates/plannedsessionteamedit.html | 137 ++++++++++ rowers/templates/planningbuttons.html | 14 +- rowers/urls.py | 12 + rowers/views.py | 236 +++++++++++++++++- 12 files changed, 612 insertions(+), 23 deletions(-) create mode 100644 rowers/templates/plannedsessionteamcreate.html create mode 100644 rowers/templates/plannedsessionteamedit.html diff --git a/rowers/forms.py b/rowers/forms.py index faa5d108..b6191619 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple -from rowers.models import Workout +from rowers.models import Workout,Rower,Team from rowers.rows import validate_file_extension,must_be_csv,validate_image_extension from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User @@ -629,3 +629,26 @@ class WorkoutSessionSelectForm(forms.Form): widget = forms.CheckboxSelectMultiple, ) +class PlannedSessionTeamForm(forms.Form): + team = forms.ModelMultipleChoiceField( + queryset=Team.objects.all(), + required=False, + widget=forms.CheckboxSelectMultiple()) + + def __init__(self, user, *args, **kwargs): + super(PlannedSessionTeamForm,self).__init__(*args, **kwargs) + + self.fields['team'].queryset = Team.objects.filter(manager=user) + + +class PlannedSessionTeamMemberForm(forms.Form): + members = forms.ModelMultipleChoiceField( + queryset=Rower.objects.all(), + widget=forms.CheckboxSelectMultiple()) + + def __init__(self, thesession, *args, **kwargs): + super(PlannedSessionTeamMemberForm,self).__init__(*args,**kwargs) + + self.fields['members'].queryset = thesession.rower.all() + + diff --git a/rowers/models.py b/rowers/models.py index bed877e9..60dbce2e 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -523,8 +523,11 @@ class Rower(models.Model): verbose_name='Show Notes for Favorite Charts') def __str__(self): - return self.user.username + return self.user.firstname+' '+self.user.last_name + def __unicode__(self): + return self.user.first_name+' '+self.user.last_name + def clean_email(self): return self.user.email.lower() diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index caca9821..1f9c708d 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -215,8 +215,19 @@ def get_sessions(r,startdate=date.today(), rower__in=[r], startdate__lte=enddate, enddate__gte=startdate, - ).order_by("startdate","enddate") + ).order_by("startdate","enddate") + + return sps +def get_sessions_manager(manager,startdate=date.today(), + enddate=date.today()+timezone.timedelta(+1000)): + + sps = PlannedSession.objects.filter( + manager=manager, + startdate__lte=enddate, + enddate__gte=startdate, + ).order_by("startdate","enddate").exclude(team__isnull=True) + return sps def get_workouts_session(r,ps): diff --git a/rowers/templates/plannedsessioncreate.html b/rowers/templates/plannedsessioncreate.html index 63bba657..97cfb0a9 100644 --- a/rowers/templates/plannedsessioncreate.html +++ b/rowers/templates/plannedsessioncreate.html @@ -7,8 +7,8 @@ {% block content %}
{% include "planningbuttons.html" %} -
+

Create Session for {{ rower.user.first_name }} {{ rower.user.last_name }}

@@ -119,7 +119,7 @@ {% csrf_token %}
- +
diff --git a/rowers/templates/plannedsessionedit.html b/rowers/templates/plannedsessionedit.html index 8bf00feb..306028b8 100644 --- a/rowers/templates/plannedsessionedit.html +++ b/rowers/templates/plannedsessionedit.html @@ -39,15 +39,10 @@
{% if user.is_authenticated and user|is_manager %} - diff --git a/rowers/templates/plannedsessions.html b/rowers/templates/plannedsessions.html index d4b1cf6a..ed5fda38 100644 --- a/rowers/templates/plannedsessions.html +++ b/rowers/templates/plannedsessions.html @@ -117,6 +117,57 @@ You have no planned workouts for this period. Planned workouts are created by your coach if you are part of a team. You can create your own planned workouts by purchasing the "Coach" or "Self-Coach" plans. + {% endif %} + {% if unmatchedworkouts %} +

Workouts that are not linked to any session

+ + + + + + + + + + + + + + + {% for workout in unmatchedworkouts %} + + + + {% if workout.user.user == user or user == team.manager %} + {% if workout.name != '' %} + + {% else %} + + {% endif %} + {% else %} + {% if workout.name != '' %} + + {% else %} + + {% endif %} + {% endif %} + + + + + + + {% endfor %} + +
Date Time Name Type Distance Duration Avg HR Max HR
{{ workout.date|date:"Y-m-d" }} {{ workout.starttime|date:"H:i" }} + + {{ workout.name }} + + + No Name + {{ workout.name }}No Name {{ workout.workouttype }} {{ workout.distance }}m {{ workout.duration |durationprint:"%H:%M:%S.%f" }} {{ workout.averagehr }} {{ workout.maxhr }}
+ + {% endif %}
diff --git a/rowers/templates/plannedsessionsmanage.html b/rowers/templates/plannedsessionsmanage.html index 879fe3cd..fdb8bc6e 100644 --- a/rowers/templates/plannedsessionsmanage.html +++ b/rowers/templates/plannedsessionsmanage.html @@ -59,10 +59,10 @@ {% for member in user|team_rowers %} {{ member.user.first_name }} {{ member.user.last_name }} {% endfor %} +
{% endif %}
-

Select one session on the left, and one or more workouts on the right to match the workouts to the session. For tests and training sessions, @@ -92,8 +92,6 @@ {% csrf_token %}

- - diff --git a/rowers/templates/plannedsessionteamcreate.html b/rowers/templates/plannedsessionteamcreate.html new file mode 100644 index 00000000..2ecb9a80 --- /dev/null +++ b/rowers/templates/plannedsessionteamcreate.html @@ -0,0 +1,121 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}New Planned Session{% endblock %} + +{% block content %} +
+ {% include "planningbuttons.html" %} +
+ +
+
+

Create Team Session

+
+ +
+ +
+
+ {% if form.errors %} +

+ Please correct the error{{ form.errors|pluralize }} below. +

+ {% endif %} + {% csrf_token %} + + + + + +
+

New Session

+ + {{ form.as_table }} +
+
+ +
+ +
+
+{% endblock %} diff --git a/rowers/templates/plannedsessionteamedit.html b/rowers/templates/plannedsessionteamedit.html new file mode 100644 index 00000000..774a4218 --- /dev/null +++ b/rowers/templates/plannedsessionteamedit.html @@ -0,0 +1,137 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}New Planned Session{% endblock %} + +{% block content %} +
+ {% include "planningbuttons.html" %} +
+ +
+
+

Edit Team Session

+
+ +
+ +
+
+ {% if form.errors %} +

+ Please correct the error{{ form.errors|pluralize }} below. +

+ {% endif %} + {% csrf_token %} + + + + + +
+

Session {{ plannedsession.name }}

+ + {{ form.as_table }} +
+
+ Delete +
+
+ Clone +
+
+ +
+ +
+
+{% endblock %} diff --git a/rowers/templates/planningbuttons.html b/rowers/templates/planningbuttons.html index 798085eb..6f57cfd4 100644 --- a/rowers/templates/planningbuttons.html +++ b/rowers/templates/planningbuttons.html @@ -21,7 +21,7 @@ {% endif %}

-
+

{% if timeperiod and rower %} Add Session @@ -32,3 +32,15 @@ {% endif %}

+
+ {% if user.is_authenticated and user|is_manager %} + {% if timeperiod %} + Add Team Session + {% else %} + Add Team Session + {% endif %} + {% else %} +   + {% endif %} +
+ diff --git a/rowers/urls.py b/rowers/urls.py index aa23fbc8..d502a7d2 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -398,6 +398,18 @@ urlpatterns = [ url(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P[\w\ ]+.*)/$',views.workout_comparison_view2), url(r'^test\_callback',views.rower_process_testcallback), url(r'^workout/(?P\d+)/test\_strokedata$',views.strokedataform), + + url(r'^sessions/teamcreate$',views.plannedsession_teamcreate_view), + url(r'^sessions/teamcreate/(?P[\w\ ]+.*)$', + views.plannedsession_teamcreate_view), + url(r'^sessions/teamcreate/(?P[\w\ ]+.*)/team/(?P\d+)$', + views.plannedsession_teamcreate_view), + url(r'^sessions/teamcreate/team/(?P\d+)$', + views.plannedsession_teamcreate_view), + + url(r'^sessions/teamedit/(?P\d+)$',views.plannedsession_teamedit_view), + url(r'^sessions/teamedit/(?P\d+)/(?P[\w\ ]+.*)$',views.plannedsession_teamedit_view), + url(r'^sessions/create$',views.plannedsession_create_view), url(r'^sessions/create/rower/(?P\d+)$', views.plannedsession_create_view), diff --git a/rowers/views.py b/rowers/views.py index 9dad3771..64faceb5 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -30,7 +30,8 @@ from rowers.forms import ( LoginForm,DocumentsForm,UploadOptionsForm,ImageForm, TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm, WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement, - LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm + LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm, + PlannedSessionTeamForm,PlannedSessionTeamMemberForm, ) from django.core.urlresolvers import reverse from django.core.exceptions import PermissionDenied @@ -11809,6 +11810,208 @@ def plannedsession_create_view(request,timeperiod='thisweek',rowerid=0): 'timeperiod':timeperiod, }) +# Manager creates sessions for entire team +@user_passes_test(iscoachmember,login_url="/rowers/planmembership/", + redirect_field_name=None) +def plannedsession_teamcreate_view(request,timeperiod='thisweek', + teamid=0): + + + teams = Team.objects.filter(manager=request.user) + teamchoices = [(team.id, team.name) for team in teams] + teaminitial = [str(teams[0].id)] + + startdate,enddate = get_dates_timeperiod(timeperiod) + + sps = [] + for team in teams: + res = get_sessions_manager(request.user,startdate=startdate,enddate=enddate) + sps += res + + sps = list(set(sps)) + + if request.method == 'POST': + sessioncreateform = PlannedSessionForm(request.POST) + sessionteamselectform = PlannedSessionTeamForm( + request.user,request.POST + ) + if sessioncreateform.is_valid(): + cd = sessioncreateform.cleaned_data + startdate = cd['startdate'] + enddate = cd['enddate'] + sessiontype = cd['sessiontype'] + sessionmode = cd['sessionmode'] + criterium = cd['criterium'] + sessionvalue = cd['sessionvalue'] + sessionunit = cd['sessionunit'] + comment = cd['comment'] + name = cd['name'] + + if sessionunit == 'min': + sessionmode = 'time' + elif sessionunit in ['km','m']: + sessionmode = 'distance' + + ps = PlannedSession( + name=name, + startdate=startdate, + enddate=enddate, + sessiontype=sessiontype, + sessionmode=sessionmode, + sessionvalue=sessionvalue, + sessionunit=sessionunit, + comment=comment, + criterium=criterium, + manager=request.user) + + ps.save() + + # some logic when to add all selected rowers + if sessionteamselectform.is_valid(): + cd = sessionteamselectform.cleaned_data + teams = cd['team'] + for team in teams: + add_team_session(team,ps) + rs = Rower.objects.filter(team__in=[team]) + for r in rs: + add_rower_session(r,ps) + + + url = reverse(plannedsession_teamcreate_view, + kwargs = { + 'timeperiod':timeperiod, + }) + return HttpResponseRedirect(url) + else: + sessioncreateform = PlannedSessionForm() + sessionteamselectform = PlannedSessionTeamForm( + request.user + ) + + return render(request,'plannedsessionteamcreate.html', + { + 'teams':get_my_teams(request.user), + 'form':sessioncreateform, + 'teamform':sessionteamselectform, + 'timeperiod':timeperiod, + 'plannedsessions':sps, + }) + +# Manager edits sessions for entire team +@user_passes_test(iscoachmember,login_url="/rowers/planmembership/", + redirect_field_name=None) +def plannedsession_teamedit_view(request,timeperiod='thisweek', + sessionid=0): + + try: + ps = PlannedSession.objects.get(id=sessionid) + except PlannedSession.DoesNotExist: + raise Http404("This session doesn't exist") + if not ps.manager == request.user: + raise Http404("You are not the manager of this session") + + teams = Team.objects.filter(manager=request.user) + teamchoices = [(team.id, team.name) for team in teams] + + teaminitial = ps.team.all() + + startdate,enddate = get_dates_timeperiod(timeperiod) + + sps = [] + rowers = [] + for team in teams: + res = get_sessions_manager(request.user,startdate=startdate,enddate=enddate) + sps += res + rowers += Rower.objects.filter(team__in=[team]) + + rowers = list(set(rowers)) + + + sps = list(set(sps)) + + if request.method == 'POST': + sessioncreateform = PlannedSessionForm(request.POST,instance=ps) + sessionteamselectform = PlannedSessionTeamForm( + request.user,request.POST + ) + sessionrowerform = PlannedSessionTeamMemberForm(ps,request.POST) + if sessioncreateform.is_valid(): + cd = sessioncreateform.cleaned_data + + if cd['sessionunit'] == 'min': + cd['sessionmode'] = 'time' + elif cd['sessionunit'] in ['km','m']: + cd['sessionmode'] = 'distance' + + + res,message = update_plannedsession(ps,cd) + + if res: + messages.info(request,message) + else: + messages.error(request,message) + + + # some logic when to add all selected rowers + if sessionteamselectform.is_valid(): + cd = sessionteamselectform.cleaned_data + selectedteams = cd['team'] + for team in teams: + if team in selectedteams: + add_team_session(team,ps) + rs = Rower.objects.filter(team__in=[team]) + for r in rs: + add_rower_session(r,ps) + else: + remove_team_session(team,ps) + else: + selectedteams = [] + + + if sessionrowerform.is_valid(): + cd = sessionrowerform.cleaned_data + selectedrowers = cd['members'] + for r in rowers: + if r in selectedrowers: + add_rower_session(r,ps) + else: + remove_rower_session(r,ps) + for t in selectedteams: + if t in r.team.all(): + add_rower_session(r,ps) + + + url = reverse(plannedsession_teamedit_view, + kwargs = { + 'sessionid':sessionid, + 'timeperiod':timeperiod, + }) + return HttpResponseRedirect(url) + else: + sessioncreateform = PlannedSessionForm(instance=ps) + sessionteamselectform = PlannedSessionTeamForm( + request.user + ) + sessionteamselectform.fields['team'].initial = teaminitial + sessionrowerform = PlannedSessionTeamMemberForm( + ps + ) + + + sessionrowerform.fields['members'].initial = ps.rower.all() + + return render(request,'plannedsessionteamedit.html', + { + 'plannedsession':ps, + 'teams':get_my_teams(request.user), + 'form':sessioncreateform, + 'teamform':sessionteamselectform, + 'rowersform':sessionrowerform, + 'timeperiod':timeperiod, + 'plannedsessions':sps, + }) + + @login_required() def plannedsessions_view(request,timeperiod='thisweek',rowerid=0): @@ -11840,7 +12043,12 @@ def plannedsessions_view(request,timeperiod='thisweek',rowerid=0): completiondate[ps.id] = date else: completiondate[ps.id] = '' - + + unmatchedworkouts = Workout.objects.filter( + user=r, + plannedsession=None, + date__gte=startdate,date__lte=enddate) + return render(request,'plannedsessions.html', { 'teams':get_my_teams(request.user), @@ -11850,6 +12058,7 @@ def plannedsessions_view(request,timeperiod='thisweek',rowerid=0): 'completeness':completeness, 'actualvalue':actualvalue, 'completiondate':completiondate, + 'unmatchedworkouts':unmatchedworkouts, }) @login_required() @@ -11926,7 +12135,10 @@ def plannedsessions_manage_view(request,timeperiod='thisweek',rowerid=0, else: selectedworkouts = [] - + if len(selectedworkouts)==0: + for w in ws: + remove_workout_plannedsession(w,ps) + if selectedworkouts: workouts = Workout.objects.filter(user=r,id__in=selectedworkouts) for w in ws: @@ -11997,6 +12209,9 @@ def plannedsession_clone_view(request,id=0,rowerid=0, if ps.manager != request.user: raise Http404("You are not allowed to clone this planned session") + rowers = ps.rower.all() + teams = ps.team.all() + ps.pk = None deltadays = ps.enddate-ps.startdate @@ -12007,7 +12222,10 @@ def plannedsession_clone_view(request,id=0,rowerid=0, ps.save() - add_rower_session(r,ps) + for rower in rowers: + add_rower_session(rower,ps) + for team in teams: + add_team_session(team,ps) url = reverse(plannedsession_edit_view, kwargs = { @@ -12024,7 +12242,7 @@ def plannedsession_clone_view(request,id=0,rowerid=0, @user_passes_test(hasplannedsessions,login_url="/rowers/planmembership/", redirect_field_name=None) def plannedsession_edit_view(request,id=0,timeperiod='thisweek',rowerid=0): - + if rowerid==0: r = getrower(request.user) else: @@ -12046,6 +12264,14 @@ def plannedsession_edit_view(request,id=0,timeperiod='thisweek',rowerid=0): if ps.manager != request.user: raise Http404("You are not allowed to edit this planned session") + if ps.team.all() or len(ps.rower.all())>1: + url = reverse(plannedsession_teamedit_view, + kwargs={ + 'timeperiod':timeperiod, + 'sessionid':id, + }) + return HttpResponseRedirect(url) + if request.method == 'POST': sessioncreateform = PlannedSessionForm(request.POST,instance=ps) if sessioncreateform.is_valid():