diff --git a/rowers/admin.py b/rowers/admin.py index 887bbd25..6c8da968 100644 --- a/rowers/admin.py +++ b/rowers/admin.py @@ -32,7 +32,7 @@ class TeamAdmin(admin.ModelAdmin): list_display = ('name','manager') class TeamInviteAdmin(admin.ModelAdmin): - list_display = ('issuedate','team','user') + list_display = ('issuedate','team','user','code') admin.site.unregister(User) admin.site.register(User,UserAdmin) diff --git a/rowers/models.py b/rowers/models.py index 18591001..c801799f 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -83,7 +83,7 @@ class PowerZonesField(models.TextField): # For future Team functionality class Team(models.Model): - name = models.CharField(max_length=150) + name = models.CharField(max_length=150,unique=True) notes = models.CharField(blank=True,max_length=200) manager = models.ForeignKey(User) @@ -92,9 +92,9 @@ class Team(models.Model): class TeamInvite(models.Model): team = models.ForeignKey(Team) - user = models.ForeignKey(User) + user = models.ForeignKey(User,null=True) issuedate = models.DateField(default=timezone.now) - code = models.CharField(max_length=150) + code = models.CharField(max_length=150,unique=True) # Extension of User with rowing specific data diff --git a/rowers/teams.py b/rowers/teams.py new file mode 100644 index 00000000..1d52b44a --- /dev/null +++ b/rowers/teams.py @@ -0,0 +1,95 @@ +# All the Team related methods + +# Python +from django.utils import timezone +from datetime import datetime +from datetime import timedelta +import time +from django.db import IntegrityError +import uuid + +from rowers.models import ( + Rower, Workout, Team, TeamInvite,User + ) + +# Low level functions - to be called by higher level methods + +def create_team(name,manager,notes=''): + # needs some error testing + try: + t = Team(name=name,manager=manager,notes=notes) + t.save() + r = Rower.objects.get(user=manager) + r.team.add(t) + except IntegrityError: + return (0,'Team name duplication') + return (t.id,'Team created') + +def remove_team(id): + t = Team.objects.get(id=id) + return t.delete() + +def add_member(id,rower): + t= Team.objects.get(id=id) + rower.team.add(t) + return (1,'Member added') + +def remove_member(id,rower): + t = Team.objects.get(id=id) + rower.team.remove(t) + return (1,'Member removed') + +def mgr_remove_member(id,manager,rower): + t = Team.objects.get(id=id) + if t.manager == manager: + rower.team.remove(t) + return (1,'Member added') + else: + return (0,'You are not the team manager') + + return 0 + +def count_members(id): + t = Team.objects.get(id=id) + return Rower.objects.filter(team=t).count() + +def count_club_members(manager): + ts = Team.objects.filter(manager=manager) + return Rower.objects.filter(team__in=ts).distinct().count() + +def get_club_members(manager): + ts = Team.objects.filter(manager=manager) + return Rower.objects.filter(team__in=ts).distinct() + +def get_team_members(id): + t = Team.objects.get(id=id) + return Rower.objects.filter(team=t) + +# Medium level functionality + +def create_invite(team,manager,user=None): + if team.manager != manager: + return (0,'Not the team manager') + if user: + try: + r2 = Rower.objects.get(user=user) + except Rower.DoesNotExist: + return (0,'Rower does not exist') + if r2 in Rower.objects.filter(team=team): + return (0,'Already member of that team') + if count_club_members(team.manager) < r.clubsize: + codes = [i.code for i in TeamInvite.objects.all()] + code = uuid.uuid4().hex[:10].upper() + # prevent duplicates + while code in codes: + code = uuid.uuid4().hex[:10].upper() + + invite = TeamInvite(team=team,code=code,user=user) + invite.save() + return code + + + else: + return (0,'You are at your club size limit') + + return (0,'Nothing done') diff --git a/rowers/templates/advancededit.html b/rowers/templates/advancededit.html index 0e40362b..fe002787 100644 --- a/rowers/templates/advancededit.html +++ b/rowers/templates/advancededit.html @@ -51,7 +51,7 @@
- {% if user.rower.rowerplan == 'pro' %} + {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Compare Workouts {% else %} Compare Workouts @@ -71,7 +71,7 @@

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

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

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

- {% if user.rower.rowerplan == 'pro' %} + {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Power Histogram {% else %} Dist Metrics Plot diff --git a/rowers/templates/advancedotw.html b/rowers/templates/advancedotw.html index 2892dcc4..e6c03f20 100644 --- a/rowers/templates/advancedotw.html +++ b/rowers/templates/advancedotw.html @@ -51,7 +51,7 @@

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

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

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

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

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

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

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

- {% if user.rower.rowerplan == 'pro' %} + {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Raw Data {% else %} Reset Smoothing diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html index c0deb3cd..4cdbf511 100644 --- a/rowers/templates/analysis.html +++ b/rowers/templates/analysis.html @@ -41,7 +41,7 @@

Pro

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

- {% if user.rower.rowerplan == 'pro' %} + {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Statistics {% else %} Statistics diff --git a/rowers/templates/base.html b/rowers/templates/base.html index 1f583a2f..57ee2294 100644 --- a/rowers/templates/base.html +++ b/rowers/templates/base.html @@ -24,7 +24,7 @@ {% analytical_body_top %}

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

 

diff --git a/rowers/templates/bases.html b/rowers/templates/bases.html index 57e283b6..a61c155d 100644 --- a/rowers/templates/bases.html +++ b/rowers/templates/bases.html @@ -19,7 +19,7 @@
- {% if user.rower.rowerplan == 'pro' %} + {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
Pro Member
{% else %}

 

diff --git a/rowers/templates/flexchart3.html b/rowers/templates/flexchart3.html index 1fac349a..aa49ff65 100644 --- a/rowers/templates/flexchart3.html +++ b/rowers/templates/flexchart3.html @@ -168,7 +168,7 @@
-{% if user.rower.rowerplan == 'pro' %} +{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if maxfav >= 0 %} diff --git a/rowers/templates/flexchart3otw.html b/rowers/templates/flexchart3otw.html index 40738d31..4697f3a7 100644 --- a/rowers/templates/flexchart3otw.html +++ b/rowers/templates/flexchart3otw.html @@ -203,7 +203,7 @@
-{% if user.rower.rowerplan == 'pro' %} +{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if maxfav >= 0 %} diff --git a/rowers/templates/otwgeeky.html b/rowers/templates/otwgeeky.html index d26fe113..8248084d 100644 --- a/rowers/templates/otwgeeky.html +++ b/rowers/templates/otwgeeky.html @@ -57,7 +57,7 @@

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

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

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

- {% if user.rower.rowerplan == 'pro' %} + {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Corrected Pace Plot {% else %} Corrected Pace Plot @@ -159,4 +159,4 @@

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/rowers/views.py b/rowers/views.py index 1f80dda1..2a49720c 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -199,7 +199,7 @@ def splitstdata(lijst): from utils import geo_distance,serialize_list,deserialize_list # Check if a user is a Pro member -def promember(user): +def ispromember(user): r = Rower.objects.get(user=user) result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach') return result @@ -1301,7 +1301,7 @@ def histo_all(request,theuser=0): if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 @@ -1371,7 +1371,7 @@ def cum_flex(request,theuser=0, if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 @@ -1463,14 +1463,14 @@ def cum_flex(request,theuser=0, }) # Show the EMpower Oarlock generated Stroke Profile -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_forcecurve_view(request,id=0,workstrokesonly=False): row = Workout.objects.get(id=id) promember=0 mayedit=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 if request.user == row.user.user: @@ -1509,7 +1509,7 @@ def workout_histo_view(request,id=0): mayedit=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 if request.user == row.user.user: @@ -1561,7 +1561,7 @@ def histo(request,theuser=0, if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 @@ -1671,7 +1671,7 @@ def rankings_view(request,theuser=0, promember=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 @@ -2040,7 +2040,7 @@ def workouts_view(request,message='',successmessage='', return HttpResponse("User has no rower instance") # List of workouts to compare a selected workout to -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_comparison_list(request,id=0,message='',successmessage='', startdatestring="",enddatestring="", startdate=timezone.now()-datetime.timedelta(days=365), @@ -2155,7 +2155,7 @@ def workout_view(request,id=0): return HttpResponseNotFound("Workout doesn't exist") # Resets stroke data to raw data (pace) -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""): row = Workout.objects.get(id=id) if (checkworkoutuser(request.user,row)==False): @@ -2182,7 +2182,7 @@ def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""): # Data smoothing of pace data -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_smoothenpace_view(request,id=0,message="",successmessage=""): row = Workout.objects.get(id=id) if (checkworkoutuser(request.user,row)==False): @@ -2218,7 +2218,7 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""): return HttpResponseRedirect(url) # Process CrewNerd Summary CSV and update summary -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""): row = Workout.objects.get(id=id) if request.method == 'POST': @@ -2263,7 +2263,7 @@ def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""): 'id':row.id}) # Get weather for given location and date/time -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_downloadwind_view(request,id=0,message="",successmessage=""): row = Workout.objects.get(id=id) f1 = row.csvfilename @@ -2320,7 +2320,7 @@ def workout_downloadwind_view(request,id=0,message="",successmessage=""): return response # Show form to update wind data -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_wind_view(request,id=0,message="",successmessage=""): row = Workout.objects.get(id=id) if (checkworkoutuser(request.user,row)==False): @@ -2420,7 +2420,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""): # Show form to update River stream data (for river dwellers) -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_stream_view(request,id=0,message="",successmessage=""): row = Workout.objects.get(id=id) if (checkworkoutuser(request.user,row)==False): @@ -2482,7 +2482,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""): 'the_div':div}) # Form to set average crew weight and boat type, then run power calcs -@user_passes_test(promember, login_url="/",redirect_field_name=None) +@user_passes_test(ispromember, login_url="/",redirect_field_name=None) def workout_otwsetpower_view(request,id=0,message="",successmessage=""): row = Workout.objects.get(id=id) if (checkworkoutuser(request.user,row)==False): @@ -2654,7 +2654,7 @@ def cumstats(request,theuser=0, if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 @@ -3086,7 +3086,7 @@ def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'): promember=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 @@ -3113,7 +3113,7 @@ def workout_comparison_view2(request,id1=0,id2=0,xparam='distance', promember=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 @@ -3161,7 +3161,7 @@ def workout_flexchart3_view(request,*args,**kwargs): mayedit=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 if request.user == row.user.user: @@ -3316,7 +3316,7 @@ def workout_biginteractive_view(request,id=0,message="",successmessage=""): mayedit=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 if request.user == row.user.user: @@ -3353,7 +3353,7 @@ def workout_otwpowerplot_view(request,id=0,message="",successmessage=""): mayedit=0 if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' + result = request.user.is_authenticated() and ispromember(request.user) if result: promember=1 if request.user == row.user.user: @@ -3555,7 +3555,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): return HttpResponseRedirect(url) # Create the chart image with wind corrected pace (OTW) -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_add_otw_powerplot_view(request,id): w = Workout.objects.get(id=id) if (checkworkoutuser(request.user,w)==False): @@ -3818,7 +3818,7 @@ def workout_add_distanceplot_view(request,id): return HttpResponseRedirect(url) # Create the advanced parameters distance overview chart -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_add_distanceplot2_view(request,id): w = Workout.objects.get(id=id) if (checkworkoutuser(request.user,w)==False): @@ -3871,7 +3871,7 @@ def workout_add_distanceplot2_view(request,id): # Create the advanced parameters time based overview chart -@user_passes_test(promember,login_url="/",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) def workout_add_timeplot2_view(request,id): w = Workout.objects.get(id=id) if (checkworkoutuser(request.user,w)==False): @@ -4934,7 +4934,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" }) # Page where user can manage his favorite charts -@user_passes_test(promember,login_url="/rowers/me/edit",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/me/edit",redirect_field_name=None) def rower_favoritecharts_view(request): message = '' successmessage = ''