Merge branch 'feature/teamcontinued' into develop
This commit is contained in:
@@ -228,7 +228,8 @@ def timedeltaconv(x):
|
||||
# Processes painsled CSV file to database
|
||||
def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
dosummary=True,title='Workout',
|
||||
notes='',totaldist=0,totaltime=0):
|
||||
notes='',totaldist=0,totaltime=0,
|
||||
makeprivate=False):
|
||||
message = None
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
@@ -313,12 +314,18 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutstartdatetime = thetimezone.localize(row.rowdatetime).astimezone(utc)
|
||||
|
||||
if makeprivate:
|
||||
privacy = 'private'
|
||||
else:
|
||||
privacy = 'visible'
|
||||
|
||||
# check for duplicate start times
|
||||
ws = Workout.objects.filter(starttime=workoutstarttime,
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
message = "Warning: This workout probably already exists in the database"
|
||||
|
||||
|
||||
w = Workout(user=r,name=title,date=workoutdate,
|
||||
workouttype=workouttype,
|
||||
duration=duration,distance=totaldist,
|
||||
@@ -326,15 +333,16 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=f2,notes=notes,summary=summary,
|
||||
maxhr=maxhr,averagehr=averagehr,
|
||||
startdatetime=workoutstartdatetime)
|
||||
startdatetime=workoutstartdatetime,
|
||||
privacy=privacy)
|
||||
|
||||
|
||||
w.save()
|
||||
|
||||
ts = Team.objects.filter(rower=r)
|
||||
|
||||
for t in ts:
|
||||
w.team.add(t)
|
||||
if privacy == 'visible':
|
||||
ts = Team.objects.filter(rower=r)
|
||||
for t in ts:
|
||||
w.team.add(t)
|
||||
|
||||
# put stroke data in database
|
||||
res = dataprep(row.df,id=w.id,bands=True,
|
||||
@@ -422,6 +430,7 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
def new_workout_from_file(r,f2,
|
||||
workouttype='rower',
|
||||
title='Workout',
|
||||
makeprivate=False,
|
||||
notes=''):
|
||||
message = None
|
||||
fileformat = get_file_type(f2)
|
||||
@@ -470,6 +479,7 @@ def new_workout_from_file(r,f2,
|
||||
dosummary = (fileformat != 'fit')
|
||||
id,message = save_workout_database(f2,r,
|
||||
workouttype=workouttype,
|
||||
makeprivate=makeprivate,
|
||||
dosummary=dosummary,
|
||||
title=title)
|
||||
|
||||
|
||||
@@ -76,14 +76,15 @@ class UploadOptionsForm(forms.Form):
|
||||
('distanceplot','Distance Plot'),
|
||||
('pieplot','Pie Chart'),
|
||||
)
|
||||
make_plot = forms.BooleanField(initial=False)
|
||||
make_plot = forms.BooleanField(initial=False,required=False)
|
||||
plottype = forms.ChoiceField(required=False,
|
||||
choices=plotchoices,
|
||||
initial='timeplot')
|
||||
upload_to_C2 = forms.BooleanField(initial=False)
|
||||
upload_to_C2 = forms.BooleanField(initial=False,required=False)
|
||||
makeprivate = forms.BooleanField(initial=False,required=False)
|
||||
|
||||
class Meta:
|
||||
fields = ['make_plot','plottype','upload_toc2']
|
||||
fields = ['make_plot','plottype','upload_toc2','makeprivate']
|
||||
|
||||
# This form is used on the Analysis page to add a custom distance/time
|
||||
# trial and predict the pace
|
||||
|
||||
@@ -104,19 +104,27 @@ class Team(models.Model):
|
||||
('private','private'),
|
||||
('open','open'),
|
||||
)
|
||||
|
||||
viewchoices = (
|
||||
('coachonly','Coach Only'),
|
||||
('allmembers','All Members')
|
||||
)
|
||||
|
||||
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)
|
||||
private = models.CharField(max_length=30,choices=choices,default='open',
|
||||
verbose_name='Team Type')
|
||||
|
||||
viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class TeamForm(ModelForm):
|
||||
class Meta:
|
||||
model = Team
|
||||
fields = ['name','notes','private']
|
||||
fields = ['name','notes','private','viewing']
|
||||
widgets = {
|
||||
'notes': forms.Textarea,
|
||||
}
|
||||
@@ -196,6 +204,11 @@ class Rower(models.Model):
|
||||
('coach','coach')
|
||||
)
|
||||
|
||||
privacychoices = (
|
||||
('visible','Visible'),
|
||||
('hidden','Hidden'),
|
||||
)
|
||||
|
||||
rowerplan = models.CharField(default='basic',max_length=30,
|
||||
choices=plans)
|
||||
|
||||
@@ -203,8 +216,11 @@ class Rower(models.Model):
|
||||
teamplanexpires = models.DateField(default=timezone.now)
|
||||
clubsize = models.IntegerField(default=0)
|
||||
|
||||
|
||||
# Friends/Team
|
||||
friends = models.ManyToManyField("self",blank=True)
|
||||
privacy = models.CharField(default='visible',max_length=30,
|
||||
choices=privacychoices)
|
||||
|
||||
team = models.ManyToManyField(Team,blank=True)
|
||||
|
||||
@@ -351,6 +367,11 @@ class Workout(models.Model):
|
||||
('4-', '4- (four)'),
|
||||
('8+', '8+ (eight)'),
|
||||
)
|
||||
|
||||
privacychoices = (
|
||||
('private','Private'),
|
||||
('visible','Visible'),
|
||||
)
|
||||
|
||||
user = models.ForeignKey(Rower)
|
||||
team = models.ManyToManyField(Team,blank=True)
|
||||
@@ -374,6 +395,8 @@ class Workout(models.Model):
|
||||
uploadedtosporttracks = models.IntegerField(default=0)
|
||||
notes = models.CharField(blank=True,null=True,max_length=200)
|
||||
summary = models.TextField(blank=True)
|
||||
privacy = models.CharField(default='visible',max_length=30,
|
||||
choices=privacychoices)
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -491,7 +514,7 @@ class WorkoutForm(ModelForm):
|
||||
duration = forms.TimeInput(format='%H:%M:%S.%f')
|
||||
class Meta:
|
||||
model = Workout
|
||||
fields = ['name','date','starttime','duration','distance','workouttype','boattype','notes']
|
||||
fields = ['name','date','starttime','duration','distance','workouttype','notes','privacy','boattype']
|
||||
widgets = {
|
||||
'date': DateInput(),
|
||||
'notes': forms.Textarea,
|
||||
@@ -500,9 +523,12 @@ class WorkoutForm(ModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(WorkoutForm, self).__init__(*args, **kwargs)
|
||||
# this line to be removed
|
||||
del self.fields['privacy']
|
||||
|
||||
if self.instance.workouttype != 'water':
|
||||
del self.fields['boattype']
|
||||
|
||||
|
||||
# Used for the rowing physics calculations
|
||||
class AdvancedWorkoutForm(ModelForm):
|
||||
class Meta:
|
||||
|
||||
@@ -43,7 +43,7 @@ def handle_add_workouts_team(ws,t):
|
||||
|
||||
return 1
|
||||
|
||||
def update_team(t,name,manager,private,notes):
|
||||
def update_team(t,name,manager,private,notes,viewing):
|
||||
if t.manager != manager:
|
||||
return (0,'You are not the manager of this team')
|
||||
try:
|
||||
@@ -51,16 +51,17 @@ def update_team(t,name,manager,private,notes):
|
||||
t.manager = manager
|
||||
t.private = private
|
||||
t.notes = notes
|
||||
t.viewing = viewing
|
||||
t.save()
|
||||
except IntegrityError:
|
||||
return (0,'Team name duplication')
|
||||
return (1,'Team Updated')
|
||||
|
||||
def create_team(name,manager,private='open',notes=''):
|
||||
def create_team(name,manager,private='open',notes='',viewing='allmembers'):
|
||||
# needs some error testing
|
||||
try:
|
||||
t = Team(name=name,manager=manager,notes=notes,
|
||||
private=private)
|
||||
private=private,viewing=viewing)
|
||||
t.save()
|
||||
r = Rower.objects.get(user=manager)
|
||||
res = add_member(t.id,r)
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<td> {{ workout.date |truncatechars:15}} </td>
|
||||
<td> {{ workout.starttime }} </td>
|
||||
<td>
|
||||
{% if workout.user.user == user %}
|
||||
{% if workout.user.user == user or user == team.manager %}
|
||||
{% if workout.name != '' %}
|
||||
<a href="/rowers/workout/{{ workout.id }}/edit">{{ workout.name }}</a> </td>
|
||||
{% else %}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
{% block title %}New Team{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
<div class="grid_12 alpha">
|
||||
<h1>Create a new Team</h1>
|
||||
</div>
|
||||
<div id="left" class="grid_6 alpha">
|
||||
<h1>Create a new Team</h1>
|
||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
{% if form.errors %}
|
||||
<p style="color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
@@ -21,7 +23,14 @@
|
||||
<input class="button green" type="submit" value="Submit">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="right" class="grid_6 omega">
|
||||
<ul>
|
||||
<li>Team Type: A private team is invisible on the Teams Management page, except for its members. The only way to add members is for the manager to send an invitation. An open team is visible for all rowsandall.com users. In addition to the invitation mechanism, any user can request to be added to this team. The team manager will always have to approve membership.</li>
|
||||
<li>Sharing Behavior: When set to "All Members", all members of a team will see each other's workouts. This is the recommended setting. If te sharing bhavior is set to "Coach Only", team members only see their own workouts. The coach sees all team members' workouts.</li>
|
||||
<li>These settings can be changed at any point in time through the Team Edit page</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
{% block title %}New Team{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
<div class="grid_12 alpha">
|
||||
<h1>Edit Team {{ team.name }}</h1>
|
||||
</div>
|
||||
<div id="left" class="grid_6 alpha">
|
||||
<h1>Edit Team {{ team.name }}</h1>
|
||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
{% if form.errors %}
|
||||
<p style="color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
@@ -21,6 +23,13 @@
|
||||
<input class="button green" type="submit" value="Submit">
|
||||
</div>
|
||||
</div>
|
||||
<div id="right" class="grid_6 omega">
|
||||
<ul>
|
||||
<li>Team Type: A private team is invisible on the Teams Management page, except for its members. The only way to add members is for the manager to send an invitation. An open team is visible for all rowsandall.com users. In addition to the invitation mechanism, any user can request to be added to this team. The team manager will always have to approve membership.</li>
|
||||
<li>Sharing Behavior: When set to "All Members", all members of a team will see each other's workouts. This is the recommended setting. If te sharing bhavior is set to "Coach Only", team members only see their own workouts. The coach sees all team members' workouts.</li>
|
||||
<li>These settings can be changed at any point in time through the Team Edit page</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +69,16 @@
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
|
||||
<div class="grid_2 prefix_2 alpha tooltip">
|
||||
{% if workout.privacy == 'visible' %}
|
||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/setprivate">Set Private</a>
|
||||
<span class="tooltiptext">Only you can see this workout</span>
|
||||
{% else %}
|
||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/makepublic">Make Public</a>
|
||||
<span class="tooltiptext">Make this workout visible to your teams and followers</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="formbutton" class="grid_1 suffix_1 omega">
|
||||
<input class="button green" type="submit" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -157,6 +157,8 @@ urlpatterns = [
|
||||
url(r'^workout/(?P<id>\d+)/edit/c/(?P<message>.+.*)$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/edit/s/(?P<successmessage>.+.*)$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/edit$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/setprivate$',views.workout_setprivate_view),
|
||||
url(r'^workout/(?P<id>\d+)/makepublic$',views.workout_makepublic_view),
|
||||
url(r'^workout/(?P<id>\d+)/advanced/c/(?P<message>.+.*)$',views.workout_advanced_view),
|
||||
url(r'^workout/(?P<id>\d+)/advanced/s/(?P<successmessage>.+.*)$',views.workout_advanced_view),
|
||||
url(r'^workout/(?P<id>\d+)/geeky$',views.workout_geeky_view),
|
||||
|
||||
132
rowers/views.py
132
rowers/views.py
@@ -302,7 +302,8 @@ def sendmail(request):
|
||||
def checkworkoutuser(user,workout):
|
||||
try:
|
||||
r = Rower.objects.get(user=user)
|
||||
return (workout.user == r)
|
||||
managers = [team.manager for team in workout.team.all()]
|
||||
return (workout.user == r or user in managers)
|
||||
except Rower.DoesNotExist:
|
||||
return(False)
|
||||
|
||||
@@ -1884,7 +1885,71 @@ def workout_recalcsummary_view(request,id=0):
|
||||
})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@login_required()
|
||||
def workout_makepublic_view(request,id,
|
||||
message='',
|
||||
successmessage=''):
|
||||
try:
|
||||
row = Workout.objects.get(id=id)
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
url = reverse(workouts_view,args=[str(message)])
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
row.privacy = 'visible'
|
||||
row.save()
|
||||
rr = Rower.objects.get(user=request.user)
|
||||
|
||||
teams = rr.team.all()
|
||||
for team in teams:
|
||||
row.team.add(team)
|
||||
|
||||
|
||||
message = "Workout set to public. Your followers and team members will see it"
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':str(id),
|
||||
'successmessage':str(message),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@login_required()
|
||||
def workout_setprivate_view(request,id,
|
||||
message='',
|
||||
successmessage=''):
|
||||
try:
|
||||
row = Workout.objects.get(id=id)
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
url = reverse(workouts_view,args=[str(message)])
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
row.privacy = 'private'
|
||||
row.save()
|
||||
|
||||
for team in row.team.all():
|
||||
row.team.remove(team)
|
||||
|
||||
message = "Workout set to private. Only you will see it"
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':str(id),
|
||||
'successmessage':str(message),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
# List Workouts
|
||||
@login_required()
|
||||
def workouts_view(request,message='',successmessage='',
|
||||
@@ -1928,9 +1993,14 @@ def workouts_view(request,message='',successmessage='',
|
||||
except Team.DoesNotExist:
|
||||
raise Http404("Team doesn't exist")
|
||||
|
||||
workouts = Workout.objects.filter(team=theteam,
|
||||
if theteam.viewing == 'allmembers' or theteam.manager == request.user:
|
||||
workouts = Workout.objects.filter(team=theteam,
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by("-date", "-starttime")
|
||||
elif theteam.viewing == 'coachonly':
|
||||
workouts = Workout.objects.filter(team=theteam,user=r,
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by("-date","-starttime")
|
||||
|
||||
|
||||
else:
|
||||
@@ -2063,6 +2133,9 @@ def workout_view(request,id=0):
|
||||
try:
|
||||
# check if valid ID exists (workout exists)
|
||||
row = Workout.objects.get(id=id)
|
||||
if row.privacy == 'private':
|
||||
raise Http404("Not allowed to view this workout")
|
||||
|
||||
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
|
||||
r = Rower.objects.get(id=row.user.id)
|
||||
u = User.objects.get(id=r.user.id)
|
||||
@@ -3259,6 +3332,10 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
try:
|
||||
boattype = request.POST['boattype']
|
||||
except KeyError:
|
||||
boattype = Workout.objects.get(id=id).boattype
|
||||
try:
|
||||
privacy = request.POST['privacy']
|
||||
except KeyError:
|
||||
privacy = Workout.objects.get(id=id).privacy
|
||||
startdatetime = (str(date) + ' ' + str(starttime))
|
||||
startdatetime = datetime.datetime.strptime(startdatetime,
|
||||
@@ -3277,6 +3354,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
row.notes = notes
|
||||
row.duration = duration
|
||||
row.distance = distance
|
||||
row.boattype = boattype
|
||||
row.privacy = privacy
|
||||
row.save()
|
||||
# change data in csv file
|
||||
@@ -4103,7 +4181,26 @@ def workout_getc2workout_view(request,c2id):
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# This is the main view for processing uploaded files
|
||||
@login_required()
|
||||
@login_required()
|
||||
def workout_upload_view(request,message="",
|
||||
uploadoptions={
|
||||
'makeprivate':False,
|
||||
'make_plot':False,
|
||||
'upload_to_C2':False,
|
||||
'plottype':'timeplot',
|
||||
}):
|
||||
|
||||
if 'uploadoptions' in request.session:
|
||||
uploadoptions = request.session['uploadoptions']
|
||||
else:
|
||||
request.session['uploadoptions'] = uploadoptions
|
||||
|
||||
|
||||
|
||||
makeprivate = uploadoptions['makeprivate']
|
||||
make_plot = uploadoptions['make_plot']
|
||||
plottype = uploadoptions['plottype']
|
||||
upload_toc2 = uploadoptions['upload_to_C2']
|
||||
|
||||
r = Rower.objects.get(user=request.user)
|
||||
if request.method == 'POST':
|
||||
@@ -4115,10 +4212,22 @@ def workout_upload_view(request,message=""):
|
||||
t = form.cleaned_data['title']
|
||||
workouttype = form.cleaned_data['workouttype']
|
||||
|
||||
notes = form.cleaned_data['notes']
|
||||
make_plot = request.POST.getlist('make_plot')
|
||||
plottype = request.POST['plottype']
|
||||
notes = form.cleaned_data['notes']
|
||||
|
||||
if optionsform.is_valid():
|
||||
make_plot = optionsform.cleaned_data['make_plot']
|
||||
plottype = optionsform.cleaned_data['plottype']
|
||||
upload_to_c2 = optionsform.cleaned_data['upload_to_C2']
|
||||
makeprivate = optionsform.cleaned_data['makeprivate']
|
||||
|
||||
uploadoptions = {
|
||||
'makeprivate':makeprivate,
|
||||
'make_plot':make_plot,
|
||||
'plottype':plottype,
|
||||
'upload_to_C2':upload_to_c2,
|
||||
}
|
||||
|
||||
|
||||
request.session['uploadoptions'] = uploadoptions
|
||||
|
||||
f1 = res[0] # file name
|
||||
@@ -4126,6 +4235,7 @@ def workout_upload_view(request,message=""):
|
||||
|
||||
|
||||
id,message = dataprep.new_workout_from_file(r,f2,
|
||||
workouttype=workouttype,
|
||||
makeprivate=makeprivate,
|
||||
title = t,
|
||||
notes='')
|
||||
@@ -4266,7 +4376,7 @@ def workout_upload_view(request,message=""):
|
||||
|
||||
return response
|
||||
else:
|
||||
form = DocumentsForm()
|
||||
form = DocumentsForm()
|
||||
optionsform = UploadOptionsForm(initial=uploadoptions)
|
||||
return render(request, 'document_form.html',
|
||||
{'form':form,
|
||||
@@ -5432,7 +5542,9 @@ def team_edit_view(request,id=0):
|
||||
name = cd['name']
|
||||
notes = cd['notes']
|
||||
manager = request.user
|
||||
private = cd['private']
|
||||
private = cd['private']
|
||||
viewing = cd['viewing']
|
||||
res,message=teams.update_team(t,name,manager,private,notes,
|
||||
viewing)
|
||||
if res:
|
||||
url = reverse(team_view,
|
||||
@@ -5470,7 +5582,9 @@ def team_create_view(request):
|
||||
name = cd['name']
|
||||
notes = cd['notes']
|
||||
manager = request.user
|
||||
private = cd['private']
|
||||
private = cd['private']
|
||||
viewing = cd['viewing']
|
||||
res,message=teams.create_team(name,manager,private,notes,
|
||||
viewing)
|
||||
url = reverse(rower_teams_view)
|
||||
response = HttpResponseRedirect(url)
|
||||
|
||||
Reference in New Issue
Block a user