Add the ability to add a comment to a group's history. Fixes #1483. Commit ready for merge.
- Legacy-Id: 14468
This commit is contained in:
parent
0a9737a5d2
commit
13e8f8982c
|
@ -57,3 +57,12 @@ def email_milestones_changed(request, group, changes, states):
|
|||
if (addrs.to or addrs.cc) and msg:
|
||||
wrap_up_email(addrs, msg)
|
||||
|
||||
def email_comment(request, event):
|
||||
(to, cc) = gather_address_lists('group_added_comment',group=event.group)
|
||||
send_mail(request, to, None, "Comment added to %s history"%event.group.acronym,
|
||||
"group/comment_added_email.txt",
|
||||
dict( event = event,
|
||||
group_url=settings.IDTRACKER_BASE_URL + event.group.about_url(),
|
||||
),
|
||||
cc = cc)
|
||||
|
||||
|
|
|
@ -738,6 +738,23 @@ class GroupEditTests(TestCase):
|
|||
group = Group.objects.get(acronym=group.acronym)
|
||||
self.assertEqual(group.state_id, "active")
|
||||
|
||||
def test_add_comment(self):
|
||||
make_test_data()
|
||||
group = Group.objects.get(acronym="mars")
|
||||
url = urlreverse('ietf.group.views.add_comment', kwargs=dict(acronym=group.acronym))
|
||||
empty_outbox()
|
||||
for username in ['secretary','ad','marschairman','marssecretary','marsdelegate']:
|
||||
login_testing_unauthorized(self, username, url)
|
||||
r = self.client.post(url, dict(comment="Test comment %s"%username))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
person = Person.objects.get(user__username=username)
|
||||
self.assertTrue(GroupEvent.objects.filter(group=group,by=person,type='added_comment',desc='Test comment %s'%username).exists())
|
||||
self.client.logout()
|
||||
self.client.login(username='ameschairman',password='ameschairman+password')
|
||||
r=self.client.get(url)
|
||||
self.assertEqual(r.status_code,403)
|
||||
self.assertEqual(len(outbox),5)
|
||||
|
||||
class MilestoneTests(TestCase):
|
||||
def create_test_milestones(self):
|
||||
draft = make_test_data()
|
||||
|
|
|
@ -24,6 +24,7 @@ info_detail_urls = [
|
|||
url(r'^about/status/edit/$', views.group_about_status_edit),
|
||||
url(r'^about/status/meeting/(?P<num>\d+)/$', views.group_about_status_meeting),
|
||||
url(r'^history/$',views.history),
|
||||
url(r'^history/addcomment/$',views.add_comment),
|
||||
url(r'^email/$', views.email),
|
||||
url(r'^deps/(?P<output_type>[\w-]+)/$', views.dependencies),
|
||||
url(r'^meetings/$', views.meetings),
|
||||
|
|
|
@ -41,6 +41,7 @@ import datetime
|
|||
from tempfile import mkstemp
|
||||
from collections import OrderedDict, defaultdict
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models.aggregates import Max
|
||||
|
@ -65,7 +66,7 @@ from ietf.group.dot import make_dot
|
|||
from ietf.group.forms import (GroupForm, StatusUpdateForm, ConcludeGroupForm, StreamEditForm,
|
||||
ManageReviewRequestForm, EmailOpenAssignmentsForm, ReviewerSettingsForm,
|
||||
AddUnavailablePeriodForm, EndUnavailablePeriodForm, ReviewSecretarySettingsForm, )
|
||||
from ietf.group.mails import email_admin_re_charter, email_personnel_change
|
||||
from ietf.group.mails import email_admin_re_charter, email_personnel_change, email_comment
|
||||
from ietf.group.models import ( Group, Role, GroupEvent, GroupStateTransitions, GroupURL, ChangeStateGroupEvent )
|
||||
from ietf.group.utils import (get_charter_text, can_manage_group_type,
|
||||
milestone_reviewer_for_group_type, can_provide_status_update,
|
||||
|
@ -74,7 +75,7 @@ from ietf.group.utils import (get_charter_text, can_manage_group_type,
|
|||
save_group_in_history, can_manage_group,
|
||||
get_group_or_404, setup_default_community_list_for_group, )
|
||||
#
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.ietfauth.utils import has_role, is_authorized_in_group
|
||||
from ietf.mailtrigger.utils import gather_relevant_expansions
|
||||
from ietf.meeting.helpers import get_meeting
|
||||
from ietf.meeting.utils import group_sessions
|
||||
|
@ -632,10 +633,13 @@ def history(request, acronym, group_type=None):
|
|||
group = get_group_or_404(acronym, group_type)
|
||||
|
||||
events = group.groupevent_set.all().select_related('by').order_by('-time', '-id')
|
||||
can_add_comment = is_authorized_in_group(request.user,group)
|
||||
|
||||
return render(request, 'group/history.html',
|
||||
construct_group_menu_context(request, group, "history", group_type, {
|
||||
"group": group,
|
||||
"events": events,
|
||||
"can_add_comment": can_add_comment,
|
||||
}))
|
||||
|
||||
def materials(request, acronym, group_type=None):
|
||||
|
@ -1784,4 +1788,24 @@ def change_review_secretary_settings(request, acronym, group_type=None):
|
|||
'back_url': back_url,
|
||||
'settings_form': settings_form,
|
||||
})
|
||||
|
||||
class AddCommentForm(forms.Form):
|
||||
comment = forms.CharField(required=True, widget=forms.Textarea, strip=False)
|
||||
|
||||
def add_comment(request, acronym, group_type=None):
|
||||
group = get_group_or_404(acronym, group_type)
|
||||
|
||||
if not is_authorized_in_group(request.user,group):
|
||||
return HttpResponseForbidden("You need to a chair, secretary, or delegate of this group to add a comment.")
|
||||
|
||||
if request.method == 'POST':
|
||||
form = AddCommentForm(request.POST)
|
||||
if form.is_valid():
|
||||
comment = form.cleaned_data['comment']
|
||||
event = GroupEvent.objects.create(group=group,desc=comment,type="added_comment",by=request.user.person)
|
||||
email_comment(request,event)
|
||||
return redirect('ietf.group.views.history', acronym=group.acronym)
|
||||
else:
|
||||
form = AddCommentForm()
|
||||
|
||||
return render(request, 'group/add_comment.html', { 'group':group, 'form':form, })
|
||||
|
|
|
@ -144,6 +144,26 @@ def is_authorized_in_doc_stream(user, doc):
|
|||
|
||||
return Role.objects.filter(Q(name__in=("chair", "secr", "delegate", "auth"), person__user=user) & group_req).exists()
|
||||
|
||||
def is_authorized_in_group(user, group):
|
||||
"""Return whether user is authorized to perform duties on
|
||||
a given group."""
|
||||
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
|
||||
if has_role(user, ["Secretariat",]):
|
||||
return True
|
||||
|
||||
if group.parent:
|
||||
if group.parent.type_id == 'area' and has_role(user, ['Area Director',]):
|
||||
return True
|
||||
if group.parent.acronym == 'irtf' and has_role(user, ['IRTF Chair',]):
|
||||
return True
|
||||
if group.parent.acronym == 'iab' and has_role(user, ['IAB','IAB Executive Director',]):
|
||||
return True
|
||||
|
||||
return Role.objects.filter(name__in=("chair", "secr", "delegate", "auth"), person__user=user,group=group ).exists()
|
||||
|
||||
def is_individual_draft_author(user, doc):
|
||||
|
||||
if not user.is_authenticated:
|
||||
|
|
33
ietf/mailtrigger/migrations/0011_group_added_comment.py
Normal file
33
ietf/mailtrigger/migrations/0011_group_added_comment.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.8 on 2017-12-28 11:11
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
MailTrigger = apps.get_model('mailtrigger','MailTrigger')
|
||||
Recipient = apps.get_model('mailtrigger', 'Recipient')
|
||||
group_added_comment = MailTrigger.objects.create(
|
||||
slug='group_added_comment',
|
||||
desc="Recipients when a comment is added to a group's history",
|
||||
)
|
||||
group_added_comment.to = Recipient.objects.filter(slug__in=[
|
||||
'group_chairs',
|
||||
'group_secretaries',
|
||||
'group_responsible_directors',
|
||||
])
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
MailTrigger = apps.get_model('mailtrigger','MailTrigger')
|
||||
MailTrigger.objects.filter(slug='group_added_comment').delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailtrigger', '0010_auto_20161207_1104'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse)
|
||||
]
|
File diff suppressed because it is too large
Load diff
24
ietf/templates/group/add_comment.html
Normal file
24
ietf/templates/group/add_comment.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Add comment for {{ group }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Add comment<br><small>{{ group }} ({{ group.acronym }})</small></h1>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
<p class="help-block">The comment will be added to the history trail for the group.</p>
|
||||
|
||||
{% buttons %}
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<a class="btn btn-default pull-right" href="{% url "ietf.group.views.history" acronym=group.acronym %}">Back</a>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
10
ietf/templates/group/comment_added_email.txt
Normal file
10
ietf/templates/group/comment_added_email.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% autoescape off %}
|
||||
Please DO NOT reply to this email.
|
||||
|
||||
{{event.by}} added the following comment to the history of {{event.group.acronym}}:
|
||||
|
||||
{{ event.desc }}
|
||||
|
||||
Information for the group can be found at {{ group_url }}.
|
||||
|
||||
{% endautoescape%}
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
{% block group_content %}
|
||||
{% origin %}
|
||||
<h2>Group History</h2>
|
||||
{% if can_add_comment %}
|
||||
<a class="btn btn-default" href="{% url 'ietf.group.views.add_comment' acronym=group.acronym %}"><span class="fa fa-plus"></span> Add comment</a>
|
||||
{% endif %}
|
||||
<table class="table table-condensed table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -35,4 +39,4 @@
|
|||
|
||||
{% block js %}
|
||||
<script src="{% static "jquery.tablesorter/js/jquery.tablesorter.combined.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue