Private
Public Access
1
0

Merge branch 'release/v8.46'

This commit is contained in:
Sander Roosendaal
2018-11-12 20:04:30 +01:00
10 changed files with 239 additions and 67 deletions
-1
View File
@@ -963,7 +963,6 @@ class PlannedSessionTeamForm(forms.Form):
return
cd = self.cleaned_data
print cd['team'],'aap'
if not cd['team']:
raise forms.ValidationError(
'You must select at least one team'
+15 -5
View File
@@ -973,18 +973,24 @@ class TrainingTargetForm(ModelForm):
}
def __init__(self,*args, **kwargs):
user = kwargs.pop('user',None)
super(TrainingTargetForm, self).__init__(*args, **kwargs)
try:
teams = Team.objects.filter(manager=self.instance.manager.user)
except AttributeError:
if user:
teams = Team.objects.filter(manager=user)
else:
teams = []
if not teams:
self.fields.pop('rowers')
else:
self.fields['rowers'].queryset = Rower.objects.filter(
team__in=teams
).distinct().order_by("user__last_name","user__first_name")
except AttributeError:
self.fields.pop('rowers')
# SportTracks has a TrainingGoal like this
@@ -1095,6 +1101,7 @@ class TrainingPlanForm(ModelForm):
def __init__(self,*args, **kwargs):
targets = kwargs.pop('targets',None)
user = kwargs.pop('user',None)
super(TrainingPlanForm, self).__init__(*args, **kwargs)
if targets:
@@ -1110,6 +1117,11 @@ class TrainingPlanForm(ModelForm):
try:
teams = Team.objects.filter(manager=self.instance.manager.user)
except AttributeError:
if user:
teams = Team.objects.filter(manager=user)
else:
teams = []
if not teams:
self.fields.pop('rowers')
@@ -1117,8 +1129,6 @@ class TrainingPlanForm(ModelForm):
self.fields['rowers'].queryset = Rower.objects.filter(
team__in=teams
).distinct().order_by("user__last_name","user__first_name")
except AttributeError:
self.fields.pop('rowers')
cycletypechoices = (
('filler','System Defined'),
@@ -1628,7 +1638,7 @@ class PlannedSession(models.Model):
('session','Training Session'),
('challenge','Challenge'),
('test','Mandatory Test'),
('cycletarget','Cycle Target'),
('cycletarget','Total for a time period'),
('coursetest','OTW test over a course'),
('race','Virtual Race'),
)
+22
View File
@@ -873,6 +873,28 @@ def handle_sendemail_unrecognizedowner(useremail, userfirstname,
return 1
@app.task
def handle_sendemailics(first_name, last_name, email, icsfile, **kwargs):
# send email with attachment
fullemail = first_name + " " + last_name + " " + "<" + email + ">"
subject = "Calendar File from Rowsandall.com"
d = {'first_name':first_name,
'siteurl':siteurl,
}
from_email = 'Rowsandall <info@rowsandall.com>'
res = send_template_email(from_email,[fullemail],
subject,'icsemail.html',d,
attach_file=icsfile,**kwargs)
os.remove(icsfile)
return 1
@app.task
def handle_sendemailkml(first_name, last_name, email, kmlfile,**kwargs):
+14
View File
@@ -0,0 +1,14 @@
{% extends "emailbase.html" %}
{% block body %}
<p>Dear <strong>{{ first_name }}</strong>,</p>
<p>
Please find attached the requested ICS Calendar file. You can import
this file to your calendar app.
</p>
<p>
Best Regards, the Rowsandall Team
</p>
{% endblock %}
+5
View File
@@ -129,7 +129,12 @@
<a
href="/rowers/sessions/print/user/{{ rower.user.id }}/?when={{ timeperiod }}">
Print View</a>
&nbsp;
<a
href="/rowers/sessions/sendcalendar/user/{{ rower.user.id }}/?when={{ timeperiod }}">
Get Calendar File</a>
</p>
</li>
<li class="grid_4">
{% if unmatchedworkouts %}
+36 -12
View File
@@ -6,6 +6,17 @@
{% block main %}
<script>
function toggle(source) {
checkboxes = document.querySelectorAll("input[type='checkbox']");
for (var i=0, n=checkboxes.length;i<n;i++) {
if (checkboxes[i].name.includes('selector')) {
checkboxes[i].checked = source.checked
}
}
}
</script>
<h1>Training Plan - {{ plan.name }}</h1>
<p>This plan starts on {{ plan.startdate }} and ends on {{ plan.enddate }}.
{% if plan.target %}
@@ -18,6 +29,7 @@
<h2>Plan Macro, Meso and Micro Cycles</h2>
<p><input type="checkbox" href="" onClick="toggle(this)" />Unfold/Fold all</p>
<ul class="cd-accordion-menu animated">
<!-- Start Macrocycle For Loop -->
{% for key, macrocycle in cycles.items %}
@@ -46,8 +58,10 @@
/
<a href="/rowers/deletemacrocycle/{{ macrocycle.0.id }}/">delete</a>
/
<a href='/rowers/sessions/create/user/{{ rower.user.id }}?when={{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}'>add sessions</a>
/
{% endif %}
<a href='/rowers/sessions/{{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% else %}
@@ -55,7 +69,7 @@
&nbsp;
</tr>
<tr>
<a href='/rowers/sessions/{{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</tr>
{% endif %}
</table>
@@ -115,8 +129,10 @@
Replan by Months
</a>
/
<a href='/rowers/sessions/create/user/{{ rower.user.id }}?when={{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}'>add sessions</a>
/
{% endif %}
<a href='/rowers/sessions/{{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% else %}
@@ -125,7 +141,7 @@
</tr>
<tr>
<td colspan="4">
<a href='/rowers/sessions/{{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% endif %}
@@ -162,8 +178,10 @@
/
<a href="/rowers/deletemesocycle/{{ mesocycle.0.id }}/">delete</a>
/
<a href='/rowers/sessions/create/user/{{ rower.user.id }}?when={{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}'>add sessions</a>
/
{% endif %}
<a href='/rowers/sessions/{{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% endif %}
@@ -172,7 +190,7 @@
&nbsp;
</tr>
<tr>
<a href='/rowers/sessions/{{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</tr>
{% endif %}
</table>
@@ -232,8 +250,10 @@
Replan by Weeks
</a>
/
<a href='/rowers/sessions/create/user/{{ rower.user.id }}?when={{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}'>add sessions</a>
/
{% endif %}
<a href='/rowers/sessions/{{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% else %}
@@ -242,7 +262,7 @@
</tr>
<tr>
<td colspan="4">
<a href='/rowers/sessions/{{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% endif %}
@@ -283,9 +303,11 @@
<a href="/rowers/microcycle/{{ microcycle.id }}/">edit</a>
/
<a href="/rowers/deletemicrocycle/{{ microcycle.id }}/">delete</a>
/
<a href='/rowers/sessions/create/user/{{ rower.user.id }}?when={{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}'>add sessions</a>
/
{% endif %}
<a href='/rowers/sessions/{{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% endif %}
@@ -296,7 +318,7 @@
</tr>
<tr>
<td colspan="4">
<a href='/rowers/sessions/{{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% endif %}
@@ -354,8 +376,10 @@
/
<a href="/rowers/deletemicrocycle/{{ microcycle.id }}">delete</a>
/
<a href='/rowers/sessions/create/user/{{ rower.user.id }}?when={{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}'>add sessions</a>
/
{% endif %}
<a href='/rowers/sessions/{{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% else %}
@@ -364,7 +388,7 @@
</tr>
<tr>
<td colspan="4">
<a href='/rowers/sessions/{{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
<a href='/rowers/sessions/user/{{ rower.user.id }}?when={{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}'>view sessions</a>
</td>
</tr>
{% endif %}
+4 -2
View File
@@ -358,8 +358,8 @@ urlpatterns = [
url(r'^me/exportsettings/$',views.rower_exportsettings_view),
url(r'^me/exportsettings/user/(?P<userid>\d+)$',views.rower_exportsettings_view),
url(r'^team/(?P<id>\d+)/$',views.team_view),
url(r'^team/(?P<id>\d+)/memberstats$',views.team_members_stats_view),
url(r'^team/(?P<id>\d+)/edit$',views.team_edit_view),
url(r'^team/(?P<id>\d+)/memberstats/$',views.team_members_stats_view),
url(r'^team/(?P<id>\d+)/edit/$',views.team_edit_view),
url(r'^team/(?P<id>\d+)/leaveconfirm/$',views.team_leaveconfirm_view),
url(r'^team/(?P<id>\d+)/leave/$',views.team_leave_view),
url(r'^team/(?P<id>\d+)/deleteconfirm/$',views.team_deleteconfirm_view),
@@ -507,6 +507,8 @@ urlpatterns = [
url(r'^sessions/coach/user/\d+/$',views.plannedsessions_coach_view),
url(r'^sessions/print/?$',views.plannedsessions_print_view),
url(r'^sessions/print/user/(?P<userid>\d+)/$',views.plannedsessions_print_view),
url(r'^sessions/sendcalendar/$',views.plannedsessions_icsemail_view),
url(r'^sessions/sendcalendar/user/(?P<userid>\d+)/$',views.plannedsessions_icsemail_view),
url(r'^sessions/$',views.plannedsessions_view),
url(r'^sessions/user/(?P<userid>\d+)$',views.plannedsessions_view),
url(r'^sessions/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',
+84 -29
View File
@@ -27,7 +27,7 @@ import codecs
import isodate
import re
import cgi
from icalendar import Calendar, Event
from django.shortcuts import render
from django.template.loader import render_to_string
@@ -103,6 +103,7 @@ import rowers.uploads as uploads
from django.forms.formsets import formset_factory
from django.forms import modelformset_factory
import StringIO
import cStringIO
from django.contrib.auth.decorators import login_required #,user_passes_test
from rowers.decorators import user_passes_test
from time import strftime,strptime,mktime,time,daylight
@@ -160,6 +161,7 @@ from rowers.tasks import (
handle_zip_file,handle_getagegrouprecords,
handle_updatefitnessmetric,
handle_update_empower,
handle_sendemailics,
handle_sendemail_userdeleted,
)
@@ -1431,6 +1433,38 @@ def workout_tcxemail_view(request,id=0):
return response
@login_required()
def plannedsessions_icsemail_view(request,userid=0):
r = getrequestrower(request,userid=userid)
startdate,enddate = get_dates_timeperiod(request)
sps = get_sessions(r,startdate=startdate,enddate=enddate)
cal = Calendar()
cal.add('prodid','rowsandall')
cal.add('version','1.0')
for ps in sps:
event = Event()
comment = '{d} {u} {c}'.format(
d=ps.sessionvalue,
u = ps.sessionunit,
c = ps.criterium)
event.add('summary',ps.name)
event.add('dtstart',ps.preferreddate)
event.add('dtend',ps.preferreddate)
event['uid'] = 'plannedsession_'+str(ps.id)
event.add('description',ps.comment)
event.add('comment',comment)
cal.add_component(event)
response = HttpResponse(cal.to_ical(),content_type = 'text/plain')
response['Content-Disposition'] = 'attachment; filename="training_plan_%s.ics"' % request.user.id
return response
@login_required()
def course_kmlemail_view(request,id=0):
r = getrower(request.user)
@@ -14326,8 +14360,9 @@ def plannedsession_multicreate_view(request,
)
if when:
url += '?when='+when
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
return HttpResponseRedirect(url)
@@ -14394,6 +14429,9 @@ def plannedsession_teamcreate_view(request,
sps += res
sps = list(set(sps))
ids = [ps.id for ps in sps]
sps = PlannedSession.objects.filter(id__in=ids).order_by(
"preferreddate","startdate","enddate")
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST)
@@ -14437,6 +14475,7 @@ def plannedsession_teamcreate_view(request,
cd = sessionteamselectform.cleaned_data
teams = cd['team']
request.session['teams'] = [team.id for team in teams]
for team in teams:
add_team_session(team,ps)
rs = Rower.objects.filter(team__in=[team])
@@ -14445,8 +14484,9 @@ def plannedsession_teamcreate_view(request,
url = reverse(plannedsession_teamcreate_view)
if when:
url += '?when='+when
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
return HttpResponseRedirect(url)
else:
@@ -14482,9 +14522,18 @@ def plannedsession_teamcreate_view(request,
'preferreddate':startdate,
}
if 'teams' in request.session:
teams = request.session['teams']
theteams = Team.objects.filter(id__in=teams)
initialteam = {
'team':theteams
}
else:
initialteam = {}
sessioncreateform = PlannedSessionForm(initial=initial)
sessionteamselectform = PlannedSessionTeamForm(
request.user
request.user,initial=initialteam
)
timeperiod = startdate.strftime('%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
@@ -14527,7 +14576,6 @@ def plannedsession_teamedit_view(request,
r = getrequestrower(request,userid=userid)
try:
ps = PlannedSession.objects.get(id=sessionid)
except PlannedSession.DoesNotExist:
@@ -14561,6 +14609,9 @@ def plannedsession_teamedit_view(request,
sps = list(set(sps))
ids = [pps.id for pps in sps]
sps = PlannedSession.objects.filter(id__in=ids).order_by(
"preferreddate","startdate","enddate")
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST,instance=ps)
@@ -14621,8 +14672,10 @@ def plannedsession_teamedit_view(request,
'sessionid':sessionid,
})
if when:
url += '?when='+when
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
return HttpResponseRedirect(url)
else:
@@ -15060,11 +15113,6 @@ def plannedsession_clone_view(request,id=0,userid=0):
r = getrequestrower(request,userid=userid)
if when:
timeperiod = when
else:
timeperiod = 'thisweek'
startdate,enddate = get_dates_timeperiod(request)
try:
@@ -15109,8 +15157,10 @@ def plannedsession_clone_view(request,id=0,userid=0):
}
)
if when:
url += '?when='+when
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
return HttpResponseRedirect(url)
@@ -15175,8 +15225,9 @@ def plannedsession_edit_view(request,id=0,userid=0):
'userid':r.user.id,
})
if when:
url += '?when='+when
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
return HttpResponseRedirect(url)
else:
@@ -16263,7 +16314,7 @@ def rower_create_trainingplan(request,userid=0):
themanager = getrower(request.user)
if request.method == 'POST' and 'date' in request.POST:
targetform = TrainingTargetForm(request.POST)
targetform = TrainingTargetForm(request.POST,user=request.user)
if targetform.is_valid():
name = targetform.cleaned_data['name']
date = targetform.cleaned_data['date']
@@ -16281,23 +16332,27 @@ def rower_create_trainingplan(request,userid=0):
t.save()
elif request.method == 'POST' and 'startdate' in request.POST:
form = TrainingPlanForm(request.POST)
form = TrainingPlanForm(request.POST,user=request.user)
if form.is_valid():
name = form.cleaned_data['name']
try:
target = form.cleaned_data['target']
except KeyError:
try:
targetid = request.POST['target']
target = TrainingTarget.objects.get(id=targetid)
if targetid != '':
target = TrainingTarget.objects.get(id=int(targetid))
else:
target = None
except KeyError:
target = None
startdate = form.cleaned_data['startdate']
enddate = form.cleaned_data['enddate']
athletes = form.cleaned_data['rowers']
p = TrainingPlan(
name=name,
target=target,
@@ -16308,19 +16363,22 @@ def rower_create_trainingplan(request,userid=0):
p.save()
p.rowers.add(therower)
for athlete in athletes:
p.rowers.add(athlete)
targets = TrainingTarget.objects.filter(
rowers=therower,
date__gte=datetime.date.today(),
).order_by("date")
targetform = TrainingTargetForm()
targetform = TrainingTargetForm(user=request.user)
plans = TrainingPlan.objects.filter(rowers=therower).order_by("-startdate")
form = TrainingPlanForm(targets=targets,initial={'status':False})
form = TrainingPlanForm(targets=targets,
initial={'status':False,'rowers':[therower]},
user=request.user)
breadcrumbs = [
{
@@ -16688,11 +16746,8 @@ def rower_trainingplan_view(request,
thismesoid=0):
when = request.GET.get('when')
if when:
startdate,enddate = get_dates_timeperiod(request)
else:
startdate = datetime.date.today()
try:
plan = TrainingPlan.objects.get(id=id)
+42 -1
View File
@@ -660,10 +660,51 @@
}
@media print {
header, user, nav, aside, footer {
.wrapper {
display: grid;
grid-template-columns: repeat(4,1fr);
grid-template-areas:
"content content content content"
}
header, ad, user, nav, aside, footer {
display: none;
}
* {
-webkit-transition: none !important;
transition: none !important;
}
body {
color:#000;
background: #fff;
}
body, content {
width: 100%;
display: block;
min-height: 100%;
}
@page {
margin: 2cm;
}
h1, h2, h3 {
page-break-after: avoid;
}
ul, img {
page-break-inside: avoid;
}
table tr td {
vertical-align: middle;
}
}
aside .cd-accordion-menu.animated label::before {
/* this class is used if you're using jquery to animate the accordion */
-webkit-transition: -webkit-transform 0.3s;
+2 -2
View File
@@ -289,14 +289,14 @@
{% endblock %}
</aside>
<div class="ad">
<ad class="ad">
{% block ad %}
<a href="https://pryglrowing.com">
<img src="/static/img/prygl.jpg">
<p style="text-align: center">Prygl Rowing Camps</p>
</a>
{% endblock %}
</div>
</ad>
<footer class="main-footer">
<p>Follow us on