Private
Public Access
1
0

adding functionality to comment on planned sessions and races

This commit is contained in:
Sander Roosendaal
2019-02-13 15:13:49 +01:00
parent da4d39709e
commit 3709ad7ccb
12 changed files with 305 additions and 10 deletions

View File

@@ -3343,3 +3343,28 @@ class WorkoutCommentForm(ModelForm):
'comment': forms.Textarea,
}
# A comment by a user on a training
class PlannedSessionComment(models.Model):
comment = models.TextField(max_length=300)
created = models.DateTimeField(default=timezone.now)
read = models.BooleanField(default=False)
notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
user = models.ForeignKey(User)
plannedsession = models.ForeignKey(PlannedSession)
def __unicode__(self):
return u'Comment to: {w} by {u1} {u2}'.format(
w=self.workout,
u1 = self.user.first_name,
u2 = self.user.last_name,
)
class PlannedSessionCommentForm(ModelForm):
class Meta:
model = PlannedSessionComment
fields = ['comment','notification']
widgets = {
'comment': forms.Textarea,
}

View File

@@ -1737,7 +1737,7 @@ def handle_sendemailnewresponse(first_name, last_name,
debug=False,**kwargs):
fullemail = email
from_email = 'Rowsandall <info@rowsandall.com>'
subject = 'New comment on workout ' + workoutname
subject = 'New comment on session ' + workoutname
comment = u''+comment
@@ -1745,7 +1745,14 @@ def handle_sendemailnewresponse(first_name, last_name,
if debug:
siteurl = SITE_URL_DEV
sessiontype = 'workout'
if 'sessiontype' in kwargs:
sessiontype=kwargs.pop('sessiontype')
commentlink = '/rowers/workout/{workoutid}/comment/'.format(workoutid=workoutid)
if 'commentlink' in kwargs:
commentlink = kwargs.pop('commentlink')
d = {
'first_name':first_name,
'commenter_first_name':commenter_first_name,
@@ -1754,10 +1761,14 @@ def handle_sendemailnewresponse(first_name, last_name,
'workoutname':workoutname,
'siteurl':siteurl,
'workoutid':workoutid,
'commentid':commentid
'commentid':commentid,
'sessiontype':sessiontype,
'commentlink':commentlink,
}
res = send_template_email(from_email,[fullemail],subject,'teamresponseemail.html',d,**kwargs)
res = send_template_email(from_email,
[fullemail],
subject,'teamresponseemail.html',d,**kwargs)
return 1
@@ -1776,7 +1787,7 @@ def handle_sendemailnewcomment(first_name,
fullemail = email
from_email = 'Rowsandall <info@rowsandall.com>'
subject = 'New comment on workout ' + workoutname
subject = 'New comment on session ' + workoutname
comment = u''+comment
@@ -1784,7 +1795,14 @@ def handle_sendemailnewcomment(first_name,
if debug:
siteurl = SITE_URL_DEV
sessiontype = 'workout'
if 'sessiontype' in kwargs:
sessiontype=kwargs.pop('sessiontype')
commentlink = '/rowers/workout/{workoutid}/comment/'.format(workoutid=workoutid)
if 'commentlink' in kwargs:
commentlink = kwargs.pop('commentlink')
d = {
'first_name':first_name,
'commenter_first_name':commenter_first_name,
@@ -1793,6 +1811,8 @@ def handle_sendemailnewcomment(first_name,
'workoutname':workoutname,
'siteurl':siteurl,
'workoutid':workoutid,
'sessiontype':sessiontype,
'commentlink':commentlink,
}
res = send_template_email(from_email,[fullemail],subject,

View File

@@ -0,0 +1,47 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% load tz %}
{% block scripts %}
{% include "monitorjobs.html" %}
{% endblock %}
{% block title %}Comment Session {% endblock %}
{% block main %}
<h1>Comments {{ plannedession.name }}</h1>
<ul class="main-content">
<li class="grid_2">
{% for c in comments %}
<p>
{{ c.created }}
<b>{{ c.user.first_name }} {{ c.user.last_name }}</b>
<div class="talk-bubble tri-right left-top">
<div class="talktext">
{{ c.comment }}
</div>
</div>
</p>
{% endfor %}
<form enctype="multipart/form-data" method="post">
<table width=100%>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Save">
</form>
</li>
</ul>
{% endblock %}
{% block sidebar %}
{% if 'racing' in active %}
{% include 'menu_racing.html' %}
{% else %}
{% include 'menu_plan.html' %}
{% endif %}
{% endblock %}

View File

@@ -135,6 +135,20 @@
title="Compare the workouts of all athletes who did this session">Compare Workouts</a>
</p>
</li>
<li class="grid_2">
<div id="comments">
<h2>Comments ({{ comments|length }})</h2>
{% for c in comments %}
<p>
<em>{{ c.user.first_name }} {{ c.user.last_name }}</em> - {{ c.created }}</br>
<q>{{ c.comment }}</q>
</p>
{% endfor %}
<p>
<a href="/rowers/sessions/{{ race.id }}/comments/">Add a comment</a>
</p>
</div>
</li>
{% if coursescript %}
<li class="grid_2">
<h2>Course</h2>

View File

@@ -5,7 +5,7 @@
<p>
{{ commenter_first_name }} {{ commenter_last_name }} has written
a new comment on workout {{ workoutname }}
a new comment on {{ sessiontype }} {{ workoutname }}
</p>
<p>
{{ comment }}
@@ -14,8 +14,8 @@
You can read the comment here:
</p>
<p>
<a href="{{ siteurl }}/rowers/workout/{{ workoutid }}/comment">
{{ siteurl }}/rowers/workout/{{ workoutid }}/comment</a>
<a href="{{ siteurl }} {{ commentlink }}">
{{ siteurl }}{{ commentlink }}</a>
</p>
<p>

View File

@@ -423,6 +423,20 @@
{% endif %}
{% endfor %}
</li>
<li class="grid_2">
<div id="comments">
<h2>Comments ({{ comments|length }})</h2>
{% for c in comments %}
<p>
<em>{{ c.user.first_name }} {{ c.user.last_name }}</em> - {{ c.created }}</br>
<q>{{ c.comment }}</q>
</p>
{% endfor %}
<p>
<a href="/rowers/sessions/{{ race.id }}/comments/">Add a comment</a>
</p>
</div>
</li>
<li class="grid_4">
<div id="rules">
<p>

View File

@@ -486,6 +486,25 @@ class SessionCompleteTest(TestCase):
self.assertEqual(verdict,'on target')
def test_session_comment(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = reverse('plannedsession_comment_view',kwargs={'id':self.ps_rscore.id})
response = self.c.get(url)
self.assertEqual(response.status_code,200)
form_data = {
'comment': faker.text()
}
form = WorkoutCommentForm(form_data)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
self.assertEqual(response.status_code,200)
def test_session1_exact_complete(self):

Binary file not shown.

View File

@@ -608,6 +608,10 @@ urlpatterns = [
name='plannedsessions_coach_view'),
url(r'^sessions/print/?/$',views.plannedsessions_print_view,
name='plannedsessions_print_view'),
url(r'^sessions/(?P<id>\d+)/comments/user/(?P<userid>\d+)/$',views.plannedsession_comment_view,
name='plannedsession_comment_view'),
url(r'^sessions/(?P<id>\d+)/comments/$',views.plannedsession_comment_view,
name='plannedsession_comment_view'),
url(r'^sessions/print/user/(?P<userid>\d+)/$',views.plannedsessions_print_view,
name='plannedsessions_print_view'),
url(r'^sessions/sendcalendar/$',views.plannedsessions_icsemail_view,

View File

@@ -1,6 +1,150 @@
from statements import *
@login_required()
def plannedsession_comment_view(request,id=0,userid=0):
r = getrequestrower(request,userid=userid)
try:
ps = PlannedSession.objects.get(id=id)
except PlannedSession.DoesNotExist:
raise Http404("Planned Session does not exist")
m = ps.manager
mm = Rower.objects.get(user=m)
if ps.manager != request.user and ps.sessiontype not in ['race','indoorrace']:
if r.rowerplan == 'coach' and r not in ps.rower.all():
teams = Team.objects.filter(manager=request.user)
members = Rower.objects.filter(team__in=teams).distinct()
teamusers = [m.user for m in members]
if ps.manager not in teamusers:
raise PermissionDenied("You do not have access to this session")
elif r not in ps.rower.all():
raise PermissionDenied("You do not have access to this session")
comments = PlannedSessionComment.objects.filter(plannedsession=ps).order_by("created")
if request.method == 'POST':
manager = ps.manager
form = PlannedSessionCommentForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
comment = cd['comment']
comment = bleach.clean(comment)
if isinstance(comment,unicode):
comment = comment.encode('utf8')
elif isinstance(comment, str):
comment = comment.decode('utf8')
notification = cd['notification']
c = PlannedSessionComment(plannedsession=ps,user=request.user,comment=comment,
notification=notification)
c.save()
url = reverse('plannedsession_comment_view',
kwargs={
'id':id
})
message = '{name} says: <a href="{url}">{comment}</a>'.format(
name = request.user.first_name,
comment = comment,
url = url,
)
if request.user != manager:
a_messages.info(r.user,message.encode('ascii','ignore'))
sessiontype = 'training session'
if ps.sessiontype == 'race':
sessiontype = 'online virtual race'
elif ps.sessiontype == 'indoorrace':
sessiontype = 'indoor online virtual race'
res = myqueue(queuehigh,
handle_sendemailnewcomment,r.user.first_name,
r.user.last_name,
r.user.email,
request.user.first_name,
request.user.last_name,
comment,ps.name,ps.id,
emailbounced = r.emailbounced,
sessiontype = sessiontype,
commentlink = url
)
commenters = {oc.user for oc in comments if oc.notification}
for u in commenters:
a_messages.info(u,message)
if u != request.user and u != r.user:
ocr = Rower.objects.get(user=u)
res = myqueue(queuelow,
handle_sendemailnewresponse,
u.first_name,
u.last_name,
u.email,
request.user.first_name,
request.user.last_name,
comment,
ps.name,
ps.id,
c.id,
emailbounced = ocr.emailbounced,
sessiontype = sessiontype,
commentlink = url
)
url = reverse('plannedsession_comment_view',kwargs={'id':ps.id})
return HttpResponseRedirect(url)
form = WorkoutCommentForm()
rower = getrower(request.user)
if ps.sessiontype in ['race','indoorrace']:
breadcrumbs = [
{
'url':reverse('virtualevents_view'),
'name': 'Races'
},
{
'url': reverse('virtualevent_view',kwargs={'id':ps.id}),
'name': ps.name
},
{
'url':reverse('plannedsession_comment_view',kwargs={'id':ps.id}),
'name': 'Comments'
}
]
active = 'nav-racing'
else:
breadcrumbs = [
{
'url':reverse('virtualevents_view'),
'name': 'Races'
},
{
'url': reverse('virtualevent_view',kwargs={'id':ps.id}),
'name': ps.name
},
{
'url':reverse('plannedsession_comment_view',kwargs={'id':ps.id}),
'name': 'Comments'
}
]
active = 'nav-plan'
return render(request,
'plannedsession_comments.html',
{'plannedsession':ps,
'rower':rower,
'breadcrumbs':breadcrumbs,
'active':active,
'comments':comments,
'form':form,
})
# Cloning sessions
@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
@@ -1385,7 +1529,7 @@ def plannedsession_view(request,id=0,userid=0):
raise Http404("Planned Session does not exist")
if ps.sessiontype in ['race','indoorrace']:
url = reverse(virtualevent_view,
url = reverse('virtualevent_view',
kwargs={'id':ps.id}
)
return HttpResponseRedirect(url)
@@ -1522,6 +1666,8 @@ def plannedsession_view(request,id=0,userid=0):
}
]
comments = PlannedSessionComment.objects.filter(plannedsession=ps).order_by("created")
return render(request,'plannedsessionview.html',
{
'psdict': psdict,
@@ -1544,7 +1690,8 @@ def plannedsession_view(request,id=0,userid=0):
'timeperiod':timeperiod,
'ranking':ranking,
'coursescript': coursescript,
'coursediv': coursediv
'coursediv': coursediv,
'comments': comments,
}
)

View File

@@ -882,6 +882,9 @@ def virtualevent_view(request,id=0):
else:
racelogo = None
comments = PlannedSessionComment.objects.filter(plannedsession=race).order_by("created")
return render(request,'virtualevent.html',
{
'coursescript':script,
@@ -896,6 +899,7 @@ def virtualevent_view(request,id=0):
'racelogo':racelogo,
'form':form,
'active':'nav-racing',
'comments':comments
})
def virtualevent_ranking_view(request,id=0):

View File

@@ -87,6 +87,7 @@ from rowers.models import (
microcyclecheckdates,mesocyclecheckdates,macrocyclecheckdates,
TrainingMesoCycleForm, TrainingMicroCycleForm,
RaceLogo,RowerBillingAddressForm,PaidPlan,
PlannedSessionComment,
)
from rowers.models import (
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
@@ -97,7 +98,7 @@ from rowers.models import (
PlannedSessionFormSmall,GeoCourseEditForm,VirtualRace,
VirtualRaceForm,VirtualRaceResultForm,RowerImportExportForm,
IndoorVirtualRaceResultForm,IndoorVirtualRaceResult,
IndoorVirtualRaceForm,
IndoorVirtualRaceForm,PlannedSessionCommentForm,
)
from rowers.models import (
FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement,BasePlannedSessionFormSet,