Added a view that generates the "send minutes" email for the secretariat. Fixes #2493. Commit ready for merge.

- Legacy-Id: 15125
This commit is contained in:
Robert Sparks 2018-05-04 21:44:46 +00:00
parent 4f99fef377
commit 345bff8850
7 changed files with 130 additions and 10 deletions

View file

@ -18,7 +18,7 @@ from ietf.meeting.helpers import get_next_interim_number, make_materials_directo
from ietf.meeting.helpers import is_meeting_approved, get_next_agenda_name
from ietf.message.models import Message
from ietf.person.models import Person
from ietf.utils.fields import DatepickerDateField, DurationField
from ietf.utils.fields import DatepickerDateField, DurationField, MultiEmailField
from ietf.utils.validators import ( validate_file_size, validate_mime_type,
validate_file_extension, validate_no_html_frame)
@ -345,4 +345,8 @@ class FileUploadForm(forms.Form):
validate_no_html_frame(file)
return file
class RequestMinutesForm(forms.Form):
to = MultiEmailField()
cc = MultiEmailField(required=False)
subject = forms.CharField()
body = forms.CharField(widget=forms.Textarea,strip=False)

View file

@ -24,12 +24,12 @@ from ietf.meeting.helpers import can_approve_interim_request, can_view_interim_r
from ietf.meeting.helpers import send_interim_approval_request
from ietf.meeting.helpers import send_interim_cancellation_notice
from ietf.meeting.helpers import send_interim_minutes_reminder, populate_important_dates
from ietf.meeting.models import Session, TimeSlot, Meeting, SchedTimeSessAssignment, Schedule
from ietf.meeting.models import Session, TimeSlot, Meeting, SchedTimeSessAssignment, Schedule, SessionPresentation
from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting
from ietf.meeting.utils import finalize
from ietf.name.models import SessionStatusName
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
from ietf.utils.mail import outbox
from ietf.utils.mail import outbox, empty_outbox
from ietf.utils.text import xslugify
from ietf.person.factories import PersonFactory
@ -1997,3 +1997,24 @@ class SessionTests(TestCase):
self.assertEqual(r.status_code,200)
self.assertTrue(requested_session.group.acronym in unicontent(r))
self.assertTrue(not_meeting.group.acronym in unicontent(r))
def test_request_minutes(self):
meeting = MeetingFactory(type_id='ietf')
area = GroupFactory(type_id='area')
has_minutes = SessionFactory(meeting=meeting,group__parent=area)
has_no_minutes = SessionFactory(meeting=meeting,group__parent=area)
SessionPresentation.objects.create(session=has_minutes,document=DocumentFactory(type_id='minutes'))
empty_outbox()
url = urlreverse('ietf.meeting.views.request_minutes',kwargs={'num':meeting.number})
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertNotIn(has_minutes.group.acronym, unicontent(r).lower())
self.assertIn(has_no_minutes.group.acronym, unicontent(r).lower())
r = self.client.post(url,{'to':'wgchairs@ietf.org',
'cc': 'irsg@irtf.org',
'subject': 'I changed the subject',
'body': 'corpus',
})
self.assertEqual(r.status_code,302)
self.assertEqual(len(outbox),1)

View file

@ -83,6 +83,7 @@ type_ietf_only_patterns_id_optional = [
url(r'^week-view(?:.html)?/?$', views.week_view),
url(r'^room-view(?:.html)?/?$', views.room_view),
url(r'^materials(?:.html)?/?$', views.materials),
url(r'^request_minutes/?$', views.request_minutes),
url(r'^materials/%(document)s((?P<ext>\.[a-z0-9]+)|/)?$' % settings.URL_REGEXPS, views.materials_document),
url(r'^session/?$', views.materials_editable_groups),
url(r'^proceedings(?:.html)?/?$', views.proceedings),

View file

@ -63,14 +63,14 @@ from ietf.secr.proceedings.utils import handle_upload_file
from ietf.secr.proceedings.proc_utils import (get_progress_stats, post_process, import_audio_files,
import_youtube_video_urls, create_recording)
from ietf.utils.decorators import require_api_key
from ietf.utils.mail import send_mail_message
from ietf.utils.mail import send_mail_message, send_mail_text
from ietf.utils.pipe import pipe
from ietf.utils.pdf import pdf_pages
from ietf.utils.text import xslugify
from ietf.utils.validators import get_mime_type
from .forms import (InterimMeetingModelForm, InterimAnnounceForm, InterimSessionModelForm,
InterimCancelForm, InterimSessionInlineFormSet, FileUploadForm)
InterimCancelForm, InterimSessionInlineFormSet, FileUploadForm, RequestMinutesForm,)
def get_menu_entries(request):
@ -139,7 +139,7 @@ def materials(request, num=None):
if date_list: setattr(event, 'last_update', sorted(date_list, reverse=True)[0])
return render(request, "meeting/materials.html", {
'meeting_num': meeting.number,
'meeting': meeting,
'plenaries': plenaries,
'ietf': ietf,
'training': training,
@ -2284,3 +2284,39 @@ def edit_timeslot_type(request, num, slot_id):
return render(request, 'meeting/edit_timeslot_type.html', {'timeslot':timeslot,'form':form,'sessions':sessions})
@role_required('Secretariat')
def request_minutes(request, num=None):
meeting = get_ietf_meeting(num)
if request.method=='POST':
form = RequestMinutesForm(data=request.POST)
if form.is_valid():
send_mail_text(request,
to=form.cleaned_data.get('to'),
frm=request.user.person.email_address(),
subject=form.cleaned_data.get('subject'),
txt=form.cleaned_data.get('body'),
cc=form.cleaned_data.get('cc'),
)
return HttpResponseRedirect(reverse('ietf.meeting.views.materials',kwargs={'num':num}))
else:
needs_minutes = set()
for a in meeting.agenda.assignments.filter(session__group__type_id__in=('wg','rg')):
if not a.session.all_meeting_minutes():
group = a.session.group
if group.parent and group.parent.type_id in ('area','irtf'):
needs_minutes.add(a.session.group)
needs_minutes = list(needs_minutes)
needs_minutes.sort(key=lambda g: ('zzz' if g.parent.acronym == 'irtf' else g.parent.acronym)+":"+g.acronym)
body_context = {'meeting':meeting,
'needs_minutes':needs_minutes,
'settings':settings,
}
body = render_to_string('meeting/request_minutes.txt', body_context)
initial = {'to': 'wgchairs@ietf.org',
'cc': 'irsg@irtf.org',
'subject': 'Request for IETF WG and Bof Session Minutes',
'body': body,
}
form = RequestMinutesForm(initial=initial)
context = {'meeting':meeting, 'form': form}
return render(request, 'meeting/request_minutes.html', context)

View file

@ -10,14 +10,14 @@
{% block bodyAttrs %}data-spy="scroll" data-target="#affix"{% endblock %}
{% block title %}IETF {{ meeting_num }} preliminary &amp; interim materials{% endblock %}
{% block title %}IETF {{ meeting.number }} preliminary &amp; interim materials{% endblock %}
{% block content %}
{% origin %}
<div class="row">
<div class="col-md-10">
<h1>IETF {{ meeting_num }} meeting materials</h1>
<h1>IETF {{ meeting.number }} meeting materials</h1>
{% if submission_started %}
<p class="alert alert-info">
@ -29,8 +29,11 @@
<p>
{% if user|has_role:"Secretariat" %}
<a class="btn btn-default" href="{% url 'ietf.secr.proceedings.views.main' %}">Secretariat proceedings functions</a>
{% if meeting.end_date.today > meeting.end_date %}
<a class="btn btn-default" href="{% url 'ietf.meeting.views.request_minutes' num=meeting.number %}">Send request for minutes</a>
{% endif %}
{% endif %}
<a class="btn btn-default" href="/meeting/{{meeting_num}}/requests">Meeting requests/conflicts</a>
<a class="btn btn-default" href="/meeting/{{meeting.number}}/requests">Meeting requests/conflicts</a>
</p>
{% with "True" as show_agenda %}

View file

@ -0,0 +1,34 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2018, All Rights Reserved #}
{% load origin %}
{% load ietf_filters staticfiles bootstrap3 %}
{% block morecss %}
#id_body {height:700px;}
{% endblock %}
{% block title %}IETF {{ meeting.number }}: Request Minutes{% endblock %}
{% block content %}
{% origin %}
<div class="row">
<div class="col-md-10">
<h1 class="title">IETF {{ meeting.number }}: Request Minutes <br>
<small>{{meeting.city}}, {{meeting.country}} -- {{meeting.venue_name}}</small>
</h1>
</div>
</div>
<div class="row">
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-danger">Send</button>
{% endbuttons %}
</form>
</div>
{% endblock %}

View file

@ -0,0 +1,21 @@
{% autoescape off %} Dear WG Chairs and BOF Chairs,
The secretariat is in the process of compiling the proceedings for {{meeting }}
and we are still missing meeting minutes from various sessions.
The cutoff for submissions is {{ meeting.get_submission_cut_off_date }}, and the correction submissions
cutoff is {{ meeting.get_submission_correction_date }}.
Please upload meeting minutes, as well as any presentations from your
sessions, at your earliest convenience using the Meeting Materials Manager
found here: {{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.meeting.views.materials' num=meeting.number %}
Alternatively, you are welcome to send them to iesg-secretary@ietf.org for
manual posting.
Groups that are missing minutes:{% for group in needs_minutes %}{% ifchanged group.parent %}
{{group.parent.name}}:{% endifchanged %}
{{ group.acronym | upper }}{% if group.state_id == 'bof' %} (BoF){% endif %}{% endfor %}
{% endautoescape %}