Merge branch 'release/team_management'
This commit is contained in:
@@ -4,7 +4,7 @@ from django.contrib.auth.models import User
|
|||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Rower, Workout,GraphImage,FavoriteChart,SiteAnnouncement,
|
Rower, Workout,GraphImage,FavoriteChart,SiteAnnouncement,
|
||||||
Team,
|
Team,TeamInvite
|
||||||
)
|
)
|
||||||
|
|
||||||
# Register your models here so you can use them in the Admin module
|
# Register your models here so you can use them in the Admin module
|
||||||
@@ -29,7 +29,10 @@ class SiteAnnouncementAdmin(admin.ModelAdmin):
|
|||||||
list_display = ('announcement','created','modified','expires','dotweet')
|
list_display = ('announcement','created','modified','expires','dotweet')
|
||||||
|
|
||||||
class TeamAdmin(admin.ModelAdmin):
|
class TeamAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name',)
|
list_display = ('name','manager')
|
||||||
|
|
||||||
|
class TeamInviteAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('issuedate','team','user','code')
|
||||||
|
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
admin.site.register(User,UserAdmin)
|
admin.site.register(User,UserAdmin)
|
||||||
@@ -38,3 +41,4 @@ admin.site.register(GraphImage)
|
|||||||
admin.site.register(Team,TeamAdmin)
|
admin.site.register(Team,TeamAdmin)
|
||||||
admin.site.register(FavoriteChart,FavoriteChartAdmin)
|
admin.site.register(FavoriteChart,FavoriteChartAdmin)
|
||||||
admin.site.register(SiteAnnouncement,SiteAnnouncementAdmin)
|
admin.site.register(SiteAnnouncement,SiteAnnouncementAdmin)
|
||||||
|
admin.site.register(TeamInvite,TeamInviteAdmin)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# All the data preparation, data cleaning and data mangling should
|
# All the data preparation, data cleaning and data mangling should
|
||||||
# be defined here
|
# be defined here
|
||||||
from rowers.models import Workout, User, Rower
|
from rowers.models import Workout, User, Rower,StrokeData
|
||||||
from rowingdata import rowingdata as rrdata
|
from rowingdata import rowingdata as rrdata
|
||||||
|
|
||||||
from rowers.tasks import handle_sendemail_unrecognized
|
from rowers.tasks import handle_sendemail_unrecognized
|
||||||
@@ -67,6 +67,98 @@ from scipy.signal import savgol_filter
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
def clean_df_stats(datadf,workstrokesonly=True):
|
||||||
|
# clean data remove zeros and negative values
|
||||||
|
datadf=datadf.clip(lower=0)
|
||||||
|
datadf.replace(to_replace=0,value=np.nan,inplace=True)
|
||||||
|
|
||||||
|
# clean data for useful ranges per column
|
||||||
|
mask = datadf['hr'] < 30
|
||||||
|
datadf.loc[mask,'hr'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['rhythm'] < 5
|
||||||
|
datadf.loc[mask,'rhythm'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['rhythm'] > 70
|
||||||
|
datadf.loc[mask,'rhythm'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['power'] < 20
|
||||||
|
datadf.loc[mask,'power'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['drivelength'] < 0.5
|
||||||
|
datadf.loc[mask,'drivelength'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['forceratio'] < 0.2
|
||||||
|
datadf.loc[mask,'forceratio'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['forceratio'] > 1.0
|
||||||
|
datadf.loc[mask,'forceratio'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['spm'] < 10
|
||||||
|
datadf.loc[mask,'spm'] = np.nan
|
||||||
|
|
||||||
|
|
||||||
|
mask = datadf['spm'] > 60
|
||||||
|
datadf.loc[mask,'spm'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['drivespeed'] < 0.5
|
||||||
|
datadf.loc[mask,'drivespeed'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['drivespeed'] > 4
|
||||||
|
datadf.loc[mask,'drivespeed'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['driveenergy'] > 2000
|
||||||
|
datadf.loc[mask,'driveenergy'] = np.nan
|
||||||
|
|
||||||
|
mask = datadf['driveenergy'] < 100
|
||||||
|
datadf.loc[mask,'driveenergy'] = np.nan
|
||||||
|
|
||||||
|
workoutstateswork = [1,4,5,8,9,6,7]
|
||||||
|
workoutstatesrest = [3]
|
||||||
|
workoutstatetransition = [0,2,10,11,12,13]
|
||||||
|
|
||||||
|
if workstrokesonly=='True' or workstrokesonly==True:
|
||||||
|
try:
|
||||||
|
datadf = datadf[~datadf['workoutstate'].isin(workoutstatesrest)]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return datadf
|
||||||
|
|
||||||
|
def getstatsfields():
|
||||||
|
# Get field names and remove those that are not useful in stats
|
||||||
|
fields = StrokeData._meta.get_fields()
|
||||||
|
|
||||||
|
fielddict = {field.name:field.verbose_name for field in fields}
|
||||||
|
|
||||||
|
fielddict.pop('workoutid')
|
||||||
|
fielddict.pop('ergpace')
|
||||||
|
fielddict.pop('hr_an')
|
||||||
|
fielddict.pop('hr_tr')
|
||||||
|
fielddict.pop('hr_at')
|
||||||
|
fielddict.pop('hr_ut2')
|
||||||
|
fielddict.pop('hr_ut1')
|
||||||
|
fielddict.pop('time')
|
||||||
|
fielddict.pop('distance')
|
||||||
|
fielddict.pop('nowindpace')
|
||||||
|
fielddict.pop('fnowindpace')
|
||||||
|
fielddict.pop('fergpace')
|
||||||
|
fielddict.pop('equivergpower')
|
||||||
|
# fielddict.pop('workoutstate')
|
||||||
|
fielddict.pop('fpace')
|
||||||
|
fielddict.pop('pace')
|
||||||
|
fielddict.pop('id')
|
||||||
|
fielddict.pop('ftime')
|
||||||
|
fielddict.pop('x_right')
|
||||||
|
fielddict.pop('hr_max')
|
||||||
|
fielddict.pop('hr_bottom')
|
||||||
|
fielddict.pop('cumdist')
|
||||||
|
|
||||||
|
fieldlist = [field for field,value in fielddict.iteritems()]
|
||||||
|
|
||||||
|
return fieldlist,fielddict
|
||||||
|
|
||||||
|
|
||||||
# A string representation for time deltas
|
# A string representation for time deltas
|
||||||
def niceformat(values):
|
def niceformat(values):
|
||||||
out = []
|
out = []
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from datetimewidget.widgets import DateTimeWidget
|
|||||||
from django.core.validators import validate_email
|
from django.core.validators import validate_email
|
||||||
import os
|
import os
|
||||||
import twitter
|
import twitter
|
||||||
|
import re
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
@@ -50,7 +51,10 @@ database_url = 'mysql://{user}:{password}@{host}:{port}/{database_name}'.format(
|
|||||||
if settings.DEBUG or user=='':
|
if settings.DEBUG or user=='':
|
||||||
database_url = 'sqlite:///db.sqlite3'
|
database_url = 'sqlite:///db.sqlite3'
|
||||||
|
|
||||||
|
class UserFullnameChoiceField(forms.ModelChoiceField):
|
||||||
|
def label_from_instance(self,obj):
|
||||||
|
return obj.get_full_name()
|
||||||
|
|
||||||
# model for Power Zone names
|
# model for Power Zone names
|
||||||
class PowerZonesField(models.TextField):
|
class PowerZonesField(models.TextField):
|
||||||
# __metaclass__ = models.SubfieldBase
|
# __metaclass__ = models.SubfieldBase
|
||||||
@@ -63,6 +67,19 @@ class PowerZonesField(models.TextField):
|
|||||||
if not value: return
|
if not value: return
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
return value
|
return value
|
||||||
|
# remove double quotes and brackets
|
||||||
|
value = re.sub(r'u\"','',value)
|
||||||
|
value = re.sub(r'u\'','',value)
|
||||||
|
value = re.sub(r'\\','',value)
|
||||||
|
value = re.sub(r'\"','',value)
|
||||||
|
value = re.sub(r'\'','',value)
|
||||||
|
value = re.sub(r'\[','',value)
|
||||||
|
value = re.sub(r'\]','',value)
|
||||||
|
value = re.sub(r'\[\[','[',value)
|
||||||
|
value = re.sub(r'\]\]',']',value)
|
||||||
|
value = re.sub(r'\ \ ',' ',value)
|
||||||
|
value = re.sub(r', ',',',value)
|
||||||
|
|
||||||
return value.split(self.token)
|
return value.split(self.token)
|
||||||
|
|
||||||
def from_db_value(self,value, expression, connection, context):
|
def from_db_value(self,value, expression, connection, context):
|
||||||
@@ -83,13 +100,40 @@ class PowerZonesField(models.TextField):
|
|||||||
|
|
||||||
# For future Team functionality
|
# For future Team functionality
|
||||||
class Team(models.Model):
|
class Team(models.Model):
|
||||||
name = models.CharField(max_length=150)
|
choices = (
|
||||||
notes = models.CharField(blank=True,max_length=200)
|
('private','private'),
|
||||||
|
('open','open'),
|
||||||
|
)
|
||||||
|
name = models.CharField(max_length=150,unique=True,verbose_name='Team Name')
|
||||||
|
notes = models.CharField(blank=True,max_length=200,verbose_name='Team Purpose')
|
||||||
manager = models.ForeignKey(User)
|
manager = models.ForeignKey(User)
|
||||||
|
private = models.CharField(max_length=30,choices=choices,default='open',
|
||||||
|
verbose_name='Team Type')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
class TeamForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Team
|
||||||
|
fields = ['name','notes','private']
|
||||||
|
widgets = {
|
||||||
|
'notes': forms.Textarea,
|
||||||
|
}
|
||||||
|
|
||||||
|
class TeamInvite(models.Model):
|
||||||
|
team = models.ForeignKey(Team)
|
||||||
|
user = models.ForeignKey(User,null=True)
|
||||||
|
issuedate = models.DateField(default=timezone.now)
|
||||||
|
code = models.CharField(max_length=150,unique=True)
|
||||||
|
email = models.CharField(max_length=150,null=True,blank=True)
|
||||||
|
|
||||||
|
class TeamInviteForm(ModelForm):
|
||||||
|
user = UserFullnameChoiceField(queryset=User.objects.all(),required=False)
|
||||||
|
class Meta:
|
||||||
|
model = TeamInvite
|
||||||
|
fields = ['user','email']
|
||||||
|
|
||||||
# Extension of User with rowing specific data
|
# Extension of User with rowing specific data
|
||||||
class Rower(models.Model):
|
class Rower(models.Model):
|
||||||
weightcategories = (
|
weightcategories = (
|
||||||
@@ -149,6 +193,8 @@ class Rower(models.Model):
|
|||||||
choices=plans)
|
choices=plans)
|
||||||
|
|
||||||
planexpires = models.DateField(default=timezone.now)
|
planexpires = models.DateField(default=timezone.now)
|
||||||
|
teamplanexpires = models.DateField(default=timezone.now)
|
||||||
|
clubsize = models.IntegerField(default=0)
|
||||||
|
|
||||||
# Friends/Team
|
# Friends/Team
|
||||||
friends = models.ManyToManyField("self",blank=True)
|
friends = models.ManyToManyField("self",blank=True)
|
||||||
@@ -297,7 +343,7 @@ class Workout(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
user = models.ForeignKey(Rower)
|
user = models.ForeignKey(Rower)
|
||||||
team = models.ForeignKey(Team,blank=True,null=True)
|
team = models.ManyToManyField(Team,blank=True)
|
||||||
name = models.CharField(max_length=150)
|
name = models.CharField(max_length=150)
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
workouttype = models.CharField(choices=workouttypes,max_length=50)
|
workouttype = models.CharField(choices=workouttypes,max_length=50)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from utils import serialize_list,deserialize_list
|
|||||||
|
|
||||||
from rowers.dataprepnodjango import update_strokedata
|
from rowers.dataprepnodjango import update_strokedata
|
||||||
|
|
||||||
|
|
||||||
from django.core.mail import send_mail, BadHeaderError,EmailMessage
|
from django.core.mail import send_mail, BadHeaderError,EmailMessage
|
||||||
|
|
||||||
# testing task
|
# testing task
|
||||||
@@ -54,6 +55,7 @@ def handle_sendemail_unrecognized(unrecognizedfile,useremail):
|
|||||||
os.remove(unrecognizedfile)
|
os.remove(unrecognizedfile)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
# Send email with TCX attachment
|
# Send email with TCX attachment
|
||||||
@app.task
|
@app.task
|
||||||
def handle_sendemailtcx(first_name,last_name,email,tcxfile):
|
def handle_sendemailtcx(first_name,last_name,email,tcxfile):
|
||||||
@@ -116,8 +118,11 @@ def handle_otwsetpower(f1,boattype,weightvalue,
|
|||||||
try:
|
try:
|
||||||
rowdata = rdata(f1)
|
rowdata = rdata(f1)
|
||||||
except IOError:
|
except IOError:
|
||||||
rowdata = rdata(f1+'.csv')
|
try:
|
||||||
|
rowdata = rdata(f1+'.csv')
|
||||||
|
except IOError:
|
||||||
|
rowdata = rdata(f1+'.gz')
|
||||||
|
|
||||||
weightvalue = float(weightvalue)
|
weightvalue = float(weightvalue)
|
||||||
|
|
||||||
# do something with boat type
|
# do something with boat type
|
||||||
@@ -154,14 +159,12 @@ def handle_otwsetpower(f1,boattype,weightvalue,
|
|||||||
subject = "Your Rowsandall OTW calculations are ready"
|
subject = "Your Rowsandall OTW calculations are ready"
|
||||||
message = "Dear "+first_name+",\n\n"
|
message = "Dear "+first_name+",\n\n"
|
||||||
message += "Your Rowsandall OTW calculations are ready.\n"
|
message += "Your Rowsandall OTW calculations are ready.\n"
|
||||||
# message += "You can now create OTW plots with power information and wind corrections.\n\n"
|
|
||||||
message += "Thank you for using rowsandall.com.\n\n"
|
message += "Thank you for using rowsandall.com.\n\n"
|
||||||
message += "Rowsandall OTW calculations have not been fully implemented yet.\n"
|
message += "Rowsandall OTW calculations have not been fully implemented yet.\n"
|
||||||
message += "We are now running an experimental version for debugging purposes. \n"
|
message += "We are now running an experimental version for debugging purposes. \n"
|
||||||
message += "Your wind/stream corrected plot is available here: http://rowsandall.com/rowers/workout/"
|
message += "Your wind/stream corrected plot is available here: http://rowsandall.com/rowers/workout/"
|
||||||
message += str(workoutid)
|
message += str(workoutid)
|
||||||
message +="/interactiveotwplot\n\n"
|
message +="/interactiveotwplot\n\n"
|
||||||
# message += "This functionality will be available soon, though.\n\n"
|
|
||||||
message += "Please report any bugs/inconsistencies/unexpected results at rowsandall.slack.com or by reply to this email.\n\n"
|
message += "Please report any bugs/inconsistencies/unexpected results at rowsandall.slack.com or by reply to this email.\n\n"
|
||||||
message += "Best Regards, The Rowsandall Physics Department."
|
message += "Best Regards, The Rowsandall Physics Department."
|
||||||
|
|
||||||
@@ -232,6 +235,53 @@ def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename):
|
|||||||
gc.collect()
|
gc.collect()
|
||||||
return imagename
|
return imagename
|
||||||
|
|
||||||
|
# Team related remote tasks
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def handle_sendemail_invite(email,name,code,teamname,manager):
|
||||||
|
fullemail = name+' <'+email+'>'
|
||||||
|
subject = 'Invitation to join team '+teamname
|
||||||
|
message = 'Dear '+name+',\n\n'
|
||||||
|
message += manager+' is inviting you to join his team '+teamname
|
||||||
|
message += ' on rowsandall.com\n\n'
|
||||||
|
message += 'If you already have an account on rowsandall.com, you can login to the site and you will find the invitation here on the Teams page:\n'
|
||||||
|
message += ' https://rowsandall.com/rowers/me/teams \n\n'
|
||||||
|
message += 'You can also click the direct link: \n'
|
||||||
|
message += 'https://rowsandall.com/rowers/me/invitation/'+code+' \n\n'
|
||||||
|
message += 'If you are not yet registered to rowsandall.com, '
|
||||||
|
message += 'you can register for free at https://rowsandall.com/rowers/register\n'
|
||||||
|
message += 'After you set up your account, you can use the direct link: '
|
||||||
|
message += 'https://rowsandall.com/rowers/me/invitation/'+code+' \n\n'
|
||||||
|
|
||||||
|
message += 'You can also manually accept your team membership with the code.\n'
|
||||||
|
message += 'You will need to do this if you registered under a differnt email address than this one.\n'
|
||||||
|
message += 'Code: '+code+'\n'
|
||||||
|
message += 'Link to manually accept your team membership: '
|
||||||
|
message += 'https://rowsandall.com/rowers/me/invitation\n\n'
|
||||||
|
message += "Best Regards, the Rowsandall Team"
|
||||||
|
|
||||||
|
email = EmailMessage(subject, message,
|
||||||
|
'Rowsandall <info@rowsandall.com>',
|
||||||
|
[fullemail])
|
||||||
|
|
||||||
|
|
||||||
|
res = email.send()
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def handle_remove_workouts_team(ws,t):
|
||||||
|
for w in ws:
|
||||||
|
w.team.remove(t)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def handle_add_workouts_team(ws,t):
|
||||||
|
for w in ws:
|
||||||
|
w.team.add(t)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
# Another simple task for debugging purposes
|
# Another simple task for debugging purposes
|
||||||
def add2(x,y):
|
def add2(x,y):
|
||||||
|
|||||||
208
rowers/teams.py
Normal file
208
rowers/teams.py
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
# 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 django.conf import settings
|
||||||
|
|
||||||
|
from rowers.models import (
|
||||||
|
Rower, Workout, Team, TeamInvite,User
|
||||||
|
)
|
||||||
|
|
||||||
|
from rowers.tasks import (
|
||||||
|
handle_remove_workouts_team,handle_sendemail_invite,
|
||||||
|
handle_add_workouts_team
|
||||||
|
)
|
||||||
|
|
||||||
|
# Low level functions - to be called by higher level methods
|
||||||
|
|
||||||
|
inviteduration = 14 # days
|
||||||
|
|
||||||
|
def create_team(name,manager,private='open',notes=''):
|
||||||
|
# needs some error testing
|
||||||
|
try:
|
||||||
|
t = Team(name=name,manager=manager,notes=notes,
|
||||||
|
private=private)
|
||||||
|
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 set_teamplanexpires(rower):
|
||||||
|
ts = Team.objects.filter(rower=rower)
|
||||||
|
|
||||||
|
texp = datetime.date(timezone.now())
|
||||||
|
|
||||||
|
for t in ts:
|
||||||
|
mr = Rower.objects.get(user=t.manager)
|
||||||
|
if mr.teamplanexpires > texp:
|
||||||
|
rower.teamplanexpires = mr.teamplanexpires
|
||||||
|
|
||||||
|
t.save()
|
||||||
|
|
||||||
|
return (1,'Updated rower team expiry')
|
||||||
|
|
||||||
|
def add_member(id,rower):
|
||||||
|
t= Team.objects.get(id=id)
|
||||||
|
rower.team.add(t)
|
||||||
|
# code to add all workouts
|
||||||
|
ws = Workout.objects.filter(user=rower)
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
res = handle_add_workouts_team(ws,t)
|
||||||
|
else:
|
||||||
|
res = queuehigh.enqueue(handle_add_workouts_team,ws,t)
|
||||||
|
|
||||||
|
|
||||||
|
set_teamplanexpires(rower)
|
||||||
|
|
||||||
|
return (id,'Member added')
|
||||||
|
|
||||||
|
def remove_member(id,rower):
|
||||||
|
t = Team.objects.get(id=id)
|
||||||
|
rower.team.remove(t)
|
||||||
|
# remove the team from rower's workouts:
|
||||||
|
ws = Workout.objects.filter(user=rower,team=t)
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
res = handle_remove_workouts_team(ws,t)
|
||||||
|
else:
|
||||||
|
res = queuehigh.enqueue(handle_remove_workouts_team,ws,t)
|
||||||
|
|
||||||
|
set_teamplanexpires(rower)
|
||||||
|
return (id,'Member removed')
|
||||||
|
|
||||||
|
def mgr_remove_member(id,manager,rower):
|
||||||
|
t = Team.objects.get(id=id)
|
||||||
|
if t.manager == manager:
|
||||||
|
remove_member(id,rower)
|
||||||
|
return (id,'Member removed')
|
||||||
|
else:
|
||||||
|
return (0,'You are not the team manager')
|
||||||
|
|
||||||
|
return (0,'')
|
||||||
|
|
||||||
|
def count_invites(manager):
|
||||||
|
ts = Team.objects.filter(manager=manager)
|
||||||
|
count = 0
|
||||||
|
for t in ts:
|
||||||
|
count += TeamInvite.objects.filter(team=t).count()
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
def get_team_workouts(id):
|
||||||
|
t = Team.objects.get(id=id)
|
||||||
|
return Workout.objects.filter(team=t).order_by("-date", "-starttime")
|
||||||
|
|
||||||
|
# Medium level functionality
|
||||||
|
|
||||||
|
def create_invite(team,manager,user=None,email=''):
|
||||||
|
r = Rower.objects.get(user=manager)
|
||||||
|
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')
|
||||||
|
elif email==None or email=='':
|
||||||
|
return (0,'Invalid request - missing email or user')
|
||||||
|
|
||||||
|
if count_club_members(team.manager)+count_invites(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,email=email)
|
||||||
|
invite.save()
|
||||||
|
return (invite.id,'Invitation created')
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
return (0,'You are at your club size limit')
|
||||||
|
|
||||||
|
return (0,'Nothing done')
|
||||||
|
|
||||||
|
def revoke_invite(id):
|
||||||
|
invitation = TeamInvite.objects.get(id=id)
|
||||||
|
invitation.delete()
|
||||||
|
|
||||||
|
return (1,'Invitation revoked')
|
||||||
|
|
||||||
|
|
||||||
|
def send_invite_email(id):
|
||||||
|
invitation = TeamInvite.objects.get(id=id)
|
||||||
|
if invitation.user:
|
||||||
|
email = invitation.user.email
|
||||||
|
name = invitation.user.first_name + " " + invitation.user.last_name
|
||||||
|
else:
|
||||||
|
email = invitation.email
|
||||||
|
name = ''
|
||||||
|
|
||||||
|
code = invitation.code
|
||||||
|
teamname = invitation.team.name
|
||||||
|
manager = invitation.team.manager.first_name+' '+invitation.team.manager.last_name
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
res = handle_sendemail_invite.delay(email,name,code,teamname,manager)
|
||||||
|
else:
|
||||||
|
queue.enqueue(handle_sendemail_invite,email,name,code,teamname,manager)
|
||||||
|
|
||||||
|
return (1,'Invitation email sent')
|
||||||
|
|
||||||
|
def process_invite_code(user,code):
|
||||||
|
code = code.upper()
|
||||||
|
try:
|
||||||
|
invitation = TeamInvite.objects.get(code=code)
|
||||||
|
except TeamInvite.DoesNotExist:
|
||||||
|
return (0,'The invitation has expired or the code is invalid')
|
||||||
|
|
||||||
|
r = Rower.objects.get(user=user)
|
||||||
|
nu = datetime.date(timezone.now())
|
||||||
|
if nu > invitation.issuedate+timedelta(days=inviteduration):
|
||||||
|
revoke_invite(invitation.id)
|
||||||
|
return (0,'The invitation has expired')
|
||||||
|
|
||||||
|
t = invitation.team
|
||||||
|
result = add_member(t.id,r)
|
||||||
|
invitation.delete()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def remove_expired_invites():
|
||||||
|
issuedate = timezone.now()-timedelta(days=inviteduration)
|
||||||
|
issuedate = datetime.date(issuedate)
|
||||||
|
invitations = TeamInvite.objects.filter(issuedate__lt=issuedate)
|
||||||
|
for i in invitations:
|
||||||
|
revoke_invite(i.id)
|
||||||
|
|
||||||
|
return (1,'Expired invitations deleted')
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
|
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership/">Compare Workouts</a>
|
<a class="button blue small" href="/rowers/promembership/">Compare Workouts</a>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 omega tooltip">
|
<div class="grid_2 omega tooltip">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
|
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid_2">
|
<div class="grid_2">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a>
|
<a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a>
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 suffix_4 alpha">
|
<div class="grid_2 suffix_4 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/histo">Power Histogram</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/histo">Power Histogram</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
|
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Compare Workouts</a>
|
<a class="button blue small" href="/rowers/promembership">Compare Workouts</a>
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 omega tooltip">
|
<div class="grid_2 omega tooltip">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
|
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/crewnerdsummary">CrewNerd Summary</a>
|
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/crewnerdsummary">CrewNerd Summary</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">CrewNerd Summary</a>
|
<a class="button blue small" href="/rowers/promembership">CrewNerd Summary</a>
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 tooltip">
|
<div class="grid_2 tooltip">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/forcecurve">Stroke Profile (Empower)</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/forcecurve">Stroke Profile (Empower)</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Stroke Profile (Empower)</a>
|
<a class="button blue small" href="/rowers/promembership">Stroke Profile (Empower)</a>
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 omega tooltip">
|
<div class="grid_2 omega tooltip">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addotwpowerplot">OTW Power Plot</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addotwpowerplot">OTW Power Plot</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">OTW Power Plot</a>
|
<a class="button blue small" href="/rowers/promembership">OTW Power Plot</a>
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/geeky">Geeky Stuff</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/geeky">Geeky Stuff</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Geeky Stuff</a>
|
<a class="button blue small" href="/rowers/promembership">Geeky Stuff</a>
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 tooltip">
|
<div class="grid_2 tooltip">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/smoothenpace">Smooth out Pace Data</a>
|
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/smoothenpace">Smooth out Pace Data</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Smooth out Pace Data</a>
|
<a class="button blue small" href="/rowers/promembership">Smooth out Pace Data</a>
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 omega">
|
<div class="grid_2 omega">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/undosmoothenpace">Raw Data</a>
|
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/undosmoothenpace">Raw Data</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Reset Smoothing</a>
|
<a class="button blue small" href="/rowers/promembership">Reset Smoothing</a>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<h2>Pro</h2>
|
<h2>Pro</h2>
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/histo">Power Histogram</a>
|
<a class="button blue small" href="/rowers/histo">Power Histogram</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Power Histogram</a>
|
<a class="button blue small" href="/rowers/promembership">Power Histogram</a>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid_2">
|
<div class="grid_2">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/cumstats">Statistics</a>
|
<a class="button blue small" href="/rowers/cumstats">Statistics</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Statistics</a>
|
<a class="button blue small" href="/rowers/promembership">Statistics</a>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
{% analytical_body_top %}
|
{% analytical_body_top %}
|
||||||
<div class="container_12">
|
<div class="container_12">
|
||||||
<div id="logo" class="grid_2">
|
<div id="logo" class="grid_2">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<p><a href="/"><img src="/static/img/logocroppedpro.gif"
|
<p><a href="/"><img src="/static/img/logocroppedpro.gif"
|
||||||
alt="Rowsandall logo" width="110" heigt="110"></a></p>
|
alt="Rowsandall logo" width="110" heigt="110"></a></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
|
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_3">
|
<div class="grid_3">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<h6>Pro Member</h6>
|
<h6>Pro Member</h6>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p> </p>
|
<p> </p>
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
<p>
|
<p>
|
||||||
<a class="button gray small" href="/rowers/me/edit">{{ user.first_name }}</a>
|
<a class="button gray small" href="/rowers/me/edit">{{ user.first_name }}</a>
|
||||||
</p>
|
</p>
|
||||||
<span class="tooltiptext">Edit user data, e.g. heart rate zones</span>
|
<span class="tooltiptext">Edit user account, e.g. heart rate zones, power zones, email, teams</span>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p><a class="button gray small" href="{% url 'login' %}">login</a> </p>
|
<p><a class="button gray small" href="{% url 'login' %}">login</a> </p>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="container_12">
|
<div class="container_12">
|
||||||
<div id="logo" class="grid_2">
|
<div id="logo" class="grid_2">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<p><a href="/"><img src="/static/img/logocroppedpro.gif"
|
<p><a href="/"><img src="/static/img/logocroppedpro.gif"
|
||||||
alt="Rowsandall logo" width="110" heigt="110"></a></p>
|
alt="Rowsandall logo" width="110" heigt="110"></a></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
|
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_3">
|
<div class="grid_3">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<h6>Pro Member</h6>
|
<h6>Pro Member</h6>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p> </p>
|
<p> </p>
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
<div class="grid_8 omega">
|
<div class="grid_8 omega">
|
||||||
{% if cordict %}
|
{% if cordict %}
|
||||||
<h2> Correlation Matrix</h2>
|
<h2> Correlation Matrix</h2>
|
||||||
<p>This table indicates a positive (+) or negative (-) correlation between two parameters. The strong correlations are indicated with ++ and --.
|
<p>This matrix indicates a positive (+) or negative (-) correlation between two parameters. The Spearman correlation coefficient has values between +1 and -1. Positive correlation between two metrics means that if one metric increases, the other value is also likely to increase. Negative is the opposite. The further from zero, the higher the likelyhood.
|
||||||
</p>
|
</p>
|
||||||
<table width="90%" class="cortable">
|
<table width="90%" class="cortable">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -116,13 +116,13 @@
|
|||||||
{% for key2,value in thedict.items %}
|
{% for key2,value in thedict.items %}
|
||||||
<td>
|
<td>
|
||||||
{% if value > 0.5 %}
|
{% if value > 0.5 %}
|
||||||
<div class="poscor">++</div>
|
<div class="poscor">{{ value|floatformat:-1 }}</div>
|
||||||
{% elif value > 0.1 %}
|
{% elif value > 0.1 %}
|
||||||
<div class="weakposcor">+</div>
|
<div class="weakposcor">{{ value|floatformat:-1 }}</div>
|
||||||
{% elif value < -0.5 %}
|
{% elif value < -0.5 %}
|
||||||
<div class="negcor">--</div>
|
<div class="negcor">{{ value|floatformat:-1 }}</div>
|
||||||
{% elif value < -0.1 %}
|
{% elif value < -0.1 %}
|
||||||
<div class="weaknegcor">-</div>
|
<div class="weaknegcor">{{ value|floatformat:-1 }}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -168,7 +168,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<div id="favorites" class="grid_12 alpha">
|
<div id="favorites" class="grid_12 alpha">
|
||||||
<div class="grid_2 suffix_4 alpha">
|
<div class="grid_2 suffix_4 alpha">
|
||||||
{% if maxfav >= 0 %}
|
{% if maxfav >= 0 %}
|
||||||
|
|||||||
@@ -203,7 +203,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<div id="favorites" class="grid_12 alpha">
|
<div id="favorites" class="grid_12 alpha">
|
||||||
<div class="grid_2 suffix_4 alpha">
|
<div class="grid_2 suffix_4 alpha">
|
||||||
{% if maxfav >= 0 %}
|
{% if maxfav >= 0 %}
|
||||||
|
|||||||
27
rowers/templates/invitations.html
Normal file
27
rowers/templates/invitations.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Teams {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<p>
|
||||||
|
<h2>Invitations</h2>
|
||||||
|
|
||||||
|
Future invitations page
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="grid_6 omega">
|
||||||
|
<p>
|
||||||
|
<h2>Manual with Code</h2>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/wind">Edit Wind Data</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/wind">Edit Wind Data</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/about">Edit Wind Data</a>
|
<a class="button blue small" href="/rowers/about">Edit Wind Data</a>
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid_2">
|
<div class="grid_2">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/stream">Edit Stream Data</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/stream">Edit Stream Data</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/about">Edit Stream Data</a>
|
<a class="button blue small" href="/rowers/about">Edit Stream Data</a>
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid_2 omega">
|
<div class="grid_2 omega">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/about">OTW Power</a>
|
<a class="button blue small" href="/rowers/about">OTW Power</a>
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
|
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveotwplot">Corrected Pace Plot</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveotwplot">Corrected Pace Plot</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/about">Corrected Pace Plot</a>
|
<a class="button blue small" href="/rowers/about">Corrected Pace Plot</a>
|
||||||
@@ -159,4 +159,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -3,107 +3,124 @@
|
|||||||
{% block title %}Change Rower {% endblock %}
|
{% block title %}Change Rower {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid_6 alpha">
|
<div class="grid_12 alpha">
|
||||||
<p>
|
<div class="grid_6 alpha">
|
||||||
<h2>Heart Rate Zones</h2>
|
<p>
|
||||||
{% if form.errors %}
|
<h2>Heart Rate Zones</h2>
|
||||||
<p style="color: red;">
|
{% if form.errors %}
|
||||||
Please correct the error{{ form.errors|pluralize }} below.
|
<p style="color: red;">
|
||||||
</p>
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
{% endif %}
|
</p>
|
||||||
|
{% endif %}
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
|
||||||
<table>
|
|
||||||
{{ form.as_table }}
|
|
||||||
</table>
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="grid_2 prefix_2 suffix_2">
|
|
||||||
<input class="button green" type="submit" value="Save">
|
|
||||||
</form>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<h2>Account Information</h2>
|
|
||||||
{% if userform.errors %}
|
|
||||||
<p style="color: red;">
|
|
||||||
Please correct the error{{ form.errors|pluralize }} below.
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% if accountform.errors %}
|
|
||||||
<p style="color: red;">
|
|
||||||
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
|
||||||
<table>
|
|
||||||
{{ userform.as_table }}
|
|
||||||
{{ accountform.as_table }}
|
|
||||||
<tr>
|
|
||||||
<td>Plan</td><td>{{ rower.rowerplan }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="grid_2 prefix_2 suffix_2">
|
|
||||||
<input class="button green" type="submit" value="Save">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="grid_6 omega">
|
|
||||||
<p>
|
|
||||||
<h2>Power Zones</h2>
|
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
{% if powerzonesform.errors %}
|
|
||||||
<p style="color: red;">
|
|
||||||
Please correct the error{{ powerzonesform.errors|pluralize }} below.
|
|
||||||
{{ powerzonesform.non_field_errors }}
|
|
||||||
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
{{ form.as_table }}
|
||||||
<tr>
|
|
||||||
<th>ID</th><th>Zone Name</th><th>Lower Boundary (Watt)</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>1</td><td>{{ powerzonesform.ut3name }}</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>2</td><td>{{ powerzonesform.ut2name }}</td>
|
|
||||||
<td>{{ powerzonesform.pw_ut2 }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>3</td><td>{{ powerzonesform.ut1name }}</td>
|
|
||||||
<td>{{ powerzonesform.pw_ut1 }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>4</td><td>{{ powerzonesform.atname }}</td>
|
|
||||||
<td>{{ powerzonesform.pw_at }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>5</td><td>{{ powerzonesform.trname }}</td>
|
|
||||||
<td>{{ powerzonesform.pw_tr }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>6</td><td>{{ powerzonesform.anname }}</td>
|
|
||||||
<td>{{ powerzonesform.pw_an }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="grid_2 prefix_2 suffix_2">
|
<div class="grid_2 prefix_2 suffix_2">
|
||||||
<input class="button green" type="submit" value="Save">
|
<input class="button green" type="submit" value="Save">
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
</div>
|
||||||
<h2>Functional Threshold Power</h2>
|
</div>
|
||||||
<p>Use this form to quickly change your zones based on the power of a
|
<div class="grid_6 omega">
|
||||||
recent
|
<p>
|
||||||
full out 60 minutes effort. It will update all zones defined above.</p>
|
<h2>Power Zones</h2>
|
||||||
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
{% if powerzonesform.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ powerzonesform.errors|pluralize }} below.
|
||||||
|
{{ powerzonesform.non_field_errors }}
|
||||||
|
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th><th>Zone Name</th><th>Lower Boundary (Watt)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>1</td><td>{{ powerzonesform.ut3name }}</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td><td>{{ powerzonesform.ut2name }}</td>
|
||||||
|
<td>{{ powerzonesform.pw_ut2 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>3</td><td>{{ powerzonesform.ut1name }}</td>
|
||||||
|
<td>{{ powerzonesform.pw_ut1 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>4</td><td>{{ powerzonesform.atname }}</td>
|
||||||
|
<td>{{ powerzonesform.pw_at }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>5</td><td>{{ powerzonesform.trname }}</td>
|
||||||
|
<td>{{ powerzonesform.pw_tr }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>6</td><td>{{ powerzonesform.anname }}</td>
|
||||||
|
<td>{{ powerzonesform.pw_an }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="grid_2 prefix_2 suffix_2">
|
||||||
|
<input class="button green" type="submit" value="Save">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<p>
|
||||||
|
<h2>Account Information</h2>
|
||||||
|
{% if userform.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if accountform.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
<table>
|
||||||
|
{{ userform.as_table }}
|
||||||
|
{{ accountform.as_table }}
|
||||||
|
<tr>
|
||||||
|
<th>Plan</th><td>{{ rower.rowerplan }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Plan Expiry</th><td>{{ rower.planexpires }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="grid_2 alpha">
|
||||||
|
{% if rower.rowerplan == 'basic' %}
|
||||||
|
<a class="button blue" href="/rowers/promembership">Upgrade</a>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 suffix_2 omega">
|
||||||
|
<input class="button green" type="submit" value="Save">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid_6 omega">
|
||||||
|
<p>
|
||||||
|
<h2>Functional Threshold Power</h2>
|
||||||
|
<p>Use this form to quickly change your zones based on the power of a
|
||||||
|
recent
|
||||||
|
full out 60 minutes effort. It will update all zones defined above.</p>
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
<table>
|
<table>
|
||||||
{{ powerform.as_table }}
|
{{ powerform.as_table }}
|
||||||
@@ -113,43 +130,61 @@
|
|||||||
<input class="button green" type="submit" value="Save">
|
<input class="button green" type="submit" value="Save">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</div>
|
||||||
{% if grants %}
|
</div>
|
||||||
<p>
|
<div class="grid_12 alpha">
|
||||||
<h2>Applications</h2>
|
<div class="grid_6 alpha">
|
||||||
<table width="100%">
|
<p>
|
||||||
<thead>
|
<h2>Teams</h2>
|
||||||
<tr>
|
<div class="grid_2 suffix_4 alpha">
|
||||||
<th>Application</th>
|
<a class="button gray small" href="/rowers/me/teams">Manage Teams</a>
|
||||||
<th>Scope</th>
|
</div>
|
||||||
<th>Revoke</th>
|
</p>
|
||||||
</tr>
|
</div>
|
||||||
</thead>
|
|
||||||
<tbody>
|
<div class="grid_6 omega">
|
||||||
{% for grant in grants %}
|
<p>
|
||||||
<tr>
|
<h2>Favorite Charts</h2>
|
||||||
<td>{{ grant.application }}</td>
|
<div class="grid_2 suffix_4 alpha">
|
||||||
<td>{{ grant.scope }}</td>
|
<a class="button gray small" href="/rowers/me/favoritecharts">Manage Favorite Charts</a>
|
||||||
<td>
|
</div>
|
||||||
<a class="button red small" href="/rowers/me/revokeapp/{{ grant.application.id }}">Revoke</a>
|
</p>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid_12 alpha">
|
||||||
<div class="grid_6 prefix_6 alpha">
|
<div class="grid_6 suffix_6 alpha">
|
||||||
<p>
|
{% if grants %}
|
||||||
<h2>Favorite Charts</h2>
|
<p>
|
||||||
<div class="grid_2 suffix_4 alpha">
|
<h2>Applications</h2>
|
||||||
<a class="button gray small" href="/rowers/me/favoritecharts">Manage Favorite Charts</a>
|
<table width="100%">
|
||||||
</div>
|
<thead>
|
||||||
</p>
|
<tr>
|
||||||
|
<th>Application</th>
|
||||||
|
<th>Scope</th>
|
||||||
|
<th>Revoke</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for grant in grants %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ grant.application }}</td>
|
||||||
|
<td>{{ grant.scope }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="button red small" href="/rowers/me/revokeapp/{{ grant.application.id }}">Revoke</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p> </p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
70
rowers/templates/team.html
Normal file
70
rowers/templates/team.html
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Team {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<h1>{{ team.name }}</h1>
|
||||||
|
<p>{{ team.notes }}</p>
|
||||||
|
<p><b>Manager:</b> {{ team.manager.first_name }} {{ team.manager.last_name }}</p>
|
||||||
|
{% if ismember %}
|
||||||
|
<div class="grid_2 suffix_10 alpha">
|
||||||
|
<a class="button red small" href="/rowers/team/{{ team.id }}/leaveconfirm">Leave this team</a>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="grid_2 suffix_10 alpha tooltip">
|
||||||
|
<a class="button green small" href="/rowers/team/{{ team.id }}/requestmembership/{{ user.id }}">Join</a>
|
||||||
|
<span class="tooltiptext">A request will be sent to the team manager</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<p>
|
||||||
|
<h2>Members</h2>
|
||||||
|
<table width="100%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for member in members %}
|
||||||
|
<tr>
|
||||||
|
<td> {{ member.user.first_name }} {{ member.user.last_name }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="grid_6 omega">
|
||||||
|
{% if team.manager == user %}
|
||||||
|
<p>Use the form to add a new user. You can either select a user from the slist, or you can type his email address, which also works for users who have not registered to the site yet.</p>
|
||||||
|
{% if inviteform.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ inviteform.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||||
|
<table>
|
||||||
|
{{ inviteform.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
|
||||||
|
<input class="button green" type="submit" value="Submit">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
28
rowers/templates/teamcreate.html
Normal file
28
rowers/templates/teamcreate.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
|
||||||
|
{% block title %}New Team{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||||
|
<div id="left" class="grid_6 alpha">
|
||||||
|
<h1>Create a new Team</h1>
|
||||||
|
{% if form.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
|
||||||
|
<input class="button green" type="submit" value="Submit">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
43
rowers/templates/teamdeleteconfirm.html
Normal file
43
rowers/templates/teamdeleteconfirm.html
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
|
{% block title %}Leave Team {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="workouts" class="grid_6 alpha">
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1>Confirm Deleting the team {{ team.name }}</h1>
|
||||||
|
<p>This will remove the team. Your team members and their workouts
|
||||||
|
will not be deleted.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="grid_2 alpha">
|
||||||
|
<p>
|
||||||
|
<a class="button green small" href="/rowers/team/{{ team.id }}">Cancel</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid_2">
|
||||||
|
<p>
|
||||||
|
<a class="button red small" href="/rowers/team/{{ team.id }}/delete">Delete</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="images" class="grid_6 omega">
|
||||||
|
<p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
45
rowers/templates/teamleaveconfirm.html
Normal file
45
rowers/templates/teamleaveconfirm.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
|
{% block title %}Leave Team {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="workouts" class="grid_6 alpha">
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1>Confirm Leaving the team {{ team.name }}</h1>
|
||||||
|
<p>This will remove you and all your workouts from the team. If this
|
||||||
|
is a closed team, you can only return when the team manager
|
||||||
|
reinvites you.
|
||||||
|
If this is an open team, you can return by applying for team membership.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="grid_2 alpha">
|
||||||
|
<p>
|
||||||
|
<a class="button green small" href="/rowers/team/{{ team.id }}">Cancel</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid_2">
|
||||||
|
<p>
|
||||||
|
<a class="button red small" href="/rowers/team/{{ team.id }}/leave">Leave</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="images" class="grid_6 omega">
|
||||||
|
<p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
133
rowers/templates/teams.html
Normal file
133
rowers/templates/teams.html
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Teams {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<p>
|
||||||
|
<h2>My Teams</h2>
|
||||||
|
{% if teams %}
|
||||||
|
<table width="70%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for team in teams %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/team/{{ team.id }}/">{{ team.name }}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="grid_1">
|
||||||
|
<a class="button small red" href="/rowers/team/{{ team.id }}/leaveconfirm">Leave</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p>You are not a member of any team.</p>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="grid_6 omega">
|
||||||
|
{% if invites %}
|
||||||
|
<p>
|
||||||
|
<h2>Invitations</h2>
|
||||||
|
<table width="70%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Manager</th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for i in invites %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="/rowers/team/{{ i.team.id }}">{{ i.team.name }}</a></td>
|
||||||
|
<td>{{ i.team.manager.first_name }} {{ i.team.manager.last_name }}</td>
|
||||||
|
<td><a class="button small green" href="/rowers/me/invitation/{{ i.code }}">Accept</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p> </p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if user.rower.rowerplan == 'coach' %}
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<h2>Teams I manage</h2>
|
||||||
|
{% if myteams %}
|
||||||
|
<table width="70%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Manager</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for team in myteams %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/team/{{ team.id }}/">{{ team.name }}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="grid_1">
|
||||||
|
<a class="button small red" href="/rowers/team/{{ team.id }}/deleteconfirm">Delete</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
<div class="grid_2 suffix_4 alpha">
|
||||||
|
<a class="button green" href="/rowers/team/create">New Team</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid_6 omega">
|
||||||
|
{% if otherteams %}
|
||||||
|
<h2>Other Teams</h2>
|
||||||
|
<table width="70%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Manager</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for team in otherteams %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/team/{{ team.id }}/">{{ team.name }}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ team.manager.first_name }} {{ team.manager.last_name }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<p> </p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -75,8 +75,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid_8 omega">
|
<div class="grid_8 omega">
|
||||||
{% if cordict %}
|
{% if cordict %}
|
||||||
<h2> Correlation table</h2>
|
<h2> Correlation matrix</h2>
|
||||||
<p>This table indicates a positive (+) or negative (-) correlation between two parameters. The strong correlations are indicated with ++ and --.
|
<p>This matrix indicates a positive (+) or negative (-) correlation between two parameters. The Spearman correlation coefficient has values between +1 and -1. Positive correlation between two metrics means that if one metric increases, the other value is also likely to increase. Negative is the opposite. The further from zero, the higher the likelyhood.
|
||||||
</p>
|
</p>
|
||||||
<table width="90%" class="cortable">
|
<table width="90%" class="cortable">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -94,13 +94,13 @@
|
|||||||
{% for key2,value in thedict.items %}
|
{% for key2,value in thedict.items %}
|
||||||
<td>
|
<td>
|
||||||
{% if value > 0.5 %}
|
{% if value > 0.5 %}
|
||||||
<div class="poscor">++</div>
|
<div class="poscor">{{ value|floatformat:-1 }}</div>
|
||||||
{% elif value > 0.1 %}
|
{% elif value > 0.1 %}
|
||||||
<div class="weakposcor">+</div>
|
<div class="weakposcor">{{ value|floatformat:-1 }}</div>
|
||||||
{% elif value < -0.5 %}
|
{% elif value < -0.5 %}
|
||||||
<div class="negcor">--</div>
|
<div class="negcor">{{ value|floatformat:-1 }}</div>
|
||||||
{% elif value < -0.1 %}
|
{% elif value < -0.1 %}
|
||||||
<div class="weaknegcor">-</div>
|
<div class="weaknegcor">{{ value|floatformat:-1 }}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -199,6 +199,20 @@ urlpatterns = [
|
|||||||
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),
|
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),
|
||||||
url(r'^workout/(\d+)/recalcsummary/$',views.workout_recalcsummary_view),
|
url(r'^workout/(\d+)/recalcsummary/$',views.workout_recalcsummary_view),
|
||||||
url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
|
url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
|
||||||
|
url(r'^me/teams/$',views.rower_teams_view),
|
||||||
|
url(r'^team/(?P<id>\d+)/s/(?P<successmessage>\w+.*)/c/(?P<message>\w+.*)$',views.team_view),
|
||||||
|
url(r'^team/(?P<id>\d+)/c/(?P<message>\w+.*)$',views.team_view),
|
||||||
|
url(r'^team/(?P<id>\d+)/s/(?P<successmessage>\w+.*)$',views.team_view),
|
||||||
|
url(r'^team/(\d+)/$',views.team_view),
|
||||||
|
url(r'^team/(\d+)/leaveconfirm/$',views.team_leaveconfirm_view),
|
||||||
|
url(r'^team/(\d+)/leave/$',views.team_leave_view),
|
||||||
|
url(r'^team/(\d+)/deleteconfirm/$',views.team_deleteconfirm_view),
|
||||||
|
url(r'^team/(\d+)/requestmembership/(\d+)$',views.team_requestmembership_view),
|
||||||
|
url(r'^team/(\d+)/delete/$',views.team_delete_view),
|
||||||
|
url(r'^team/create/$',views.team_create_view),
|
||||||
|
url(r'^me/invitation/$',views.rower_invitations_view),
|
||||||
|
url(r'^me/invitation/c/(?P<message>\w+.*)/$',views.rower_invitations_view),
|
||||||
|
url(r'^me/invitation/(\w+.*)/$',views.rower_invitations_view),
|
||||||
url(r'^me/edit/c/(?P<message>\w+.*)$',views.rower_edit_view),
|
url(r'^me/edit/c/(?P<message>\w+.*)$',views.rower_edit_view),
|
||||||
url(r'^me/edit/s/(?P<successmessage>\w+.*)$',views.rower_edit_view),
|
url(r'^me/edit/s/(?P<successmessage>\w+.*)$',views.rower_edit_view),
|
||||||
url(r'^me/edit/$',views.rower_edit_view),
|
url(r'^me/edit/$',views.rower_edit_view),
|
||||||
|
|||||||
412
rowers/views.py
412
rowers/views.py
@@ -31,6 +31,7 @@ from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart
|
|||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
||||||
RowerPowerZonesForm,AccountRowerForm,UserForm,StrokeData,
|
RowerPowerZonesForm,AccountRowerForm,UserForm,StrokeData,
|
||||||
|
Team,TeamForm,TeamInviteForm,TeamInvite
|
||||||
)
|
)
|
||||||
from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement
|
from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement
|
||||||
from django.forms.formsets import formset_factory
|
from django.forms.formsets import formset_factory
|
||||||
@@ -57,6 +58,7 @@ from rest_framework.parsers import JSONParser
|
|||||||
from rowers.rows import handle_uploaded_file
|
from rowers.rows import handle_uploaded_file
|
||||||
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
|
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
|
||||||
from rowers.tasks import handle_sendemail_unrecognized
|
from rowers.tasks import handle_sendemail_unrecognized
|
||||||
|
|
||||||
from scipy.signal import savgol_filter
|
from scipy.signal import savgol_filter
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from Cookie import SimpleCookie
|
from Cookie import SimpleCookie
|
||||||
@@ -198,8 +200,14 @@ def splitstdata(lijst):
|
|||||||
|
|
||||||
from utils import geo_distance,serialize_list,deserialize_list
|
from utils import geo_distance,serialize_list,deserialize_list
|
||||||
|
|
||||||
|
# Check if a user is a Coach member
|
||||||
|
def iscoachmember(user):
|
||||||
|
r = Rower.objects.get(user=user)
|
||||||
|
result = user.is_authenticated() and (r.rowerplan=='coach')
|
||||||
|
return result
|
||||||
|
|
||||||
# Check if a user is a Pro member
|
# Check if a user is a Pro member
|
||||||
def promember(user):
|
def ispromember(user):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach')
|
result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach')
|
||||||
return result
|
return result
|
||||||
@@ -1301,7 +1309,7 @@ def histo_all(request,theuser=0):
|
|||||||
|
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
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:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
|
|
||||||
@@ -1371,7 +1379,7 @@ def cum_flex(request,theuser=0,
|
|||||||
|
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
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:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
|
|
||||||
@@ -1463,14 +1471,14 @@ def cum_flex(request,theuser=0,
|
|||||||
})
|
})
|
||||||
|
|
||||||
# Show the EMpower Oarlock generated Stroke Profile
|
# 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):
|
def workout_forcecurve_view(request,id=0,workstrokesonly=False):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
promember=0
|
promember=0
|
||||||
mayedit=0
|
mayedit=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
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:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
if request.user == row.user.user:
|
if request.user == row.user.user:
|
||||||
@@ -1509,7 +1517,7 @@ def workout_histo_view(request,id=0):
|
|||||||
mayedit=0
|
mayedit=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
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:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
if request.user == row.user.user:
|
if request.user == row.user.user:
|
||||||
@@ -1561,7 +1569,7 @@ def histo(request,theuser=0,
|
|||||||
|
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
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:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
|
|
||||||
@@ -1671,7 +1679,7 @@ def rankings_view(request,theuser=0,
|
|||||||
promember=0
|
promember=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
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:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
|
|
||||||
@@ -2040,7 +2048,7 @@ def workouts_view(request,message='',successmessage='',
|
|||||||
return HttpResponse("User has no rower instance")
|
return HttpResponse("User has no rower instance")
|
||||||
|
|
||||||
# List of workouts to compare a selected workout to
|
# 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='',
|
def workout_comparison_list(request,id=0,message='',successmessage='',
|
||||||
startdatestring="",enddatestring="",
|
startdatestring="",enddatestring="",
|
||||||
startdate=timezone.now()-datetime.timedelta(days=365),
|
startdate=timezone.now()-datetime.timedelta(days=365),
|
||||||
@@ -2155,7 +2163,7 @@ def workout_view(request,id=0):
|
|||||||
except Workout.DoesNotExist:
|
except Workout.DoesNotExist:
|
||||||
return HttpResponseNotFound("Workout doesn't exist")
|
return HttpResponseNotFound("Workout doesn't exist")
|
||||||
|
|
||||||
# Resets stroke data to raw data (pace)
|
# Resets stroke data to raw data (pace)
|
||||||
@user_passes_test(ispromember,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=""):
|
def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
@@ -2182,7 +2190,7 @@ def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""):
|
|||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
# Data smoothing of pace data
|
# Data smoothing of pace data
|
||||||
@user_passes_test(ispromember,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=""):
|
def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
@@ -2218,7 +2226,7 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
|
|||||||
|
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
# Process CrewNerd Summary CSV and update summary
|
# Process CrewNerd Summary CSV and update summary
|
||||||
@user_passes_test(ispromember,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=""):
|
def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
@@ -2263,7 +2271,7 @@ def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
|
|||||||
{'form':form,
|
{'form':form,
|
||||||
'id':row.id})
|
'id':row.id})
|
||||||
|
|
||||||
# Get weather for given location and date/time
|
# Get weather for given location and date/time
|
||||||
@user_passes_test(ispromember,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=""):
|
def workout_downloadwind_view(request,id=0,message="",successmessage=""):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
@@ -2320,7 +2328,7 @@ def workout_downloadwind_view(request,id=0,message="",successmessage=""):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# Show form to update wind data
|
# Show form to update wind data
|
||||||
@user_passes_test(ispromember,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=""):
|
def workout_wind_view(request,id=0,message="",successmessage=""):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
@@ -2420,7 +2428,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""):
|
|||||||
'gmapdiv':gmdiv})
|
'gmapdiv':gmdiv})
|
||||||
|
|
||||||
|
|
||||||
# Show form to update River stream data (for river dwellers)
|
# Show form to update River stream data (for river dwellers)
|
||||||
@user_passes_test(ispromember,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=""):
|
def workout_stream_view(request,id=0,message="",successmessage=""):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
@@ -2482,7 +2490,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""):
|
|||||||
'form':form,
|
'form':form,
|
||||||
'the_div':div})
|
'the_div':div})
|
||||||
|
|
||||||
# Form to set average crew weight and boat type, then run power calcs
|
# Form to set average crew weight and boat type, then run power calcs
|
||||||
@user_passes_test(ispromember, 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=""):
|
def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
@@ -2654,7 +2662,7 @@ def cumstats(request,theuser=0,
|
|||||||
theuser = request.user.id
|
theuser = request.user.id
|
||||||
|
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
result = request.user.is_authenticated() and ispromember(request.user)
|
result = request.user.is_authenticated() and ispromember(request.user)
|
||||||
if result:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
@@ -2738,97 +2746,17 @@ def cumstats(request,theuser=0,
|
|||||||
u = ''
|
u = ''
|
||||||
|
|
||||||
ids = [int(workout.id) for workout in allergworkouts]
|
ids = [int(workout.id) for workout in allergworkouts]
|
||||||
|
|
||||||
# Get field names and remove those that are not useful in stats
|
|
||||||
fields = StrokeData._meta.get_fields()
|
|
||||||
|
|
||||||
fielddict = {field.name:field.verbose_name for field in fields}
|
|
||||||
|
|
||||||
|
|
||||||
fielddict.pop('workoutid')
|
|
||||||
fielddict.pop('ergpace')
|
|
||||||
fielddict.pop('hr_an')
|
|
||||||
fielddict.pop('hr_tr')
|
|
||||||
fielddict.pop('hr_at')
|
|
||||||
fielddict.pop('hr_ut2')
|
|
||||||
fielddict.pop('hr_ut1')
|
|
||||||
fielddict.pop('time')
|
|
||||||
fielddict.pop('distance')
|
|
||||||
fielddict.pop('nowindpace')
|
|
||||||
fielddict.pop('fnowindpace')
|
|
||||||
fielddict.pop('fergpace')
|
|
||||||
fielddict.pop('equivergpower')
|
|
||||||
# fielddict.pop('workoutstate')
|
|
||||||
fielddict.pop('fpace')
|
|
||||||
fielddict.pop('pace')
|
|
||||||
fielddict.pop('id')
|
|
||||||
fielddict.pop('ftime')
|
|
||||||
fielddict.pop('x_right')
|
|
||||||
fielddict.pop('hr_max')
|
|
||||||
fielddict.pop('hr_bottom')
|
|
||||||
fielddict.pop('cumdist')
|
|
||||||
|
|
||||||
fieldlist,fielddict = dataprep.getstatsfields()
|
fieldlist,fielddict = dataprep.getstatsfields()
|
||||||
|
|
||||||
# prepare data frame
|
# prepare data frame
|
||||||
datadf = dataprep.read_cols_df_sql(ids,fieldlist)
|
datadf = dataprep.read_cols_df_sql(ids,fieldlist)
|
||||||
|
|
||||||
# clean data remove zeros and negative values
|
|
||||||
datadf=datadf.clip(lower=0)
|
|
||||||
datadf.replace(to_replace=0,value=np.nan,inplace=True)
|
|
||||||
|
|
||||||
# clean data for useful ranges per column
|
|
||||||
mask = datadf['hr'] < 30
|
|
||||||
datadf.loc[mask,'hr'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['rhythm'] < 5
|
|
||||||
datadf.loc[mask,'rhythm'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['rhythm'] > 70
|
|
||||||
datadf.loc[mask,'rhythm'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['power'] < 20
|
|
||||||
datadf.loc[mask,'power'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['drivelength'] < 0.5
|
|
||||||
datadf.loc[mask,'drivelength'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['forceratio'] < 0.2
|
|
||||||
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
|
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
|
||||||
|
|
||||||
mask = datadf['forceratio'] > 1.0
|
|
||||||
datadf.loc[mask,'forceratio'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['spm'] < 10
|
|
||||||
datadf.loc[mask,'spm'] = np.nan
|
|
||||||
|
|
||||||
|
|
||||||
mask = datadf['spm'] > 60
|
|
||||||
datadf.loc[mask,'spm'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['drivespeed'] < 0.5
|
|
||||||
datadf.loc[mask,'drivespeed'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['drivespeed'] > 4
|
|
||||||
datadf.loc[mask,'drivespeed'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['driveenergy'] > 2000
|
|
||||||
datadf.loc[mask,'driveenergy'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['driveenergy'] < 100
|
|
||||||
|
|
||||||
|
|
||||||
if datadf.empty:
|
if datadf.empty:
|
||||||
return HttpResponse("No data found")
|
return HttpResponse("No data found")
|
||||||
|
|
||||||
workoutstateswork = [1,4,5,8,9,6,7]
|
|
||||||
workoutstatesrest = [3]
|
|
||||||
workoutstatetransition = [0,2,10,11,12,13]
|
|
||||||
|
|
||||||
if workstrokesonly=='True' or workstrokesonly==True:
|
|
||||||
try:
|
|
||||||
datadf = datadf[~datadf['workoutstate'].isin(workoutstatesrest)]
|
|
||||||
except:
|
|
||||||
|
|
||||||
|
|
||||||
# Create stats
|
# Create stats
|
||||||
@@ -2908,51 +2836,8 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
|||||||
message = "You are not allowed to see the stats of this workout"
|
message = "You are not allowed to see the stats of this workout"
|
||||||
url = reverse(workouts_view,args=[str(message)])
|
url = reverse(workouts_view,args=[str(message)])
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
|
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
|
||||||
|
|
||||||
# clean data remove zeros and negative values
|
|
||||||
datadf=datadf.clip(lower=0)
|
|
||||||
datadf.replace(to_replace=0,value=np.nan,inplace=True)
|
|
||||||
|
|
||||||
# clean data for useful ranges per column
|
|
||||||
mask = datadf['hr'] < 30
|
|
||||||
datadf.loc[mask,'hr'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['rhythm'] < 5
|
|
||||||
datadf.loc[mask,'rhythm'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['rhythm'] > 70
|
|
||||||
datadf.loc[mask,'rhythm'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['power'] < 20
|
|
||||||
datadf.loc[mask,'power'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['drivelength'] < 0.5
|
|
||||||
datadf.loc[mask,'drivelength'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['forceratio'] < 0.2
|
|
||||||
datadf.loc[mask,'forceratio'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['forceratio'] > 1.0
|
|
||||||
datadf.loc[mask,'forceratio'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['spm'] < 10
|
|
||||||
datadf.loc[mask,'spm'] = np.nan
|
|
||||||
|
|
||||||
|
|
||||||
mask = datadf['spm'] > 60
|
|
||||||
datadf.loc[mask,'spm'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['drivespeed'] < 0.5
|
|
||||||
datadf.loc[mask,'drivespeed'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['drivespeed'] > 4
|
|
||||||
datadf.loc[mask,'drivespeed'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['driveenergy'] > 2000
|
|
||||||
datadf.loc[mask,'driveenergy'] = np.nan
|
|
||||||
|
|
||||||
mask = datadf['driveenergy'] < 100
|
|
||||||
|
|
||||||
|
|
||||||
if datadf.empty:
|
if datadf.empty:
|
||||||
@@ -2961,44 +2846,12 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
|||||||
workoutstateswork = [1,4,5,8,9,6,7]
|
workoutstateswork = [1,4,5,8,9,6,7]
|
||||||
workoutstatesrest = [3]
|
workoutstatesrest = [3]
|
||||||
workoutstatetransition = [0,2,10,11,12,13]
|
workoutstatetransition = [0,2,10,11,12,13]
|
||||||
|
|
||||||
if workstrokesonly=='True' or workstrokesonly==True:
|
|
||||||
try:
|
|
||||||
datadf = datadf[~datadf['workoutstate'].isin(workoutstatesrest)]
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# Create stats
|
# Create stats
|
||||||
stats = {}
|
stats = {}
|
||||||
|
|
||||||
# Get field names and remove those that are not useful in stats
|
fieldlist,fielddict = dataprep.getstatsfields()
|
||||||
fields = StrokeData._meta.get_fields()
|
|
||||||
|
|
||||||
fielddict = {field.name:field.verbose_name for field in fields}
|
|
||||||
|
|
||||||
|
|
||||||
fielddict.pop('workoutid')
|
|
||||||
fielddict.pop('ergpace')
|
|
||||||
fielddict.pop('hr_an')
|
|
||||||
fielddict.pop('hr_tr')
|
|
||||||
fielddict.pop('hr_at')
|
|
||||||
fielddict.pop('hr_ut2')
|
|
||||||
fielddict.pop('hr_ut1')
|
|
||||||
fielddict.pop('time')
|
|
||||||
fielddict.pop('distance')
|
|
||||||
fielddict.pop('nowindpace')
|
|
||||||
fielddict.pop('fnowindpace')
|
|
||||||
fielddict.pop('fergpace')
|
|
||||||
fielddict.pop('equivergpower')
|
|
||||||
fielddict.pop('workoutstate')
|
|
||||||
fielddict.pop('fpace')
|
|
||||||
fielddict.pop('pace')
|
|
||||||
fielddict.pop('id')
|
|
||||||
fielddict.pop('ftime')
|
|
||||||
fielddict.pop('x_right')
|
|
||||||
fielddict.pop('hr_max')
|
|
||||||
fielddict.pop('hr_bottom')
|
|
||||||
|
|
||||||
|
|
||||||
for field,verbosename in fielddict.iteritems():
|
for field,verbosename in fielddict.iteritems():
|
||||||
@@ -3086,7 +2939,7 @@ def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'):
|
|||||||
def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'):
|
def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'):
|
||||||
promember=0
|
promember=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
result = request.user.is_authenticated() and ispromember(request.user)
|
result = request.user.is_authenticated() and ispromember(request.user)
|
||||||
if result:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
@@ -3113,7 +2966,7 @@ def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
|
|||||||
yparam='spm',plottype='line'):
|
yparam='spm',plottype='line'):
|
||||||
promember=0
|
promember=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
result = request.user.is_authenticated() and ispromember(request.user)
|
result = request.user.is_authenticated() and ispromember(request.user)
|
||||||
if result:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
@@ -3161,7 +3014,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
|||||||
promember=0
|
promember=0
|
||||||
mayedit=0
|
mayedit=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
result = request.user.is_authenticated() and ispromember(request.user)
|
result = request.user.is_authenticated() and ispromember(request.user)
|
||||||
if result:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
@@ -3316,7 +3169,7 @@ def workout_biginteractive_view(request,id=0,message="",successmessage=""):
|
|||||||
promember=0
|
promember=0
|
||||||
mayedit=0
|
mayedit=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
result = request.user.is_authenticated() and ispromember(request.user)
|
result = request.user.is_authenticated() and ispromember(request.user)
|
||||||
if result:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
@@ -3353,7 +3206,7 @@ def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
|
|||||||
promember=0
|
promember=0
|
||||||
mayedit=0
|
mayedit=0
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
result = request.user.is_authenticated() and ispromember(request.user)
|
result = request.user.is_authenticated() and ispromember(request.user)
|
||||||
if result:
|
if result:
|
||||||
promember=1
|
promember=1
|
||||||
@@ -3555,7 +3408,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
|||||||
})
|
})
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
# Create the chart image with wind corrected pace (OTW)
|
# Create the chart image with wind corrected pace (OTW)
|
||||||
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
||||||
def workout_add_otw_powerplot_view(request,id):
|
def workout_add_otw_powerplot_view(request,id):
|
||||||
w = Workout.objects.get(id=id)
|
w = Workout.objects.get(id=id)
|
||||||
@@ -3818,7 +3671,7 @@ def workout_add_distanceplot_view(request,id):
|
|||||||
url = "/rowers/workout/"+str(w.id)+"/edit"
|
url = "/rowers/workout/"+str(w.id)+"/edit"
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
# Create the advanced parameters distance overview chart
|
# Create the advanced parameters distance overview chart
|
||||||
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
||||||
def workout_add_distanceplot2_view(request,id):
|
def workout_add_distanceplot2_view(request,id):
|
||||||
w = Workout.objects.get(id=id)
|
w = Workout.objects.get(id=id)
|
||||||
@@ -3871,7 +3724,7 @@ def workout_add_distanceplot2_view(request,id):
|
|||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
# Create the advanced parameters time based overview chart
|
# Create the advanced parameters time based overview chart
|
||||||
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
||||||
def workout_add_timeplot2_view(request,id):
|
def workout_add_timeplot2_view(request,id):
|
||||||
w = Workout.objects.get(id=id)
|
w = Workout.objects.get(id=id)
|
||||||
@@ -4934,7 +4787,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
|||||||
'savebutton':savebutton,
|
'savebutton':savebutton,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Page where user can manage his favorite charts
|
# Page where user can manage his favorite charts
|
||||||
@user_passes_test(ispromember,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):
|
def rower_favoritecharts_view(request):
|
||||||
message = ''
|
message = ''
|
||||||
@@ -5430,3 +5283,190 @@ def strokedatajson(request,id):
|
|||||||
return HttpResponse(row.id,status=201)
|
return HttpResponse(row.id,status=201)
|
||||||
|
|
||||||
#Method not supported
|
#Method not supported
|
||||||
|
return HttpResponseNotAllowed("Method not supported")
|
||||||
|
|
||||||
|
|
||||||
|
# Teams related views
|
||||||
|
import teams
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def team_view(request,id=0,message='',successmessage=''):
|
||||||
|
ismember = 0
|
||||||
|
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
t = Team.objects.get(id=id)
|
||||||
|
except Team.DoesNotExist:
|
||||||
|
return HttpResponse("Team doesn't exist")
|
||||||
|
|
||||||
|
|
||||||
|
if request.method == 'POST' and request.user == t.manager:
|
||||||
|
inviteform = TeamInviteForm(request.POST)
|
||||||
|
if inviteform.is_valid():
|
||||||
|
cd = inviteform.cleaned_data
|
||||||
|
newmember = cd['user']
|
||||||
|
email = cd['email']
|
||||||
|
inviteid,text = teams.create_invite(t,t.manager,
|
||||||
|
user=newmember,
|
||||||
|
email=email)
|
||||||
|
if inviteid:
|
||||||
|
teams.send_invite_email(inviteid)
|
||||||
|
successmessage = text
|
||||||
|
else:
|
||||||
|
message = text
|
||||||
|
|
||||||
|
elif request.user == t.manager:
|
||||||
|
inviteform = TeamInviteForm()
|
||||||
|
inviteform.fields['user'].queryset = User.objects.filter(rower__isnull=False)
|
||||||
|
else:
|
||||||
|
inviteform = ''
|
||||||
|
|
||||||
|
members = Rower.objects.filter(team=t).order_by('user__last_name','user__first_name')
|
||||||
|
|
||||||
|
if r in members:
|
||||||
|
ismember = 1
|
||||||
|
|
||||||
|
return render(request, 'team.html',
|
||||||
|
{
|
||||||
|
'team':t,
|
||||||
|
'members':members,
|
||||||
|
'inviteform':inviteform,
|
||||||
|
'message':message,
|
||||||
|
'successmessage':successmessage,
|
||||||
|
'ismember':ismember,
|
||||||
|
})
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def team_leaveconfirm_view(request,id=0):
|
||||||
|
try:
|
||||||
|
t = Team.objects.get(id=id)
|
||||||
|
except Team.DoesNotExist:
|
||||||
|
return HttpResponse("Team doesn't exist")
|
||||||
|
|
||||||
|
return render(request,'teamleaveconfirm.html',
|
||||||
|
{
|
||||||
|
'team':t
|
||||||
|
})
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def team_leave_view(request,id=0):
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
teams.remove_member(id,r)
|
||||||
|
|
||||||
|
url = reverse(rower_teams_view)
|
||||||
|
response = HttpResponseRedirect(url)
|
||||||
|
return response
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def rower_teams_view(request):
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
ts = Team.objects.filter(rower=r)
|
||||||
|
myteams = Team.objects.filter(manager=request.user)
|
||||||
|
otherteams = Team.objects.filter(private='open').exclude(rower=r).exclude(manager=request.user).order_by('name')
|
||||||
|
teams.remove_expired_invites()
|
||||||
|
|
||||||
|
invites = TeamInvite.objects.filter(user=request.user)
|
||||||
|
|
||||||
|
return render(request, 'teams.html',
|
||||||
|
{
|
||||||
|
'teams':ts,
|
||||||
|
'myteams':myteams,
|
||||||
|
'invites':invites,
|
||||||
|
'otherteams':otherteams,
|
||||||
|
})
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def rower_invitations_view(request,code=None,message='',successmessage=''):
|
||||||
|
|
||||||
|
if code:
|
||||||
|
teams.remove_expired_invites()
|
||||||
|
res,text = teams.process_invite_code(request.user,code)
|
||||||
|
if res:
|
||||||
|
successmessage = text
|
||||||
|
teamid=res
|
||||||
|
url = reverse(team_view,kwargs={
|
||||||
|
'id':teamid,
|
||||||
|
'successmessage': successmessage,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
message = text
|
||||||
|
url = reverse(rower_invitations_view,kwargs={
|
||||||
|
'message':message
|
||||||
|
})
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
ts = Team.objects.filter(rower=r)
|
||||||
|
myteams = Team.objects.filter(manager=request.user)
|
||||||
|
invites = TeamInvite.objects.filter(user=request.user)
|
||||||
|
otherteams = Team.objects.filter(private='open').drop(rower=r)
|
||||||
|
|
||||||
|
return render(request, 'teams.html',
|
||||||
|
{
|
||||||
|
'teams':ts,
|
||||||
|
'myteams':myteams,
|
||||||
|
'invites':invites,
|
||||||
|
'otherteams':otherteams,
|
||||||
|
})
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def team_requestmembership_view(request,teamid,userid):
|
||||||
|
return HttpResponse("Not yet implemented")
|
||||||
|
|
||||||
|
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
|
||||||
|
def team_create_view(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
teamcreateform = TeamForm(request.POST)
|
||||||
|
if teamcreateform.is_valid():
|
||||||
|
cd = teamcreateform.cleaned_data
|
||||||
|
name = cd['name']
|
||||||
|
notes = cd['notes']
|
||||||
|
manager = request.user
|
||||||
|
private = cd['private']
|
||||||
|
res,message=teams.create_team(name,manager,private,notes)
|
||||||
|
url = reverse(rower_teams_view)
|
||||||
|
response = HttpResponseRedirect(url)
|
||||||
|
return response
|
||||||
|
|
||||||
|
else:
|
||||||
|
teamcreateform = TeamForm()
|
||||||
|
|
||||||
|
return render(request,'teamcreate.html',
|
||||||
|
{
|
||||||
|
'form':teamcreateform,
|
||||||
|
})
|
||||||
|
|
||||||
|
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
|
||||||
|
def team_deleteconfirm_view(request,id):
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
try:
|
||||||
|
t = Team.objects.get(id=id)
|
||||||
|
except Team.DoesNotExist:
|
||||||
|
return HttpResponse("This team doesn't exist")
|
||||||
|
if t.manager != request.user:
|
||||||
|
return HttpResponse("You are not allowed to delete this team")
|
||||||
|
|
||||||
|
return render(request,'teamdeleteconfirm.html',
|
||||||
|
{
|
||||||
|
'team':t
|
||||||
|
})
|
||||||
|
|
||||||
|
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
|
||||||
|
def team_delete_view(request,id):
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
try:
|
||||||
|
t = Team.objects.get(id=id)
|
||||||
|
except Team.DoesNotExist:
|
||||||
|
return HttpResponse("This team doesn't exist")
|
||||||
|
if t.manager != request.user:
|
||||||
|
return HttpResponse("You are not allowed to delete this team")
|
||||||
|
|
||||||
|
teams.remove_team(t.id)
|
||||||
|
|
||||||
|
url = reverse(rower_teams_view)
|
||||||
|
response = HttpResponseRedirect(url)
|
||||||
|
|||||||
Reference in New Issue
Block a user