Skip to content

Commit 7a0a990

Browse files
committed
Merged in [14468] from rjsparks@nostrum.com:
Add the ability to add a comment to a group's history. Fixes ietf-tools#1483. - Legacy-Id: 14485 Note: SVN reference [14468] has been migrated to Git commit 13e8f89
2 parents 8ff59cd + 13e8f89 commit 7a0a990

10 files changed

Lines changed: 171 additions & 8 deletions

File tree

ietf/group/mails.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,12 @@ def wrap_up_email(addrs, text):
5757
if (addrs.to or addrs.cc) and msg:
5858
wrap_up_email(addrs, msg)
5959

60+
def email_comment(request, event):
61+
(to, cc) = gather_address_lists('group_added_comment',group=event.group)
62+
send_mail(request, to, None, "Comment added to %s history"%event.group.acronym,
63+
"group/comment_added_email.txt",
64+
dict( event = event,
65+
group_url=settings.IDTRACKER_BASE_URL + event.group.about_url(),
66+
),
67+
cc = cc)
68+

ietf/group/tests_info.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,30 @@ def test_conclude(self):
738738
group = Group.objects.get(acronym=group.acronym)
739739
self.assertEqual(group.state_id, "active")
740740

741+
def test_add_comment(self):
742+
make_test_data()
743+
group = Group.objects.get(acronym="mars")
744+
url = urlreverse('ietf.group.views.add_comment', kwargs=dict(acronym=group.acronym))
745+
empty_outbox()
746+
for username in ['secretary','ad','marschairman','marssecretary','marsdelegate']:
747+
login_testing_unauthorized(self, username, url)
748+
# get
749+
r = self.client.get(url)
750+
self.assertContains(r, "Add comment")
751+
self.assertContains(r, group.acronym)
752+
q = PyQuery(r.content)
753+
self.assertEqual(len(q('form textarea[name=comment]')), 1)
754+
# post
755+
r = self.client.post(url, dict(comment="Test comment %s"%username))
756+
self.assertEqual(r.status_code, 302)
757+
person = Person.objects.get(user__username=username)
758+
self.assertTrue(GroupEvent.objects.filter(group=group,by=person,type='added_comment',desc='Test comment %s'%username).exists())
759+
self.client.logout()
760+
self.client.login(username='ameschairman',password='ameschairman+password')
761+
r=self.client.get(url)
762+
self.assertEqual(r.status_code,403)
763+
self.assertEqual(len(outbox),5)
764+
741765
class MilestoneTests(TestCase):
742766
def create_test_milestones(self):
743767
draft = make_test_data()

ietf/group/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
url(r'^about/status/edit/$', views.group_about_status_edit),
2525
url(r'^about/status/meeting/(?P<num>\d+)/$', views.group_about_status_meeting),
2626
url(r'^history/$',views.history),
27+
url(r'^history/addcomment/$',views.add_comment),
2728
url(r'^email/$', views.email),
2829
url(r'^deps/(?P<output_type>[\w-]+)/$', views.dependencies),
2930
url(r'^meetings/$', views.meetings),

ietf/group/views.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
from tempfile import mkstemp
4242
from collections import OrderedDict, defaultdict
4343

44+
from django import forms
4445
from django.conf import settings
4546
from django.contrib.auth.decorators import login_required
4647
from django.db.models.aggregates import Max
@@ -65,7 +66,7 @@
6566
from ietf.group.forms import (GroupForm, StatusUpdateForm, ConcludeGroupForm, StreamEditForm,
6667
ManageReviewRequestForm, EmailOpenAssignmentsForm, ReviewerSettingsForm,
6768
AddUnavailablePeriodForm, EndUnavailablePeriodForm, ReviewSecretarySettingsForm, )
68-
from ietf.group.mails import email_admin_re_charter, email_personnel_change
69+
from ietf.group.mails import email_admin_re_charter, email_personnel_change, email_comment
6970
from ietf.group.models import ( Group, Role, GroupEvent, GroupStateTransitions, GroupURL, ChangeStateGroupEvent )
7071
from ietf.group.utils import (get_charter_text, can_manage_group_type,
7172
milestone_reviewer_for_group_type, can_provide_status_update,
@@ -74,7 +75,7 @@
7475
save_group_in_history, can_manage_group,
7576
get_group_or_404, setup_default_community_list_for_group, )
7677
#
77-
from ietf.ietfauth.utils import has_role
78+
from ietf.ietfauth.utils import has_role, is_authorized_in_group
7879
from ietf.mailtrigger.utils import gather_relevant_expansions
7980
from ietf.meeting.helpers import get_meeting
8081
from ietf.meeting.utils import group_sessions
@@ -632,10 +633,13 @@ def history(request, acronym, group_type=None):
632633
group = get_group_or_404(acronym, group_type)
633634

634635
events = group.groupevent_set.all().select_related('by').order_by('-time', '-id')
636+
can_add_comment = is_authorized_in_group(request.user,group)
635637

636638
return render(request, 'group/history.html',
637639
construct_group_menu_context(request, group, "history", group_type, {
640+
"group": group,
638641
"events": events,
642+
"can_add_comment": can_add_comment,
639643
}))
640644

641645
def materials(request, acronym, group_type=None):
@@ -1784,4 +1788,24 @@ def change_review_secretary_settings(request, acronym, group_type=None):
17841788
'back_url': back_url,
17851789
'settings_form': settings_form,
17861790
})
1791+
1792+
class AddCommentForm(forms.Form):
1793+
comment = forms.CharField(required=True, widget=forms.Textarea, strip=False)
1794+
1795+
def add_comment(request, acronym, group_type=None):
1796+
group = get_group_or_404(acronym, group_type)
1797+
1798+
if not is_authorized_in_group(request.user,group):
1799+
return HttpResponseForbidden("You need to a chair, secretary, or delegate of this group to add a comment.")
17871800

1801+
if request.method == 'POST':
1802+
form = AddCommentForm(request.POST)
1803+
if form.is_valid():
1804+
comment = form.cleaned_data['comment']
1805+
event = GroupEvent.objects.create(group=group,desc=comment,type="added_comment",by=request.user.person)
1806+
email_comment(request,event)
1807+
return redirect('ietf.group.views.history', acronym=group.acronym)
1808+
else:
1809+
form = AddCommentForm()
1810+
1811+
return render(request, 'group/add_comment.html', { 'group':group, 'form':form, })

ietf/ietfauth/utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,26 @@ def is_authorized_in_doc_stream(user, doc):
144144

145145
return Role.objects.filter(Q(name__in=("chair", "secr", "delegate", "auth"), person__user=user) & group_req).exists()
146146

147+
def is_authorized_in_group(user, group):
148+
"""Return whether user is authorized to perform duties on
149+
a given group."""
150+
151+
if not user.is_authenticated:
152+
return False
153+
154+
if has_role(user, ["Secretariat",]):
155+
return True
156+
157+
if group.parent:
158+
if group.parent.type_id == 'area' and has_role(user, ['Area Director',]):
159+
return True
160+
if group.parent.acronym == 'irtf' and has_role(user, ['IRTF Chair',]):
161+
return True
162+
if group.parent.acronym == 'iab' and has_role(user, ['IAB','IAB Executive Director',]):
163+
return True
164+
165+
return Role.objects.filter(name__in=("chair", "secr", "delegate", "auth"), person__user=user,group=group ).exists()
166+
147167
def is_individual_draft_author(user, doc):
148168

149169
if not user.is_authenticated:
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.10.8 on 2017-12-28 11:11
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations
6+
7+
def forward(apps, schema_editor):
8+
MailTrigger = apps.get_model('mailtrigger','MailTrigger')
9+
Recipient = apps.get_model('mailtrigger', 'Recipient')
10+
group_added_comment = MailTrigger.objects.create(
11+
slug='group_added_comment',
12+
desc="Recipients when a comment is added to a group's history",
13+
)
14+
group_added_comment.to = Recipient.objects.filter(slug__in=[
15+
'group_chairs',
16+
'group_secretaries',
17+
'group_responsible_directors',
18+
])
19+
20+
def reverse(apps, schema_editor):
21+
MailTrigger = apps.get_model('mailtrigger','MailTrigger')
22+
MailTrigger.objects.filter(slug='group_added_comment').delete()
23+
24+
25+
class Migration(migrations.Migration):
26+
27+
dependencies = [
28+
('mailtrigger', '0010_auto_20161207_1104'),
29+
]
30+
31+
operations = [
32+
migrations.RunPython(forward, reverse)
33+
]

ietf/name/fixtures/names.json

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,19 @@
27322732
"model": "mailtrigger.mailtrigger",
27332733
"pk": "doc_telechat_details_changed"
27342734
},
2735+
{
2736+
"fields": {
2737+
"cc": [],
2738+
"desc": "Recipients when a comment is added to a group's history",
2739+
"to": [
2740+
"group_chairs",
2741+
"group_responsible_directors",
2742+
"group_secretaries"
2743+
]
2744+
},
2745+
"model": "mailtrigger.mailtrigger",
2746+
"pk": "group_added_comment"
2747+
},
27352748
{
27362749
"fields": {
27372750
"cc": [],
@@ -3091,6 +3104,7 @@
30913104
"fields": {
30923105
"cc": [
30933106
"doc_group_chairs",
3107+
"doc_group_mail_list",
30943108
"doc_notify",
30953109
"doc_shepherd",
30963110
"iesg_secretary"
@@ -8470,7 +8484,7 @@
84708484
},
84718485
{
84728486
"fields": {
8473-
"default_offset_days": -89,
8487+
"default_offset_days": -68,
84748488
"desc": "IETF Online Registration Opens",
84758489
"name": "Registration Opens",
84768490
"order": 0,
@@ -9988,7 +10002,7 @@
998810002
"fields": {
998910003
"command": "xym",
999010004
"switch": "--version",
9991-
"time": "2017-09-29T00:07:40.668",
10005+
"time": "2017-12-31T00:07:14.314",
999210006
"used": true,
999310007
"version": "xym 0.4"
999410008
},
@@ -9999,7 +10013,7 @@
999910013
"fields": {
1000010014
"command": "pyang",
1000110015
"switch": "--version",
10002-
"time": "2017-09-29T00:07:41.703",
10016+
"time": "2017-12-31T00:07:15.241",
1000310017
"used": true,
1000410018
"version": "pyang 1.7.3"
1000510019
},
@@ -10010,9 +10024,9 @@
1001010024
"fields": {
1001110025
"command": "yanglint",
1001210026
"switch": "--version",
10013-
"time": "2017-09-29T00:07:41.812",
10027+
"time": "2017-12-31T00:07:15.325",
1001410028
"used": true,
10015-
"version": "yanglint 0.13.49"
10029+
"version": "yanglint 0.14.53"
1001610030
},
1001710031
"model": "utils.versioninfo",
1001810032
"pk": 3
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{% extends "base.html" %}
2+
{# Copyright The IETF Trust 2015, All Rights Reserved #}
3+
{% load origin %}
4+
5+
{% load bootstrap3 %}
6+
7+
{% block title %}Add comment for {{ group }}{% endblock %}
8+
9+
{% block content %}
10+
{% origin %}
11+
<h1>Add comment<br><small>{{ group }} ({{ group.acronym }})</small></h1>
12+
13+
<form method="post">
14+
{% csrf_token %}
15+
{% bootstrap_form form %}
16+
<p class="help-block">The comment will be added to the history trail for the group.</p>
17+
18+
{% buttons %}
19+
<button type="submit" class="btn btn-primary">Submit</button>
20+
<a class="btn btn-default pull-right" href="{% url "ietf.group.views.history" acronym=group.acronym %}">Back</a>
21+
{% endbuttons %}
22+
</form>
23+
24+
{% endblock %}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{% autoescape off %}
2+
Please DO NOT reply to this email.
3+
4+
{{event.by}} added the following comment to the history of {{event.group.acronym}}:
5+
6+
{{ event.desc }}
7+
8+
Information for the group can be found at {{ group_url }}.
9+
10+
{% endautoescape%}

ietf/templates/group/history.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
{% block group_content %}
1212
{% origin %}
13+
<h2>Group History</h2>
14+
{% if can_add_comment %}
15+
<a class="btn btn-default" href="{% url 'ietf.group.views.add_comment' acronym=group.acronym %}"><span class="fa fa-plus"></span> Add comment</a>
16+
{% endif %}
1317
<table class="table table-condensed table-striped tablesorter">
1418
<thead>
1519
<tr>
@@ -35,4 +39,4 @@
3539

3640
{% block js %}
3741
<script src="{% static "jquery.tablesorter/js/jquery.tablesorter.combined.min.js" %}"></script>
38-
{% endblock %}
42+
{% endblock %}

0 commit comments

Comments
 (0)