Private
Public Access
1
0

team manager can upload on behalf of team member

This commit is contained in:
Sander Roosendaal
2017-04-13 11:39:51 +02:00
parent a03c25cc98
commit 35f1fb5b59
10 changed files with 328 additions and 12 deletions

View File

@@ -90,6 +90,24 @@ class UploadOptionsForm(forms.Form):
class Meta: class Meta:
fields = ['make_plot','plottype','upload_toc2','makeprivate'] fields = ['make_plot','plottype','upload_toc2','makeprivate']
# The form to indicate additional actions to be performed immediately
# after a successful upload. This version allows the Team manager to select
# a team member
class TeamUploadOptionsForm(forms.Form):
plotchoices = (
('timeplot','Time Plot'),
('distanceplot','Distance Plot'),
('pieplot','Pie Chart'),
)
make_plot = forms.BooleanField(initial=False,required=False)
plottype = forms.ChoiceField(required=False,
choices=plotchoices,
initial='timeplot',
label='Plot Type')
class Meta:
fields = ['make_plot','plottype']
# This form is used on the Analysis page to add a custom distance/time # This form is used on the Analysis page to add a custom distance/time
# trial and predict the pace # trial and predict the pace
class PredictedPieceForm(forms.Form): class PredictedPieceForm(forms.Form):

View File

@@ -1,5 +1,6 @@
{% load cookielaw_tags %} {% load cookielaw_tags %}
{% load analytical %} {% load analytical %}
{% load rowerfilters %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en"> <html lang="en">
<head> <head>
@@ -143,14 +144,17 @@
{% endif %} {% endif %}
</div> </div>
<div class="grid_1 tooltip"> <div class="grid_1 tooltip">
{% if user.is_authenticated and teams %} {% if user.is_authenticated and user|has_teams %}
<div class="grid_1 alpha dropdown"> <div class="grid_1 alpha dropdown">
<button class="grid_1 alpha button gray small dropbtn"> <button class="grid_1 alpha button gray small dropbtn">
Teams Teams
</button> </button>
<div class="dropdown-content"> <div class="dropdown-content">
<a class="button gray small" href="/rowers/me/teams/">Manage Teams</a> <a class="button gray small" href="/rowers/me/teams/">Manage Teams</a>
{% for t in teams %} {% if user|is_manager %}
<a class="button gray small" href="/rowers/workout/upload/team/">Upload Team Member Workout</a>
{% endif %}
{% for t in user|user_teams %}
<a class="button gray small" href="/rowers/list-workouts/team/{{ t.id }}/">{{ t.name }}</a> <a class="button gray small" href="/rowers/list-workouts/team/{{ t.id }}/">{{ t.name }}</a>
{% endfor %} {% endfor %}
</div> </div>

View File

@@ -1,5 +1,6 @@
{% load cookielaw_tags %} {% load cookielaw_tags %}
{% load analytical %} {% load analytical %}
{% load rowerfilters %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en"> <html lang="en">
<head> <head>
@@ -162,13 +163,17 @@
{% endif %} {% endif %}
</div> </div>
<div class="grid_1 tooltip"> <div class="grid_1 tooltip">
{% if user.is_authenticated and teams %} {% if user.is_authenticated and user|user_teams %}
<div class="grid_1 alpha dropdown"> <div class="grid_1 alpha dropdown">
<button class="grid_1 alpha button gray small dropbtn"> <button class="grid_1 alpha button gray small dropbtn">
Teams Teams
</button> </button>
<div class="dropdown-content"> <div class="dropdown-content">
{% for t in teams %} <a class="button gray small" href="/rowers/me/teams/">Manage Teams</a>
{% if user|is_manager %}
<a class="button gray small" href="/rowers/workout/upload/team/">Upload Team Member Workout</a>
{% endif %}
{% for t in user|user_teams %}
<a class="button gray small" href="/rowers/list-workouts/team/{{ t.id }}/">{{ t.name }}</a> <a class="button gray small" href="/rowers/list-workouts/team/{{ t.id }}/">{{ t.name }}</a>
{% endfor %} {% endfor %}
</div> </div>

View File

@@ -1,12 +1,17 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load staticfiles %} {% load staticfiles %}
{% load rowerfilters %}
{% block title %}File loading{% endblock %} {% block title %}File loading{% endblock %}
{% block content %} {% block content %}
<form enctype="multipart/form-data" action="{{ formloc }}" method="post"> <form enctype="multipart/form-data" action="{{ formloc }}" method="post">
<div id="left" class="grid_6 alpha"> <div id="left" class="grid_6 alpha">
<h1>Upload Workout File</h1> <h1>Upload Workout File</h1>
{% if user.is_authenticated and user|is_manager %}
<p>Looking for <a href="/rowers/workout/upload/team/">Team Manager
Upload?</a></p>
{% endif %}
{% if form.errors %} {% if form.errors %}
<p style="color: red;"> <p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below. Please correct the error{{ form.errors|pluralize }} below.

View File

@@ -35,7 +35,9 @@
<div id="workouts_table" class="grid_8 alpha"> <div id="workouts_table" class="grid_8 alpha">
{% if team %} {% if team %}
{% include "teambuttons.html" with teamid=team.id %} <div class="grid_8 alpha">
{% include "teambuttons.html" with teamid=team.id %}
</div>
<h3>{{ team.name }} Team Workouts</h3> <h3>{{ team.name }} Team Workouts</h3>
{% else %} {% else %}
<h3>My Workouts</h3> <h3>My Workouts</h3>

View File

@@ -0,0 +1,55 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}File loading{% endblock %}
{% block content %}
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
<div id="left" class="grid_6 alpha">
<h1>Upload Workout File</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<table>
{{ rowerform.as_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>
<div id="right" class="grid_6 omega">
<h1>Optional extra actions</h1>
<p>
<table>
{{ optionsform.as_table }}
</table>
</p>
<p>
You can select one static plot to be generated immediately for this workout. You can select to upload to Concept2 automatically. If you check "make private", this workout will not be visible to your followers and will not show up in your teams' workouts list.
</p>
<p>
Valid file types are:
<ul>
<li>Painsled iOS Stroke Export (CSV)</li>
<li>Painsled desktop version Stroke Export (CSV)</li>
<li>A TCX file with location data (lat,long) - with or without Heart Rate value, for example from RiM or CrewNerd</li>
<li>RowPro CSV export</li>
<li>SpeedCoach GPS and SpeedCoach GPS 2 CSV export</li>
<li>ErgData CSV export</li>
<li>ErgStick CSV export</li>
<li>BoatCoach CSV export</li>
<li>A FIT file with location data (experimental)</li>
</ul>
</p>
</div>
</form>
{% endblock %}

View File

@@ -1,3 +1,4 @@
{% load rowerfilters %}
<div class="grid_2 alpha"> <div class="grid_2 alpha">
<p> <p>
<a class="button gray small" href="/rowers/list-workouts/team/{{ teamid }}/">Team Workouts</a> <a class="button gray small" href="/rowers/list-workouts/team/{{ teamid }}/">Team Workouts</a>
@@ -8,8 +9,17 @@
<a class="button gray small" href="/rowers/team-compare-select/team/{{ teamid }}/">Multi Compare</a> <a class="button gray small" href="/rowers/team-compare-select/team/{{ teamid }}/">Multi Compare</a>
</p> </p>
</div> </div>
<div class="grid_2 suffix_2 omega"> <div class="grid_2">
<p> <p>
<a class="button gray small" href="/rowers/team/{{ teamid }}/">Team Page</a> <a class="button gray small" href="/rowers/team/{{ teamid }}/">Team Page</a>
</p> </p>
</div> </div>
<div class="grid_2 omega">
{% if user|is_manager and user|has_teams %}
<p>
<a class="button gray small" href="/rowers/workout/upload/team/">Upload Workout</a>
</p>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>

View File

@@ -65,3 +65,35 @@ def times(number):
def get_field_id(id,s,form): def get_field_id(id,s,form):
field_name = s+str(id) field_name = s+str(id)
return form.__getitem__(field_name) return form.__getitem__(field_name)
from rowers.models import Rower,Team
@register.filter
def is_manager(user):
r = Rower.objects.get(user=user)
return r.rowerplan == 'coach'
@register.filter
def user_teams(user):
try:
therower = Rower.objects.get(user=user)
teams1 = therower.team.all()
teams2 = Team.objects.filter(manager=user)
teams = list(set(teams1).union(set(teams2)))
except TypeError:
teams = []
return teams
@register.filter
def has_teams(user):
try:
therower = Rower.objects.get(user=user)
teams1 = therower.team.all()
teams2 = Team.objects.filter(manager=user)
teams = list(set(teams1).union(set(teams2)))
return True
except TypeError:
return False
return False

View File

@@ -157,8 +157,12 @@ urlpatterns = [
url(r'^graph/(\d+)/$',views.graph_show_view), url(r'^graph/(\d+)/$',views.graph_show_view),
url(r'^graph/(\d+)/deleteconfirm$',views.graph_delete_confirm_view), url(r'^graph/(\d+)/deleteconfirm$',views.graph_delete_confirm_view),
url(r'^graph/(\d+)/delete$',views.graph_delete_view), url(r'^graph/(\d+)/delete$',views.graph_delete_view),
url(r'^workout/upload/team/s/(?P<successmessage>\w+.*)/c/(?P<message>\w+.*)/$',views.team_workout_upload_view),
url(r'^workout/upload/team/c/(?P<message>\w+.*)/$',views.team_workout_upload_view),
url(r'^workout/upload/team/s/(?P<successmessage>\w+.*)/$',views.team_workout_upload_view),
url(r'^workout/upload/team/$',views.team_workout_upload_view),
url(r'^workout/upload/$',views.workout_upload_view), url(r'^workout/upload/$',views.workout_upload_view),
url(r'^workout/upload/(.+.*)$',views.workout_upload_view), url(r'^workout/upload/c/(?P<message>\w+.*)$',views.workout_upload_view),
url(r'^workout/(?P<id>\d+)/histo$',views.workout_histo_view), url(r'^workout/(?P<id>\d+)/histo$',views.workout_histo_view),
url(r'^workout/(?P<id>\d+)/forcecurve$',views.workout_forcecurve_view), url(r'^workout/(?P<id>\d+)/forcecurve$',views.workout_forcecurve_view),
url(r'^workout/(?P<id>\d+)/unsubscribe$',views.workout_unsubscribe_view), url(r'^workout/(?P<id>\d+)/unsubscribe$',views.workout_unsubscribe_view),

View File

@@ -14,7 +14,10 @@ from django.http import (
HttpResponseNotFound,Http404 HttpResponseNotFound,Http404
) )
from django.contrib.auth import authenticate, login, logout from django.contrib.auth import authenticate, login, logout
from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm from rowers.forms import (
LoginForm,DocumentsForm,UploadOptionsForm,
TeamUploadOptionsForm,
)
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.template import RequestContext from django.template import RequestContext
@@ -5350,6 +5353,183 @@ def workout_upload_view(request,message="",
'optionsform': optionsform, 'optionsform': optionsform,
'message':message}) 'message':message})
# This is the main view for processing uploaded files
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def team_workout_upload_view(request,message="",
successmessage="",
uploadoptions={
'make_plot':False,
'plottype':'timeplot',
}):
if 'uploadoptions' in request.session:
uploadoptions = request.session['uploadoptions']
else:
request.session['uploadoptions'] = uploadoptions
myteams = Team.objects.filter(manager=request.user)
make_plot = uploadoptions['make_plot']
plottype = uploadoptions['plottype']
r = Rower.objects.get(user=request.user)
if request.method == 'POST':
form = DocumentsForm(request.POST,request.FILES)
optionsform = TeamUploadOptionsForm(request.POST)
rowerform = TeamInviteForm(request.POST)
rowerform.fields.pop('email')
rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
if form.is_valid():
f = request.FILES['file']
res = handle_uploaded_file(f)
t = form.cleaned_data['title']
if rowerform.is_valid():
u = rowerform.cleaned_data['user']
if u:
r = Rower.objects.get(user=u)
else:
message = 'Please select a rower'
response = render(request,
'team_document_form.html',
{'form':form,
'teams':get_my_teams(request.user),
'optionsform': optionsform,
'rowerform': rowerform,
'message':message,
'successmessage':successmessage,
})
return response
workouttype = form.cleaned_data['workouttype']
notes = form.cleaned_data['notes']
if optionsform.is_valid():
make_plot = optionsform.cleaned_data['make_plot']
plottype = optionsform.cleaned_data['plottype']
uploadoptions = {
'makeprivate':False,
'make_plot':make_plot,
'plottype':plottype,
'upload_to_C2':False,
}
request.session['uploadoptions'] = uploadoptions
f1 = res[0] # file name
f2 = res[1] # file name incl media directory
id,message,f2 = dataprep.new_workout_from_file(r,f2,
workouttype=workouttype,
makeprivate=False,
title = t,
notes='')
if not id:
url = reverse(team_workout_upload_view,
args=[str(message)])
response = HttpResponseRedirect(url)
return response
else:
if message:
successmessage = "The workout was added to the user's account"
url = reverse(team_workout_upload_view,
kwargs = {
'message':message,
'successmessage':successmessage,
})
else:
successmessage = "The workout was added to the user's account"
url = reverse(team_workout_upload_view,
kwargs = {
'successmessage':successmessage,
})
response = HttpResponseRedirect(url)
w = Workout.objects.get(id=id)
if (make_plot):
imagename = f1[:-4]+'.png'
fullpathimagename = 'static/plots/'+imagename
powerperc = 100*np.array([r.pw_ut2,
r.pw_ut1,
r.pw_at,
r.pw_tr,r.pw_an])/r.ftp
hrpwrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
'ftp':r.ftp,
'powerperc':serialize_list(powerperc),
'powerzones':serialize_list(r.powerzones),
}
# make plot - asynchronous task
plotnrs = {
'timeplot':1,
'distanceplot':2,
'pieplot':3,
}
plotnr = plotnrs[plottype]
if (workouttype=='water'):
plotnr = plotnr+3
if settings.DEBUG:
res = handle_makeplot.delay(f1,f2,t,
hrpwrdata,plotnr,
imagename)
else:
res = queue.enqueue(handle_makeplot,f1,f2,
t,hrpwrdata,
plotnr,imagename)
i = GraphImage(workout=w,
creationdatetime=timezone.now(),
filename=fullpathimagename)
i.save()
else:
response = render(request,
'team_document_form.html',
{'form':form,
'teams':get_my_teams(request.user),
'optionsform': optionsform,
'rowerform': rowerform,
'message':message,
'successmessage':successmessage,
})
return response
else:
form = DocumentsForm()
optionsform = TeamUploadOptionsForm(initial=uploadoptions)
rowerform = TeamInviteForm()
rowerform.fields.pop('email')
rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
return render(request, 'team_document_form.html',
{'form':form,
'teams':get_my_teams(request.user),
'optionsform': optionsform,
'rowerform':rowerform,
'message':message,
'successmessage':successmessage,
})
# Ask the user if he really wants to delete the workout # Ask the user if he really wants to delete the workout
@@ -6434,6 +6614,7 @@ def rower_teams_view(request,message='',successmessage=''):
'successmessage':successmessage, 'successmessage':successmessage,
'myinvites':myinvites, 'myinvites':myinvites,
}) })
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None) @user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def invitation_revoke_view(request,id): def invitation_revoke_view(request,id):
res,text = teams.revoke_invite(request.user,id) res,text = teams.revoke_invite(request.user,id)