not sure if this works
This commit is contained in:
@@ -386,7 +386,6 @@ class TeamInviteForm(ModelForm):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TeamRequest(models.Model):
|
||||
team = models.ForeignKey(Team)
|
||||
@@ -633,6 +632,8 @@ class PaidPlan(models.Model):
|
||||
paymentprocessor = self.paymentprocessor,
|
||||
)
|
||||
|
||||
class CoachingGroup(models.Model):
|
||||
pass
|
||||
|
||||
# Extension of User with rowing specific data
|
||||
class Rower(models.Model):
|
||||
@@ -832,7 +833,8 @@ class Rower(models.Model):
|
||||
|
||||
# Friends/Team
|
||||
friends = models.ManyToManyField("self",blank=True)
|
||||
coaches = models.ManyToManyField("self",blank=True)
|
||||
mycoachgroup = models.ForeignKey(CoachingGroup,related_name='coachingrole',null=True)
|
||||
coachinggroups = models.ManyToManyField(CoachingGroup,related_name='coaches')
|
||||
privacy = models.CharField(default='visible',max_length=30,
|
||||
choices=privacychoices)
|
||||
|
||||
@@ -870,6 +872,19 @@ class DeleteUserForm(forms.ModelForm):
|
||||
model = User
|
||||
fields = []
|
||||
|
||||
# requestor is user
|
||||
class CoachRequest(models.Model):
|
||||
coach = models.ForeignKey(Rower)
|
||||
user = models.ForeignKey(User,null=True)
|
||||
issuedate = models.DateField(default=current_day)
|
||||
code = models.CharField(max_length=150,unique=True)
|
||||
|
||||
# requestor is coach
|
||||
class CoachOffer(models.Model):
|
||||
coach = models.ForeignKey(Rower)
|
||||
user = models.ForeignKey(User,null=True)
|
||||
issuedate = models.DateField(default=current_day)
|
||||
code = models.CharField(max_length=150,unique=True)
|
||||
|
||||
from django.db.models.signals import m2m_changed
|
||||
|
||||
@@ -988,7 +1003,7 @@ def checkworkoutuser(user,workout):
|
||||
return False
|
||||
try:
|
||||
r = Rower.objects.get(user=user)
|
||||
coaches = user.rower.coaches.filter(rowerplan='coach')
|
||||
coaches = rower_get_coaches(user.rower)
|
||||
if workout.user == r:
|
||||
return True
|
||||
elif coaches:
|
||||
@@ -1007,7 +1022,7 @@ def checkaccessuser(user,rower):
|
||||
r = Rower.objects.get(user=user)
|
||||
if rower == r:
|
||||
return True
|
||||
coaches = rower.coaches.filter(rowerplan='coach')
|
||||
coaches = rower_get_coaches(rower)
|
||||
if coaches:
|
||||
for coach in coaches:
|
||||
if user.rower == coach:
|
||||
@@ -3434,3 +3449,4 @@ class PlannedSessionCommentForm(ModelForm):
|
||||
'comment': forms.Textarea,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1699,6 +1699,57 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
|
||||
|
||||
# Team related remote tasks
|
||||
|
||||
@app.task
|
||||
def handle_sendemail_coachrequest(email,name,code,coachname,
|
||||
debug=False,**kwargs):
|
||||
|
||||
fullemail = email
|
||||
subject = 'Invitation to add {n} to your athletes'.format(n=name)
|
||||
|
||||
siteurl = SITE_URL
|
||||
if debug:
|
||||
siteurl = SITE_URL_DEV
|
||||
|
||||
d = {
|
||||
'name':name,
|
||||
'coach':coachname,
|
||||
'code':code,
|
||||
'siteurl':siteurl
|
||||
}
|
||||
|
||||
form_email = 'Rowsandall <info@rowsandall.com>'
|
||||
|
||||
res = send_template_email(from_email,[fullemail],
|
||||
subject,'coachrequestemail.html',d,
|
||||
**kwargs)
|
||||
|
||||
return 1
|
||||
|
||||
@app.task
|
||||
def handle_sendemail_coacheerequest(email,name,code,coachname,
|
||||
debug=False,**kwargs):
|
||||
|
||||
fullemail = email
|
||||
subject = '{n} asks coach access to your data on rowsandall.com'.format(n=coachname)
|
||||
|
||||
siteurl = SITE_URL
|
||||
if debug:
|
||||
siteurl = SITE_URL_DEV
|
||||
|
||||
d = {
|
||||
'name':name,
|
||||
'coach':coachname,
|
||||
'code':code,
|
||||
'siteurl':siteurl
|
||||
}
|
||||
|
||||
form_email = 'Rowsandall <info@rowsandall.com>'
|
||||
|
||||
res = send_template_email(from_email,[fullemail],
|
||||
subject,'coacheerequestemail.html',d,
|
||||
**kwargs)
|
||||
|
||||
return 1
|
||||
|
||||
@app.task
|
||||
def handle_sendemail_invite(email, name, code, teamname, manager,
|
||||
|
||||
195
rowers/teams.py
195
rowers/teams.py
@@ -17,7 +17,7 @@ queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('low')
|
||||
|
||||
from rowers.models import (
|
||||
Rower, Workout, Team, TeamInvite,User,TeamRequest
|
||||
Rower, Workout, Team, TeamInvite,User,TeamRequest, CoachRequest, CoachOffer
|
||||
)
|
||||
|
||||
from rowers.tasks import (
|
||||
@@ -26,6 +26,7 @@ from rowers.tasks import (
|
||||
handle_sendemail_member_dropped,handle_sendemail_request_accept,
|
||||
handle_sendemail_request_reject,handle_sendemail_invite_reject,
|
||||
handle_sendemail_invite_accept,handle_sendemail_team_removed,
|
||||
handle_sendemail_coachrequest,handle_sendemail_coacheerequest,
|
||||
)
|
||||
|
||||
from rowers.models import ValidationError
|
||||
@@ -102,8 +103,17 @@ def remove_team(id):
|
||||
|
||||
return (1,'Updated rower team expiry')
|
||||
|
||||
def add_coach(manager,rower):
|
||||
rower.coaches.add(m)
|
||||
def add_coach(coach,rower):
|
||||
# get coaching group
|
||||
try:
|
||||
coachgroup = coach.mycoachgroup
|
||||
except CoachingGroup.DoesNotExist:
|
||||
coachgroup = CoachingGroup()
|
||||
coachgroup.save()
|
||||
coach.mycoachgroup = coachgroup
|
||||
coach.save()
|
||||
|
||||
rower.coachinggroups.add(coach)
|
||||
|
||||
return (1,"Added Coach")
|
||||
|
||||
@@ -134,6 +144,44 @@ def remove_member(id,rower):
|
||||
# set_teamplanexpires(rower)
|
||||
return (id,'Member removed')
|
||||
|
||||
def remove_coach(coach,rower):
|
||||
try:
|
||||
coachgroup = coach.mycoachgroup
|
||||
except CoachingGroup.DoesNotExist:
|
||||
coachgroup = CoachingGroup()
|
||||
coachgroup.save()
|
||||
coach.mycoachgroup = coachgroup
|
||||
coach.save()
|
||||
|
||||
rower.coachinggroups.remove(coachgroup)
|
||||
|
||||
return (1,'Coach removed')
|
||||
|
||||
def rower_get_coaches(rower):
|
||||
coaches = []
|
||||
for group in rower.coachinggroups:
|
||||
coach = Rower.objects.get(mycoachgroup=group)
|
||||
coaches.append(coach)
|
||||
|
||||
return coaches
|
||||
|
||||
|
||||
def coach_getcoachees(coach):
|
||||
return Rower.objects.filter(coachinggroups__in=[coach.mycoachgroup])
|
||||
|
||||
def coach_remove_athlete(coach,rower):
|
||||
try:
|
||||
coachgroup = coach.mycoachgroup
|
||||
except CoachingGroup.DoesNotExist:
|
||||
coachgroup = CoachingGroup()
|
||||
coachgroup.save()
|
||||
coach.mycoachgroup = coachgroup
|
||||
coach.save()
|
||||
|
||||
rower.coachingrgroups.remove(coachgroup)
|
||||
|
||||
return (1,'Coach removed')
|
||||
|
||||
def mgr_remove_member(id,manager,rower):
|
||||
t = Team.objects.get(id=id)
|
||||
if t.manager == manager:
|
||||
@@ -161,6 +209,51 @@ def count_club_members(manager):
|
||||
|
||||
# Medium level functionality
|
||||
|
||||
# request by user to be coached by coach
|
||||
def create_coaching_request(coach,user):
|
||||
if coach in rower_get_coaches(user.rower):
|
||||
return (0,'Already coached by that coach')
|
||||
|
||||
codes = [i.code for i in CoachRequest.objects.all()]
|
||||
code = uuid.uuid4().hex[:10].upper()
|
||||
while code in codes:
|
||||
code = uuid.uuid4().hex[:10].upper()
|
||||
|
||||
if coach.rowerplan == 'coach':
|
||||
rekwest = CoachRequest(coach=coach,user=user,code=code)
|
||||
rekwest.save()
|
||||
|
||||
send_coachrequest_email(rekwest)
|
||||
|
||||
return (rekwest.id,'The request was created')
|
||||
|
||||
else:
|
||||
return (0,'That person is not a coach')
|
||||
|
||||
def send_coachrequest_email(rekwest):
|
||||
name = rekwest.user.first_name + " " + rekwest.user.last_name
|
||||
email = rekwest.user.email
|
||||
|
||||
code = rekwest.code
|
||||
|
||||
coachname = rekwest.coach.user.first_name + " " + rekwest.coach.user.last_name
|
||||
|
||||
res = myqueue(queuehigh,
|
||||
handle_sendemail_coachrequest,
|
||||
email,name,code,coachname)
|
||||
|
||||
def send_coacheerequest_email(rekwest):
|
||||
name = rekwest.user.first_name + " " + rekwest.user.last_name
|
||||
email = rekwest.user.email
|
||||
|
||||
code = rekwest.code
|
||||
|
||||
coachname = rekwest.coach.user.first_name + " " + rekwest.coach.user.last_name
|
||||
|
||||
res = myqueue(queuehigh,
|
||||
handle_sendemail_coacheerequest,
|
||||
email,name,code,coachname)
|
||||
|
||||
def create_request(team,user):
|
||||
r2 = Rower.objects.get(user=user)
|
||||
r = Rower.objects.get(user=team.manager)
|
||||
@@ -183,7 +276,33 @@ def create_request(team,user):
|
||||
return (rekwest.id,'The request was created')
|
||||
|
||||
return (0,'Something went wrong in create_request')
|
||||
|
||||
# request by coach to coach user
|
||||
def create_coaching_offer(coach,user):
|
||||
r = user.rower
|
||||
|
||||
if coach in rower_get_coaches(user.rower):
|
||||
return (0,'You are already coaching this person.')
|
||||
|
||||
codes = [i.code for i in CoachOffer.objects.all()]
|
||||
code = uuid.uuid4().hex[:10].upper()
|
||||
while code in codes:
|
||||
code = uuid.uuid4().hex[:10].upper()
|
||||
|
||||
if coach.rowerplan == 'coach':
|
||||
rekwest = CoachOffer(coach=coach,user=user,code=code)
|
||||
rekwest.save()
|
||||
|
||||
send_coacheerequest_email(rekwest)
|
||||
|
||||
return (rekwest.id,'The request was created')
|
||||
|
||||
else:
|
||||
return (0,'You are not a coach')
|
||||
|
||||
|
||||
|
||||
|
||||
def create_invite(team,manager,user=None,email=''):
|
||||
r = Rower.objects.get(user=manager)
|
||||
if team.manager != manager:
|
||||
@@ -235,6 +354,36 @@ def revoke_request(user,id):
|
||||
else:
|
||||
return (0,'You are not the requestor')
|
||||
|
||||
def reject_revoke_coach_offer(user,id):
|
||||
try:
|
||||
rekwest = CoachOffer.objects.get(id=id)
|
||||
except CoachOffer.DoesNotExist:
|
||||
return (0,'The request is invalid')
|
||||
|
||||
if rekwest.coach.user == user:
|
||||
rekwest.delete()
|
||||
return (1,'Request removed')
|
||||
elif rekwest.user == user:
|
||||
rekwest.delete()
|
||||
return (1,'Request removed')
|
||||
else:
|
||||
return (0,'Not permitted')
|
||||
|
||||
def reject_revoke_coach_request(user,id):
|
||||
try:
|
||||
rekwest = CoachRequest.objects.get(id=id)
|
||||
except CoachRequest.DoesNotExist:
|
||||
return (0,'The request is invalid')
|
||||
|
||||
if rekwest.coach.user == user:
|
||||
rekwest.delete()
|
||||
return (1,'Request rejected')
|
||||
elif rekwest.user == user:
|
||||
rekwest.delete()
|
||||
return (1,'Request rejected')
|
||||
else:
|
||||
return (0,'Not permitted')
|
||||
|
||||
def revoke_invite(manager,id):
|
||||
try:
|
||||
invite = TeamInvite.objects.get(id=id)
|
||||
@@ -458,3 +607,43 @@ def remove_expired_invites():
|
||||
revoke_invite(i.team.manager,i.id)
|
||||
|
||||
return (1,'Expired invitations deleted')
|
||||
|
||||
def process_coachrequest_code(coach,code):
|
||||
code = code.upper()
|
||||
|
||||
try:
|
||||
rekwest = CoachRequest.objects.get(code=code)
|
||||
except CoachRequest.DoesNotExist:
|
||||
return (0,'The request has been revoked or is invalid')
|
||||
|
||||
if rekwest.coach != coach:
|
||||
return (0,'The request is invalid')
|
||||
|
||||
result = add_coach(coach,rekwest.user.rower)
|
||||
if not result:
|
||||
return (result,"Something went wrong")
|
||||
|
||||
rekwest.delete()
|
||||
|
||||
return result
|
||||
|
||||
def process_coachoffer_code(user,code):
|
||||
code = code.upper()
|
||||
|
||||
try:
|
||||
rekwest = CoachOffer.objects.get(code=code)
|
||||
except CoachOffer.DoesNotExist:
|
||||
return (0,'The request has been revoked or is invalid')
|
||||
|
||||
if rekwest.user != user:
|
||||
return (0,'The request is invalid')
|
||||
|
||||
result = add_coach(rekwest.coach,rekwest.user.rower)
|
||||
if not result:
|
||||
return (result,"Something went wrong")
|
||||
|
||||
rekwest.delete()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
32
rowers/templates/coacheerequestemail.html
Normal file
32
rowers/templates/coacheerequestemail.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends "emailbase.html" %}
|
||||
|
||||
{% block body %}
|
||||
<p>Dear <strong>{{ name }}</strong>,</p>
|
||||
|
||||
<p>
|
||||
{{ coachname }} is inviting you to become your coach on rowsandall.com.
|
||||
</p>
|
||||
<p>
|
||||
By accepting the invite, {{ coachname }} will have access to your
|
||||
data and will be able to upload workouts and run analysis on rowsandall.com
|
||||
on behalf of you.
|
||||
</p>
|
||||
<p>
|
||||
By accepting the invite, you are agreeing with the sharing
|
||||
of personal data according to our privacy policy.
|
||||
</p>
|
||||
<p>
|
||||
To accept, login to the
|
||||
site and you will find the invitation here on the Teams page:
|
||||
<a href="{{ siteurl }}/rowers/me/teams">{{ siteurl }}/rowers/me/teams</a>
|
||||
</p>
|
||||
<p>
|
||||
You can also click the direct link:
|
||||
<a href="{{ siteurl }}/rowers/me/coacheeinvitation/{{ code }}">
|
||||
{{ siteurl }}/rowers/me/coacheeinvitation/{{ code }}</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Best Regards, the Rowsandall Team
|
||||
</p>
|
||||
{% endblock %}
|
||||
33
rowers/templates/coachrequestemail.html
Normal file
33
rowers/templates/coachrequestemail.html
Normal file
@@ -0,0 +1,33 @@
|
||||
{% extends "emailbase.html" %}
|
||||
|
||||
{% block body %}
|
||||
<p>Dear <strong>{{ coachname }}</strong>,</p>
|
||||
|
||||
<p>
|
||||
{{ name }} is inviting you to become his/her coach
|
||||
on rowsandall.com
|
||||
</p>
|
||||
<p>
|
||||
By accepting the invite, you will have access to {{ name }}'s
|
||||
data and will be able to upload workouts and run analysis on rowsandall.com
|
||||
on behalf of {{ name }}.
|
||||
</p>
|
||||
<p>
|
||||
By accepting the invite, you are agreeing with the sharing
|
||||
of personal data according to our privacy policy.
|
||||
</p>
|
||||
<p>
|
||||
To accept the login to the
|
||||
site and you will find the invitation here on the Teams page:
|
||||
<a href="{{ siteurl }}/rowers/me/teams">{{ siteurl }}/rowers/me/teams</a>
|
||||
</p>
|
||||
<p>
|
||||
You can also click the direct link:
|
||||
<a href="{{ siteurl }}/rowers/me/coachinvitation/{{ code }}">
|
||||
{{ siteurl }}/rowers/me/coachinvitation/{{ code }}</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Best Regards, the Rowsandall Team
|
||||
</p>
|
||||
{% endblock %}
|
||||
@@ -78,7 +78,7 @@
|
||||
<label for="athlete-selector"><i class="fas fa-users fa-fw"></i> Athletes</label>
|
||||
<ul>
|
||||
{% for member in user|coach_rowers %}
|
||||
<a href={{ request.path|userurl:member }}>
|
||||
<a href={{ request.path|userurl:member.user }}>
|
||||
<i class="fas fa-user fa-fw"></i>
|
||||
{% if member.user == rower.user %}
|
||||
•
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<label for="athlete-selector"><i class="fas fa-users fa-fw"></i> Athletes</label>
|
||||
<ul>
|
||||
{% for member in user|coach_rowers %}
|
||||
<a href={{ request.path|userurl:member }}?when={{ timeperiod }}>
|
||||
<a href={{ request.path|userurl:member.user }}?when={{ timeperiod }}>
|
||||
<i class="fas fa-user fa-fw"></i>
|
||||
{% if member.user == rower.user %}
|
||||
•
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<label for="athlete-selector"><i class="fas fa-users fa-fw"></i> Athletes</label>
|
||||
<ul>
|
||||
{% for member in user|coach_rowers %}
|
||||
<a href={{ request.path|userurl:member }}>
|
||||
<a href={{ request.path|userurl:member.user }}>
|
||||
<i class="fas fa-user fa-fw"></i>
|
||||
{% if member.user == rower.user %}
|
||||
•
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</li>
|
||||
<li id="create">
|
||||
<a href="/rowers/team/create/">
|
||||
<i class="fas fa-plus fa-fw"></i> New Team
|
||||
<i class="fas fa-plus fa-fw"></i> New Training Group
|
||||
</a>
|
||||
</li>
|
||||
</ul><!-- cd-accordion-menu -->
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<ul>
|
||||
{% for member in user|coach_rowers %}
|
||||
<li>
|
||||
<a href={{ request.path|userurl:member }}>
|
||||
<a href={{ request.path|userurl:member.user }}>
|
||||
<i class="fas fa-user fa-fw"></i>
|
||||
{% if member.user == rower.user and not team %}
|
||||
•
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
{% for member in members %}
|
||||
<tr>
|
||||
{% if team.manager == user %}
|
||||
<td><a href="/rowers/me/preferences/{{ member.id }}/"> {{ member.user.first_name }} {{ member.user.last_name }}</a></td>
|
||||
<td><a href="/rowers/me/preferences/user/{{ member.user.id }}/"> {{ member.user.first_name }} {{ member.user.last_name }}</a></td>
|
||||
<td><a class="button red small" href="/rowers/me/team/{{ team.id }}/drop/{{ member.user.id }}/">Drop</a></td>
|
||||
{% else %}
|
||||
<td>{{ member.user.first_name }} {{ member.user.last_name }}</td>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<a class="button green" href="/rowers/team/create/">New Team</a>
|
||||
<a class="button green" href="/rowers/team/create/">New Training Group</a>
|
||||
</li>
|
||||
{% if coaches %}
|
||||
<li>
|
||||
@@ -136,7 +136,7 @@
|
||||
{% endif %}
|
||||
{% if invites or requests or myrequests or myinvites %}
|
||||
<li class="grid_2">
|
||||
<h2>Invitations and Requests</h2>
|
||||
<h2>Group Invitations and Requests</h2>
|
||||
<p>This section lists open invites to join a group. By accepting
|
||||
a group invite, you are agreeing with the sharing
|
||||
of personal data between group members and coaches according to
|
||||
@@ -221,7 +221,131 @@
|
||||
<input class="button green" type="submit" value="Submit">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if mycoachrequests or mycoachoffers or coachoffers or coachrequests %}
|
||||
<li class="grid_2">
|
||||
<h2>Coaching Invitations and Requests</h2>
|
||||
<p>This section lists open invites related to coaching.
|
||||
By accepting a coaching invite, the coach can run
|
||||
analysis, add workouts and edit settings on behalf of the athlete.
|
||||
You agree to the sharing
|
||||
of personal data between athletes and coaches according to
|
||||
our <a href="/rowers/legal/">privacy policy</a>.
|
||||
</p>
|
||||
<table width="90%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Coach</th>
|
||||
<th>User</th>
|
||||
<th>Action</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for i in coachrequests %}
|
||||
<tr>
|
||||
<td>{{ i.coach.user.first_name }} {{ i.coach.user.last_name }}</td>
|
||||
<td>{{ i.user.first_name }} {{ i.user.last_name }}</td>
|
||||
<td><a
|
||||
class="button small green"
|
||||
href="/rowers/me/coachrequest/{{ i.code }}/accept">Accept</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="button small red" href="/rowers/me/coachrequest/{{ i.id }}/reject/">Reject</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for i in mycoachoffers %}
|
||||
<tr>
|
||||
<td>{{ i.coach.user.first_name }} {{ i.coach.user.last_name }}</td>
|
||||
<td>{{ i.user.first_name }} {{ i.user.last_name }}</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<a class="button small red" href="/rowers/me/coachoffer/{{ i.id }}/revoke/">Revoke</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for i in mycoachrequests %}
|
||||
<tr>
|
||||
<td>{{ i.coach.user.first_name }} {{ i.coach.user.last_name }}</td>
|
||||
<td>{{ i.user.first_name }} {{ i.user.last_name }}</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<a
|
||||
class="button small red"
|
||||
href="/rowers/me/coachrequest/{{ i.id }}/revoke/">Revoke</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for i in coachoffers %}
|
||||
<tr>
|
||||
<td>{{ i.coach.user.first_name }} {{ i.coach.user.last_name }}</td>
|
||||
<td>{{ i.user.first_name }} {{ i.user.last_name }}</td>
|
||||
<td><a
|
||||
class="button small green"
|
||||
href="/rowers/me/coachoffer/{{ i.code }}/accept/">Accept</a>
|
||||
</td>
|
||||
<td>
|
||||
<a
|
||||
class="button small red"
|
||||
href="/rowers/me/coachoffer/{{ i.id }}/revoke/">Reject</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% if potentialathletes %}
|
||||
<li>
|
||||
<h2>Rowers you could coach</h2>
|
||||
<table width="90%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for a in potentialathletes %}
|
||||
<tr>
|
||||
<td>{{ a.user.first_name }} {{ a.user.last_name }}</td>
|
||||
<td>
|
||||
<a
|
||||
class="button small green"
|
||||
href="/rowers/me/coacheerequest/{{ a.user.id }}/">Offer Coaching</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if potentialcoaches %}
|
||||
<li>
|
||||
<h2>Coaches who could coach you</h2>
|
||||
<table width="90%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in potentialcoaches %}
|
||||
<tr>
|
||||
<td>{{ c.first_name }} {{ c.last_name }}</td>
|
||||
<td>
|
||||
<a
|
||||
class="button small green"
|
||||
href="/rowers/me/coachrequest/{{ c.id }}/">Request Coaching</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
BIN
rowers/tests/testdata/testdata.csv.gz
vendored
BIN
rowers/tests/testdata/testdata.csv.gz
vendored
Binary file not shown.
@@ -410,6 +410,22 @@ urlpatterns = [
|
||||
url(r'^team/(?P<id>\d+)/leave/$',views.team_leave_view,name='team_leave_view'),
|
||||
url(r'^team/(?P<id>\d+)/deleteconfirm/$',views.team_deleteconfirm_view,name='team_deleteconfirm_view'),
|
||||
url(r'^team/(?P<teamid>\d+)/requestmembership/(?P<userid>\d+)/$',views.team_requestmembership_view,name='team_requestmembership_view'),
|
||||
url(r'^me/coachrequest/(?P<id>\d+)/reject/$',views.reject_revoke_coach_request,
|
||||
name='reject_revoke_coach_request'),
|
||||
url(r'^me/coachrequest/(?P<id>\d+)/revoke/$',views.reject_revoke_coach_request,
|
||||
name='reject_revoke_coach_request'),
|
||||
url(r'^me/coachoffer/(?P<id>\d+)/reject/$',views.reject_revoke_coach_offer,
|
||||
name='reject_revoke_coach_offer'),
|
||||
url(r'^me/coachoffer/(?P<id>\d+)/revoke/$',views.reject_revoke_coach_offer,
|
||||
name='reject_revoke_coach_offer'),
|
||||
url(r'^me/coachrequest/(?P<coachid>\d+)/$',views.request_coaching_view,
|
||||
name='request_coaching_view'),
|
||||
url(r'^me/coachoffer/(?P<userid>\d+)/$',views.offer_coaching_view,
|
||||
name='offer_coaching_view'),
|
||||
url(r'^me/coachrequest/(\w+.*)/accept/$',views.coach_accept_coachrequest_view,
|
||||
name='coach_accept_coachrequest_view'),
|
||||
url(r'^me/coachoffer/(\w+.*)/accept/$',views.rower_accept_coachoffer_view,
|
||||
name='rower_accept_coachofer_view'),
|
||||
url(r'^team/(?P<id>\d+)/delete/$',views.team_delete_view,name='team_delete_view'),
|
||||
url(r'^team/create/$',views.team_create_view,name='team_create_view'),
|
||||
url(r'^me/team/(?P<teamid>\d+)/drop/(?P<userid>\d+)/$',views.manager_member_drop_view,name='manager_member_drop_view'),
|
||||
|
||||
@@ -88,7 +88,7 @@ from rowers.models import (
|
||||
microcyclecheckdates,mesocyclecheckdates,macrocyclecheckdates,
|
||||
TrainingMesoCycleForm, TrainingMicroCycleForm,
|
||||
RaceLogo,RowerBillingAddressForm,PaidPlan,
|
||||
PlannedSessionComment,
|
||||
PlannedSessionComment,CoachRequest,CoachOffer,
|
||||
)
|
||||
from rowers.models import (
|
||||
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
||||
|
||||
@@ -166,12 +166,35 @@ def rower_teams_view(request,message='',successmessage=''):
|
||||
|
||||
myteams, memberteams, otherteams = get_teams(request)
|
||||
teams.remove_expired_invites()
|
||||
|
||||
|
||||
invites = TeamInvite.objects.filter(user=request.user)
|
||||
requests = TeamRequest.objects.filter(user=request.user)
|
||||
myrequests = TeamRequest.objects.filter(team__in=myteams)
|
||||
myinvites = TeamInvite.objects.filter(team__in=myteams)
|
||||
|
||||
# user invites (as coach)
|
||||
mycoachoffers = CoachOffer.objects.filter(coach=r)
|
||||
# user is invited (by coach)
|
||||
coachoffers = CoachOffer.objects.filter(user=r.user)
|
||||
|
||||
# user requests a coach
|
||||
mycoachrequests = CoachRequest.objects.filter(user=r.user)
|
||||
# user is requested to coach
|
||||
coachrequests = CoachRequest.objects.filter(coach=r)
|
||||
|
||||
invitedathletes = [rekwest.user for rekwest in mycoachoffers]
|
||||
invitedcoaches = [rekwest.coach for rekwest in mycoachrequests]
|
||||
|
||||
coaches = rower_get_coaches(r)
|
||||
potentialcoaches = [t.manager for t in memberteams if t.manager not in coaches ]
|
||||
potentialcoaches = [c for c in potentialcoaches if c.rower not in invitedcoaches]
|
||||
coachees = teams.coach_getcoachees(r)
|
||||
|
||||
potentialathletes = Rower.objects.filter(
|
||||
team__in=myteams).exclude(
|
||||
user__in=invitedathletes).exclude(user=request.user)
|
||||
|
||||
|
||||
# clubsize = teams.count_invites(request.user)+teams.count_club_members(request.user)
|
||||
# max_clubsize = r.clubsize
|
||||
|
||||
@@ -184,6 +207,7 @@ def rower_teams_view(request,message='',successmessage=''):
|
||||
'name': 'Teams'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
return render(request, 'teams.html',
|
||||
{
|
||||
@@ -198,6 +222,14 @@ def rower_teams_view(request,message='',successmessage=''):
|
||||
'myrequests':myrequests,
|
||||
'form':form,
|
||||
'myinvites':myinvites,
|
||||
'mycoachrequests':mycoachrequests,
|
||||
'mycoachoffers':mycoachoffers,
|
||||
'coachrequests':coachrequests,
|
||||
'coachoffers':coachoffers,
|
||||
'coaches':coaches,
|
||||
'potentialcoaches':potentialcoaches,
|
||||
'coachees':coachees,
|
||||
'potentialathletes':potentialathletes,
|
||||
})
|
||||
|
||||
@login_required()
|
||||
@@ -276,6 +308,71 @@ def team_requestmembership_view(request,teamid,userid):
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@login_required()
|
||||
def request_coaching_view(request,coachid):
|
||||
r = getrequestrower(request)
|
||||
|
||||
coach = User.objects.get(id=coachid).rower
|
||||
|
||||
if coach.rowerplan == 'coach':
|
||||
res,text = teams.create_coaching_request(coach,request.user)
|
||||
if res:
|
||||
messages.info(request,text)
|
||||
else:
|
||||
messages.error(request,text)
|
||||
else:
|
||||
messages.error(request,'That person is not a coach')
|
||||
|
||||
url = reverse('rower_teams_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
|
||||
def offer_coaching_view(request,userid):
|
||||
try:
|
||||
u = User.objects.get(id=userid)
|
||||
except User.DoesNotExist:
|
||||
raise Http404("This user doesn't exist")
|
||||
|
||||
coach = getrequestrower(request)
|
||||
|
||||
res,text = teams.create_coaching_invite(coach,u)
|
||||
|
||||
if res:
|
||||
message.info(request,text)
|
||||
else:
|
||||
messages.error(request,text)
|
||||
|
||||
url = reverse('rower_teams_view')
|
||||
|
||||
return HttpResponseRedirecet(url)
|
||||
|
||||
@login_required()
|
||||
def reject_revoke_coach_request(request,id=0):
|
||||
res, text = teams.reject_revoke_coach_request(request.user,id)
|
||||
|
||||
if res:
|
||||
messages.info(request,text)
|
||||
else:
|
||||
messages.error(request,text)
|
||||
|
||||
url = reverse('rower_teams_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@login_required()
|
||||
def reject_revoke_coach_offer(request,id=0):
|
||||
res, text = teams.reject_revoke_coach_offer(request.user,id)
|
||||
|
||||
if res:
|
||||
messages.info(request,text)
|
||||
else:
|
||||
messages.error(request,text)
|
||||
|
||||
url = reverse('rower_teams_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@login_required()
|
||||
def request_revoke_view(request,id=0):
|
||||
res,text = teams.revoke_request(request.user,id)
|
||||
@@ -559,3 +656,27 @@ def team_members_stats_view(request,id):
|
||||
})
|
||||
|
||||
return response
|
||||
|
||||
@login_required()
|
||||
def rower_accept_coachoffer_view(request,code=None):
|
||||
if code:
|
||||
res, text = teams.process_coachoffer_code(request.user,code)
|
||||
if res:
|
||||
message.info(request,text)
|
||||
else:
|
||||
messages.error(request,text)
|
||||
|
||||
url = reverse('rower_teams_view')
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@login_required()
|
||||
def coach_accept_coachrequest_view(request,code=None):
|
||||
if code:
|
||||
res, text = teams.process_coachrequest_code(request.user.rower,code)
|
||||
if res:
|
||||
messages.info(request,text)
|
||||
else:
|
||||
messages.error(request,text)
|
||||
|
||||
url = reverse('rower_teams_view')
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
Reference in New Issue
Block a user