adding functionality to comment on planned sessions and races
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +1745,13 @@ 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,
|
||||
@@ -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,6 +1795,13 @@ 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,
|
||||
@@ -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,
|
||||
|
||||
47
rowers/templates/plannedsession_comments.html
Normal file
47
rowers/templates/plannedsession_comments.html
Normal 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 %}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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):
|
||||
|
||||
BIN
rowers/tests/testdata/testdata.csv.gz
vendored
BIN
rowers/tests/testdata/testdata.csv.gz
vendored
Binary file not shown.
@@ -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,
|
||||
|
||||
@@ -1,5 +1,149 @@
|
||||
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/",
|
||||
@@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user