Private
Public Access
1
0

Merge branch 'release/v5.80'

This commit is contained in:
Sander Roosendaal
2018-02-09 16:52:49 +01:00
23 changed files with 772 additions and 85 deletions
+3 -3
View File
@@ -2226,11 +2226,11 @@ def workout_trimp(workout):
return trimp
def workout_rscore(w):
r = workout.user
df,row = getrowdata_db(id=workout.id)
r = w.user
df,row = getrowdata_db(id=w.id)
df = clean_df_stats(df)
if df.empty:
df,row = getrowdata_db(id=workout.id)
df,row = getrowdata_db(id=w.id)
df = clean_df_stats(df,workstrokesonly=False)
duration = df['time'].max()-df['time'].min()
+24 -1
View File
@@ -1,6 +1,6 @@
from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from rowers.models import Workout
from rowers.models import Workout,Rower,Team
from rowers.rows import validate_file_extension,must_be_csv,validate_image_extension
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
@@ -629,3 +629,26 @@ class WorkoutSessionSelectForm(forms.Form):
widget = forms.CheckboxSelectMultiple,
)
class PlannedSessionTeamForm(forms.Form):
team = forms.ModelMultipleChoiceField(
queryset=Team.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple())
def __init__(self, user, *args, **kwargs):
super(PlannedSessionTeamForm,self).__init__(*args, **kwargs)
self.fields['team'].queryset = Team.objects.filter(manager=user)
class PlannedSessionTeamMemberForm(forms.Form):
members = forms.ModelMultipleChoiceField(
queryset=Rower.objects.all(),
widget=forms.CheckboxSelectMultiple())
def __init__(self, thesession, *args, **kwargs):
super(PlannedSessionTeamMemberForm,self).__init__(*args,**kwargs)
self.fields['members'].queryset = thesession.rower.all()
+6 -1
View File
@@ -502,6 +502,8 @@ class Rower(models.Model):
planexpires = models.DateField(default=timezone.now)
teamplanexpires = models.DateField(default=timezone.now)
clubsize = models.IntegerField(default=0)
protrialexpires = models.DateField(blank=True,null=True)
plantrialexpires = models.DateField(blank=True,null=True)
# Friends/Team
@@ -521,7 +523,10 @@ class Rower(models.Model):
verbose_name='Show Notes for Favorite Charts')
def __str__(self):
return self.user.username
return self.user.firstname+' '+self.user.last_name
def __unicode__(self):
return self.user.first_name+' '+self.user.last_name
def clean_email(self):
return self.user.email.lower()
+11
View File
@@ -219,6 +219,17 @@ def get_sessions(r,startdate=date.today(),
return sps
def get_sessions_manager(manager,startdate=date.today(),
enddate=date.today()+timezone.timedelta(+1000)):
sps = PlannedSession.objects.filter(
manager=manager,
startdate__lte=enddate,
enddate__gte=startdate,
).order_by("startdate","enddate").exclude(team__isnull=True)
return sps
def get_workouts_session(r,ps):
ws = Workout.objects.filter(user=r,plannedsession=ps)
+8 -8
View File
@@ -60,7 +60,7 @@
<div class="grid_6 alpha">
<div class="grid_2 alpha">
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
{% else %}
<a class="button blue small" href="/rowers/promembership/">Compare Workouts</a>
@@ -80,7 +80,7 @@
<div class="grid_2 omega tooltip">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
@@ -97,7 +97,7 @@
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
@@ -109,7 +109,7 @@
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a>
@@ -121,7 +121,7 @@
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/histo">Power Histogram</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Power Histogram</a>
@@ -135,7 +135,7 @@
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workouts-join-select">Glue</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Glue</a>
@@ -148,7 +148,7 @@
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id }}/">Sensor Fusion</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Sensor Fusion</a>
@@ -160,7 +160,7 @@
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/split">Split Workout</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Split Workout</a>
+11 -11
View File
@@ -56,7 +56,7 @@
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Compare Workouts</a>
@@ -78,7 +78,7 @@
<div class="grid_2 omega tooltip">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
@@ -95,7 +95,7 @@
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/crewnerdsummary">CrewNerd Summary</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">CrewNerd Summary</a>
@@ -109,7 +109,7 @@
<div class="grid_2 tooltip">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/forcecurve">Stroke Profile (Empower)</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Stroke Profile (Empower)</a>
@@ -122,7 +122,7 @@
<div class="grid_2 omega tooltip">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addotwpowerplot">OTW Power Plot</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">OTW Power Plot</a>
@@ -142,7 +142,7 @@
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/geeky">Geeky Stuff</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Geeky Stuff</a>
@@ -157,7 +157,7 @@
<div class="grid_2 tooltip">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/smoothenpace">Smooth out Pace Data</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Smooth out Pace Data</a>
@@ -174,7 +174,7 @@
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/undosmoothenpace">Raw Data</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Reset Smoothing</a>
@@ -189,7 +189,7 @@
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workouts-join-select">Glue</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Glue</a>
@@ -201,7 +201,7 @@
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id }}/">Sensor Fusion</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Sensor Fusion</a>
@@ -213,7 +213,7 @@
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/split">Split Workout</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Split Workout</a>
+7 -7
View File
@@ -41,7 +41,7 @@
<h2>Pro</h2>
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/histo">Power Histogram</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Power Histogram</a>
@@ -53,7 +53,7 @@
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/cumstats">Statistics</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Statistics</a>
@@ -65,7 +65,7 @@
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/user-boxplot-select">Box Chart</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Box Chart</a>
@@ -90,7 +90,7 @@
<div class="grid_6 omega">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/otw-bests">OTW Critical Power</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">OTW Critical Power</a>
@@ -102,7 +102,7 @@
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/team-compare-select/team/0/">Multi Compare</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Multi Compare</a>
@@ -114,7 +114,7 @@
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/user-multiflex-select">Trend Flex</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Trend Flex</a>
@@ -128,7 +128,7 @@
<div class="grid_6 prefix_6 alpha">
<div class="grid_2 suffix_4 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/ote-ranking">OTE Critical Power</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">OTE Critical Power</a>
+3 -2
View File
@@ -1,3 +1,4 @@
{% load rowerfilters %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
@@ -19,7 +20,7 @@
<body>
<div class="container_12">
<div id="logo" class="grid_2">
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<p><a href="/"><img src="/static/img/logocroppedpro.gif"
alt="Rowsandall logo" width="110" heigt="110"></a></p>
{% else %}
@@ -44,7 +45,7 @@
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
</div>
<div class="grid_3">
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<h6>Pro Member</h6>
{% else %}
<p>&nbsp;</p>
+1 -1
View File
@@ -97,8 +97,8 @@
</div>
{% else %}
&nbsp;
{% endif %}
</div>
{% endif %}
</div>
<div class="grid_12 alpha">
+4 -4
View File
@@ -57,7 +57,7 @@
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/wind">Edit Wind Data</a>
{% else %}
<a class="button blue small" href="/rowers/about">Edit Wind Data</a>
@@ -70,7 +70,7 @@
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/stream">Edit Stream Data</a>
{% else %}
<a class="button blue small" href="/rowers/about">Edit Stream Data</a>
@@ -83,7 +83,7 @@
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a>
{% else %}
<a class="button blue small" href="/rowers/about">OTW Power</a>
@@ -100,7 +100,7 @@
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveotwplot">Corrected Pace Plot</a>
{% else %}
<a class="button blue small" href="/rowers/about">Corrected Pace Plot</a>
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}About us{% endblock title %}
{% block title %}Rowsandall Plan Membership{% endblock title %}
{% block content %}
<div class="grid_6 alpha">
+2 -2
View File
@@ -7,8 +7,8 @@
{% block content %}
<div class="grid_12 alpha">
{% include "planningbuttons.html" %}
</div>
<div class="grid_12 alpha">
<div id="left" class="grid_6 alpha">
<h1>Create Session for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1>
@@ -119,7 +119,7 @@
</table>
{% csrf_token %}
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input class="button green" type="submit" value="Submit">
<input class="button green" type="submit" value="Save">
</div>
</form>
</div>
+9 -1
View File
@@ -1,5 +1,6 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Update Planned Session{% endblock %}
@@ -13,7 +14,7 @@
<h1>Edit Session {{ thesession.name }}</h1>
</div>
<div id="timeperiod" class="grid_2 dropdown">
<button class="grid_2 alpha button gray small dropbtn">Time Period</button>
<button class="grid_2 alpha button gray small dropbtn">Select Time Period ({{ timeperiod|verbosetimeperiod }})</button>
<div class="dropdown-content">
<a class="button gray small alpha"
href="/rowers/sessions/create/today/rower/{{ rower.id }}">
@@ -37,6 +38,13 @@
</a>
</div>
</div>
{% if user.is_authenticated and user|is_manager %}
<div class="grid_2">
<a class="button green small alpha" href="/rowers/sessions/teamedit/{{ thesession.id }}/{{ timeperiod}}">
Assign to my Teams
</a>
</div>
{% endif %}
</div>
<div class="grid_12 alpha">
<div class="grid_6 alpha">
+51
View File
@@ -117,6 +117,57 @@
You have no planned workouts for this period. Planned workouts are created
by your coach if you are part of a team. You can create your own
planned workouts by purchasing the "Coach" or "Self-Coach" plans.
{% endif %}
{% if unmatchedworkouts %}
<h1>Workouts that are not linked to any session</h1>
<table width="90%" class="listtable shortpadded">
<thead>
<tr>
<th style="width:80"> Date</th>
<th> Time</th>
<th> Name</th>
<th> Type</th>
<th> Distance </th>
<th> Duration </th>
<th> Avg HR </th>
<th> Max HR </th>
</tr>
</thead>
<tbody>
{% for workout in unmatchedworkouts %}
<tr>
<td> {{ workout.date|date:"Y-m-d" }} </td>
<td> {{ workout.starttime|date:"H:i" }} </td>
{% if workout.user.user == user or user == team.manager %}
{% if workout.name != '' %}
<td>
<a href={% url rower.defaultlandingpage id=workout.id %}>
{{ workout.name }}
</a>
</td>
{% else %}
<td>
<a href={% url rower.defaultlandingpage id=workout.id %}>No Name
</a></td>
{% endif %}
{% else %}
{% if workout.name != '' %}
<td><a href="/rowers/workout/{{ workout.id }}/">{{ workout.name }}</a></td>
{% else %}
<td><a href="/rowers/workout/{{ workout.id }}/">No Name</a> </td>
{% endif %}
{% endif %}
<td> {{ workout.workouttype }} </td>
<td> {{ workout.distance }}m</td>
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
<td> {{ workout.averagehr }} </td>
<td> {{ workout.maxhr }} </td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
+1 -3
View File
@@ -60,8 +60,8 @@
<a class="button green small" href="/rowers/sessions/manage/{{ timeperiod }}/rower/{{ member.id }}">{{ member.user.first_name }} {{ member.user.last_name }}</a>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
</div>
<div class="grid_12 alpha">
<p>Select one session on the left, and one or more workouts on the right
@@ -92,8 +92,6 @@
{% csrf_token %}
<input class="button green" type="submit" value="Submit">
</div>
</form>
</form>
@@ -0,0 +1,121 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}New Planned Session{% endblock %}
{% block content %}
<div class="grid_12 alpha">
{% include "planningbuttons.html" %}
</div>
<div class="grid_12 alpha">
<div id="left" class="grid_6 alpha">
<h1>Create Team Session</h1>
</div>
<div id="timeperiod" class="grid_2 dropdown">
<button class="grid_2 alpha button gray small dropbtn">Select Time Period ({{ timeperiod|verbosetimeperiod }})</button>
<div class="dropdown-content">
<a class="button gray small alpha"
href="/rowers/sessions/create/today/rower/{{ rower.id }}">
Today
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/thisweek/rower/{{ rower.id }}">
This Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/thismonth/rower/{{ rower.id }}">
This Month
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/lastweek/rower/{{ rower.id }}">
Last Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/lastmonth/rower/{{ rower.id }}">
Last Month
</a>
</div>
</div>
</div>
<div class="grid_12 alpha">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
{% csrf_token %}
<div id="right" class="grid_6 alpha">
<h1>Select Team</h1>
<p>
<table>
{{ teamform.as_table }}
</table></p>
{% if plannedsessions %}
<h1>Team Plan Sessions</h1>
<p>
<table class="listtable shortpadded" width="80%">
<thead>
<tr>
<th>After</th>
<th>Before</th>
<th>Name</th>
<th>Value</th>
<th>&nbsp;</th>
<th>Edit</th>
<th>Clone</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for ps in plannedsessions %}
<tr>
<td> {{ ps.startdate|date:"Y-m-d" }} </td>
<td> {{ ps.enddate|date:"Y-m-d" }} </td>
<td>
{% if ps.name != '' %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}">{{ ps.name }}</a>
{% else %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}">Unnamed Session</a>
{% endif %}
</td>
<td> {{ ps.sessionvalue }} </td>
<td> {{ ps.sessionunit }} </td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/edit">Edit</a>
</td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/clone">Clone</a>
</td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/deleteconfirm">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</p>
{% endif %}
</div>
<div class="grid_6 omega">
<h1>New Session</h1>
<table>
{{ form.as_table }}
</table>
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input class="button green" type="submit" value="Save">
</div>
</form>
</div>
</div>
{% endblock %}
@@ -0,0 +1,137 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}New Planned Session{% endblock %}
{% block content %}
<div class="grid_12 alpha">
{% include "planningbuttons.html" %}
</div>
<div class="grid_12 alpha">
<div id="left" class="grid_6 alpha">
<h1>Edit Team Session</h1>
</div>
<div id="timeperiod" class="grid_2 dropdown">
<button class="grid_2 alpha button gray small dropbtn">Select Time Period ({{ timeperiod|verbosetimeperiod }})</button>
<div class="dropdown-content">
<a class="button gray small alpha"
href="/rowers/sessions/create/today/rower/{{ rower.id }}">
Today
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/thisweek/rower/{{ rower.id }}">
This Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/thismonth/rower/{{ rower.id }}">
This Month
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/lastweek/rower/{{ rower.id }}">
Last Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/create/lastmonth/rower/{{ rower.id }}">
Last Month
</a>
</div>
</div>
</div>
<div class="grid_12 alpha">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
{% csrf_token %}
<div id="right" class="grid_6 alpha">
<h1>Select Team</h1>
<p>
Selecting a team assigns this session to all members of the team.
Unselecting a team does not remove rowers
who are already assigned to this session. Use the Rowers selection for that.
</p><p>
<table>
{{ teamform.as_table }}
</table></p>
<h1>Select Rowers</h1>
<p>
<table>
{{ rowersform.as_table }}
</table>
</p>
{% if plannedsessions %}
<h1>Team Plan Sessions</h1>
<p>
<table class="listtable shortpadded" width="80%">
<thead>
<tr>
<th>After</th>
<th>Before</th>
<th>Name</th>
<th>Value</th>
<th>&nbsp;</th>
<th>Edit</th>
<th>Clone</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for ps in plannedsessions %}
<tr>
<td> {{ ps.startdate|date:"Y-m-d" }} </td>
<td> {{ ps.enddate|date:"Y-m-d" }} </td>
<td>
{% if ps.name != '' %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}">{{ ps.name }}</a>
{% else %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}">Unnamed Session</a>
{% endif %}
</td>
<td> {{ ps.sessionvalue }} </td>
<td> {{ ps.sessionunit }} </td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/edit">Edit</a>
</td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/clone">Clone</a>
</td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/deleteconfirm">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</p>
{% endif %}
</div>
<div class="grid_6 omega">
<h1>Session {{ plannedsession.name }}</h1>
<table>
{{ form.as_table }}
</table>
<div class="grid_1 prefix_2 alpha">
<a class="red button small" href="/rowers/sessions/{{ plannedsession.id }}/deleteconfirm">Delete</a>
</div>
<div class="grid_1">
<a class="gray button small" href="/rowers/sessions/{{ plannedsession.id }}/clone">Clone</a>
</div>
<div id="formbutton" class="grid_1 suffix_1 omega">
<input class="button green" type="submit" value="Save">
</div>
</form>
</div>
</div>
{% endblock %}
+13 -1
View File
@@ -21,7 +21,7 @@
{% endif %}
</p>
</div>
<div class="grid_2 suffix_6 omega">
<div class="grid_2">
<p>
{% if timeperiod and rower %}
<a class="button gray small" href="/rowers/sessions/create/{{ timeperiod }}/rower/{{ rower.id }}">Add Session</a>
@@ -32,3 +32,15 @@
{% endif %}
</p>
</div>
<div class="grid_2 omega">
{% if user.is_authenticated and user|is_manager %}
{% if timeperiod %}
<a class="button gray small" href="/rowers/sessions/teamcreate/{{ timeperiod }}">Add Team Session</a>
{% else %}
<a class="button gray small" href="/rowers/session/teamcreate">Add Team Session</a>
{% endif %}
{% else %}
&nbsp;
{% endif %}
</div>
+15 -5
View File
@@ -1,7 +1,8 @@
{% extends "base.html" %}
{% block title %}About us{% endblock title %}
{% block title %}Rowsandall Pro Membership{% endblock title %}
{% block content %}
{% load rowerfilters %}
<div class="grid_6 alpha">
<h2>Pro Membership</h2>
@@ -24,12 +25,21 @@ website. </p>
Your payment will be valid for one year with automatic renewal which you can stop at any time.
You will be taken to the secure PayPal payment site.
</p>
{% if user.rower.rowerplan == 'basic' and user.rower.protrialexpires|date_dif == 1 %}
<p>
You qualify for a 14 day free trial. No credit card needed.
Try out Pro membership for two weeks. Click the button below to
sign up for the trial. After your trial period expires, you will be
automatically reset to the Basic plan, unless you upgrade to Pro.
</p>
<div class="grid_6"><p><a class="button green small" href="/rowers/starttrial">Yes, I want to try Pro membership for 14 days for free. No strings attached.</a></p></div>
{% endif %}
</div>
<div class="grid_6 omega">
<h2>Recurring Payment</h2>
<p>You need a Paypal account for this</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<p><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
{% if user.is_authenticated %}
@@ -38,16 +48,16 @@ You will be taken to the secure PayPal payment site.
{% endif %}
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG_global.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
</form></p>
<h2>One Year Subscription</h2>
<p>Only a credit card needed. Will not automatically renew</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<p><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="2YB32HQTF96QW">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
</form></p>
<h2>Payment Processing</h2>
<p>After you do the payment, we will manually change your membership to
+32 -1
View File
@@ -3,7 +3,7 @@ from django.utils.safestring import mark_safe
from time import strftime
import dateutil.parser
import json
import datetime
register = template.Library()
def strfdelta(tdelta):
@@ -41,6 +41,10 @@ def secondstotimestring(tdelta):
return res
@register.filter
def ddays(ddelta):
return ddelta.days+1
@register.filter
def spacetohtml(t):
return t.replace(" ","%20")
@@ -107,6 +111,11 @@ def get_field_id(id,s,form):
from rowers.models import Rower,Team
from rowers.views import ispromember
@register.filter
def is_promember(user):
return ispromember(user)
@register.filter
def is_manager(user):
r = Rower.objects.get(user=user)
@@ -183,3 +192,25 @@ def verbosetimeperiod(timeperiod):
return verbose
from datetime import date
@ register.filter
def future_date_only(the_date):
if the_date > date.today():
return the_date
else:
return None
@register.filter
def is_future_date(the_date):
return the_date >= date.today()
@register.filter
def date_dif(the_date):
if the_date:
return the_date - date.today()
else:
return 1
+13
View File
@@ -382,6 +382,7 @@ urlpatterns = [
url(r'^videos', TemplateView.as_view(template_name='videos.html'),name='videos'),
url(r'^analysis', TemplateView.as_view(template_name='analysis.html'),name='analysis'),
url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'),
url(r'^starttrial$',views.start_trial_view),
url(r'^planmembership', TemplateView.as_view(template_name='planmembership.html'),name='planmembership'),
url(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'),
url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'),
@@ -397,6 +398,18 @@ urlpatterns = [
url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>[\w\ ]+.*)/$',views.workout_comparison_view2),
url(r'^test\_callback',views.rower_process_testcallback),
url(r'^workout/(?P<id>\d+)/test\_strokedata$',views.strokedataform),
url(r'^sessions/teamcreate$',views.plannedsession_teamcreate_view),
url(r'^sessions/teamcreate/(?P<timeperiod>[\w\ ]+.*)$',
views.plannedsession_teamcreate_view),
url(r'^sessions/teamcreate/(?P<timeperiod>[\w\ ]+.*)/team/(?P<teamid>\d+)$',
views.plannedsession_teamcreate_view),
url(r'^sessions/teamcreate/team/(?P<teamid>\d+)$',
views.plannedsession_teamcreate_view),
url(r'^sessions/teamedit/(?P<sessionid>\d+)$',views.plannedsession_teamedit_view),
url(r'^sessions/teamedit/(?P<sessionid>\d+)/(?P<timeperiod>[\w\ ]+.*)$',views.plannedsession_teamedit_view),
url(r'^sessions/create$',views.plannedsession_create_view),
url(r'^sessions/create/rower/(?P<rowerid>\d+)$',
views.plannedsession_create_view),
+261 -3
View File
@@ -30,7 +30,8 @@ from rowers.forms import (
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm
LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm,
PlannedSessionTeamForm,PlannedSessionTeamMemberForm,
)
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
@@ -800,6 +801,8 @@ def ispromember(user):
r.save()
result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach' or r.rowerplan=='plan')
if not result and r.protrialexpires:
result = user.is_authenticated() and r.rowerplan=='basic' and r.protrialexpires >= datetime.date.today()
else:
result = False
return result
@@ -930,6 +933,33 @@ def sendmail(request):
else:
return HttpResponseRedirect('/rowers/email/')
@login_required()
def start_trial_view(request):
r = getrower(request.user)
if r.protrialexpires is not None:
messages.error(request,'You do not qualify for a trial')
url = '/rowers/promembership'
return HttpResponseRedirect(url)
r.protrialexpires = datetime.date.today()+datetime.timedelta(13)
r.save()
url = reverse(workouts_view)
messages.info(request,'We have started your 14 day trial period')
subject2 = "User started Pro Trial"
message2 = "User Started Pro Trial.\n"
message2 += request.user.email + "\n"
message2 += "User name: "+request.user.username
send_mail(subject2, message2,
'Rowsandall Server <info@rowsandall.com>',
['roosendaalsander@gmail.com'])
return HttpResponseRedirect(url)
# Create workout data from Strava or Concept2
# data and create the associated Workout object and save it
def add_workout_from_strokedata(user,importid,data,strokedata,
@@ -5060,6 +5090,7 @@ def team_comparison_select(request,
theteam = 0
if r.rowerplan == 'basic' and theteam==0:
if r.protrialexpires is None or r.protrialexpires<datetime.date.today():
raise Http404("Not allowed")
if theteam and (theteam.viewing == 'allmembers' or theteam.manager == request.user):
@@ -11779,6 +11810,208 @@ def plannedsession_create_view(request,timeperiod='thisweek',rowerid=0):
'timeperiod':timeperiod,
})
# Manager creates sessions for entire team
@user_passes_test(iscoachmember,login_url="/rowers/planmembership/",
redirect_field_name=None)
def plannedsession_teamcreate_view(request,timeperiod='thisweek',
teamid=0):
teams = Team.objects.filter(manager=request.user)
teamchoices = [(team.id, team.name) for team in teams]
teaminitial = [str(teams[0].id)]
startdate,enddate = get_dates_timeperiod(timeperiod)
sps = []
for team in teams:
res = get_sessions_manager(request.user,startdate=startdate,enddate=enddate)
sps += res
sps = list(set(sps))
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST)
sessionteamselectform = PlannedSessionTeamForm(
request.user,request.POST
)
if sessioncreateform.is_valid():
cd = sessioncreateform.cleaned_data
startdate = cd['startdate']
enddate = cd['enddate']
sessiontype = cd['sessiontype']
sessionmode = cd['sessionmode']
criterium = cd['criterium']
sessionvalue = cd['sessionvalue']
sessionunit = cd['sessionunit']
comment = cd['comment']
name = cd['name']
if sessionunit == 'min':
sessionmode = 'time'
elif sessionunit in ['km','m']:
sessionmode = 'distance'
ps = PlannedSession(
name=name,
startdate=startdate,
enddate=enddate,
sessiontype=sessiontype,
sessionmode=sessionmode,
sessionvalue=sessionvalue,
sessionunit=sessionunit,
comment=comment,
criterium=criterium,
manager=request.user)
ps.save()
# some logic when to add all selected rowers
if sessionteamselectform.is_valid():
cd = sessionteamselectform.cleaned_data
teams = cd['team']
for team in teams:
add_team_session(team,ps)
rs = Rower.objects.filter(team__in=[team])
for r in rs:
add_rower_session(r,ps)
url = reverse(plannedsession_teamcreate_view,
kwargs = {
'timeperiod':timeperiod,
})
return HttpResponseRedirect(url)
else:
sessioncreateform = PlannedSessionForm()
sessionteamselectform = PlannedSessionTeamForm(
request.user
)
return render(request,'plannedsessionteamcreate.html',
{
'teams':get_my_teams(request.user),
'form':sessioncreateform,
'teamform':sessionteamselectform,
'timeperiod':timeperiod,
'plannedsessions':sps,
})
# Manager edits sessions for entire team
@user_passes_test(iscoachmember,login_url="/rowers/planmembership/",
redirect_field_name=None)
def plannedsession_teamedit_view(request,timeperiod='thisweek',
sessionid=0):
try:
ps = PlannedSession.objects.get(id=sessionid)
except PlannedSession.DoesNotExist:
raise Http404("This session doesn't exist")
if not ps.manager == request.user:
raise Http404("You are not the manager of this session")
teams = Team.objects.filter(manager=request.user)
teamchoices = [(team.id, team.name) for team in teams]
teaminitial = ps.team.all()
startdate,enddate = get_dates_timeperiod(timeperiod)
sps = []
rowers = []
for team in teams:
res = get_sessions_manager(request.user,startdate=startdate,enddate=enddate)
sps += res
rowers += Rower.objects.filter(team__in=[team])
rowers = list(set(rowers))
sps = list(set(sps))
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST,instance=ps)
sessionteamselectform = PlannedSessionTeamForm(
request.user,request.POST
)
sessionrowerform = PlannedSessionTeamMemberForm(ps,request.POST)
if sessioncreateform.is_valid():
cd = sessioncreateform.cleaned_data
if cd['sessionunit'] == 'min':
cd['sessionmode'] = 'time'
elif cd['sessionunit'] in ['km','m']:
cd['sessionmode'] = 'distance'
res,message = update_plannedsession(ps,cd)
if res:
messages.info(request,message)
else:
messages.error(request,message)
# some logic when to add all selected rowers
if sessionteamselectform.is_valid():
cd = sessionteamselectform.cleaned_data
selectedteams = cd['team']
for team in teams:
if team in selectedteams:
add_team_session(team,ps)
rs = Rower.objects.filter(team__in=[team])
for r in rs:
add_rower_session(r,ps)
else:
remove_team_session(team,ps)
else:
selectedteams = []
if sessionrowerform.is_valid():
cd = sessionrowerform.cleaned_data
selectedrowers = cd['members']
for r in rowers:
if r in selectedrowers:
add_rower_session(r,ps)
else:
remove_rower_session(r,ps)
for t in selectedteams:
if t in r.team.all():
add_rower_session(r,ps)
url = reverse(plannedsession_teamedit_view,
kwargs = {
'sessionid':sessionid,
'timeperiod':timeperiod,
})
return HttpResponseRedirect(url)
else:
sessioncreateform = PlannedSessionForm(instance=ps)
sessionteamselectform = PlannedSessionTeamForm(
request.user
)
sessionteamselectform.fields['team'].initial = teaminitial
sessionrowerform = PlannedSessionTeamMemberForm(
ps
)
sessionrowerform.fields['members'].initial = ps.rower.all()
return render(request,'plannedsessionteamedit.html',
{
'plannedsession':ps,
'teams':get_my_teams(request.user),
'form':sessioncreateform,
'teamform':sessionteamselectform,
'rowersform':sessionrowerform,
'timeperiod':timeperiod,
'plannedsessions':sps,
})
@login_required()
def plannedsessions_view(request,timeperiod='thisweek',rowerid=0):
@@ -11811,6 +12044,11 @@ def plannedsessions_view(request,timeperiod='thisweek',rowerid=0):
else:
completiondate[ps.id] = ''
unmatchedworkouts = Workout.objects.filter(
user=r,
plannedsession=None,
date__gte=startdate,date__lte=enddate)
return render(request,'plannedsessions.html',
{
'teams':get_my_teams(request.user),
@@ -11820,6 +12058,7 @@ def plannedsessions_view(request,timeperiod='thisweek',rowerid=0):
'completeness':completeness,
'actualvalue':actualvalue,
'completiondate':completiondate,
'unmatchedworkouts':unmatchedworkouts,
})
@login_required()
@@ -11896,6 +12135,9 @@ def plannedsessions_manage_view(request,timeperiod='thisweek',rowerid=0,
else:
selectedworkouts = []
if len(selectedworkouts)==0:
for w in ws:
remove_workout_plannedsession(w,ps)
if selectedworkouts:
workouts = Workout.objects.filter(user=r,id__in=selectedworkouts)
@@ -11967,15 +12209,23 @@ def plannedsession_clone_view(request,id=0,rowerid=0,
if ps.manager != request.user:
raise Http404("You are not allowed to clone this planned session")
rowers = ps.rower.all()
teams = ps.team.all()
ps.pk = None
deltadays = ps.enddate-ps.startdate
ps.startdate = timezone.now()
ps.enddate = timezone.now()
ps.enddate = timezone.now()+deltadays
ps.name += ' (copy)'
ps.save()
add_rower_session(r,ps)
for rower in rowers:
add_rower_session(rower,ps)
for team in teams:
add_team_session(team,ps)
url = reverse(plannedsession_edit_view,
kwargs = {
@@ -12014,6 +12264,14 @@ def plannedsession_edit_view(request,id=0,timeperiod='thisweek',rowerid=0):
if ps.manager != request.user:
raise Http404("You are not allowed to edit this planned session")
if ps.team.all() or len(ps.rower.all())>1:
url = reverse(plannedsession_teamedit_view,
kwargs={
'timeperiod':timeperiod,
'sessionid':id,
})
return HttpResponseRedirect(url)
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST,instance=ps)
if sessioncreateform.is_valid():
+11 -3
View File
@@ -1,6 +1,6 @@
{% load leaflet_tags %}
{% load cookielaw_tags %}
{% load rowerfilters %}
{% load tz_detect %}
{% tz_detect %}
{% load analytical %}
@@ -101,7 +101,7 @@
</div>
<div class="grid_12">
<div id="logo" class="grid_6 alpha">
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if user|is_promember %}
<p><a href="/"><img src="/static/img/logo7.png"
alt="Rowsandall logo" height="80"></a></p>
{% else %}
@@ -157,7 +157,10 @@
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
<h6 class="graytext">Pro Member</h6>
{% else %}
<div class="grid_1"><a class="button green small" href="/rowers/promembership">Upgrade to Pro</a></div>
<div class="grid_1"><p><a class="button green small" href="/rowers/promembership">Upgrade to Pro</a></p></div>
{% endif %}
{% if user.rower.rowerplan == 'basic' and user.rower.protrialexpires|date_dif == 1 %}
<div class="grid_1"><p><a class="button green small" href="/rowers/promembership">Start Free Pro trial</a></p></div>
{% endif %}
</div>
</div>
@@ -238,6 +241,11 @@
{{ WARNING_MESSAGE }}
</p>
{% endif %}
{% if user.rower.protrialexpires and user.rower.protrialexpires|is_future_date %}
<p class="successmessage">
{{ user.rower.protrialexpires|date_dif|ddays }} days left in Pro trial
</p>
{% endif %}
{% if messages %}
{% for message in messages %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}