Merged in [15125] from rjsparks@nostrum.com:
Added a view that generates the \'send minutes\' email for the secretariat. Fixes #2493.
- Legacy-Id: 15134
Note: SVN reference [15125] has been migrated to Git commit 345bff8850
This commit is contained in:
commit
aeaf67af43
|
@ -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.meeting.helpers import is_meeting_approved, get_next_agenda_name
|
||||||
from ietf.message.models import Message
|
from ietf.message.models import Message
|
||||||
from ietf.person.models import Person
|
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,
|
from ietf.utils.validators import ( validate_file_size, validate_mime_type,
|
||||||
validate_file_extension, validate_no_html_frame)
|
validate_file_extension, validate_no_html_frame)
|
||||||
|
|
||||||
|
@ -345,4 +345,8 @@ class FileUploadForm(forms.Form):
|
||||||
validate_no_html_frame(file)
|
validate_no_html_frame(file)
|
||||||
return file
|
return file
|
||||||
|
|
||||||
|
class RequestMinutesForm(forms.Form):
|
||||||
|
to = MultiEmailField()
|
||||||
|
cc = MultiEmailField(required=False)
|
||||||
|
subject = forms.CharField()
|
||||||
|
body = forms.CharField(widget=forms.Textarea,strip=False)
|
||||||
|
|
|
@ -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_approval_request
|
||||||
from ietf.meeting.helpers import send_interim_cancellation_notice
|
from ietf.meeting.helpers import send_interim_cancellation_notice
|
||||||
from ietf.meeting.helpers import send_interim_minutes_reminder, populate_important_dates
|
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.test_data import make_meeting_test_data, make_interim_meeting
|
||||||
from ietf.meeting.utils import finalize
|
from ietf.meeting.utils import finalize
|
||||||
from ietf.name.models import SessionStatusName
|
from ietf.name.models import SessionStatusName
|
||||||
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
|
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.utils.text import xslugify
|
||||||
|
|
||||||
from ietf.person.factories import PersonFactory
|
from ietf.person.factories import PersonFactory
|
||||||
|
@ -1997,3 +1997,24 @@ class SessionTests(TestCase):
|
||||||
self.assertEqual(r.status_code,200)
|
self.assertEqual(r.status_code,200)
|
||||||
self.assertTrue(requested_session.group.acronym in unicontent(r))
|
self.assertTrue(requested_session.group.acronym in unicontent(r))
|
||||||
self.assertTrue(not_meeting.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)
|
||||||
|
|
|
@ -83,6 +83,7 @@ type_ietf_only_patterns_id_optional = [
|
||||||
url(r'^week-view(?:.html)?/?$', views.week_view),
|
url(r'^week-view(?:.html)?/?$', views.week_view),
|
||||||
url(r'^room-view(?:.html)?/?$', views.room_view),
|
url(r'^room-view(?:.html)?/?$', views.room_view),
|
||||||
url(r'^materials(?:.html)?/?$', views.materials),
|
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'^materials/%(document)s((?P<ext>\.[a-z0-9]+)|/)?$' % settings.URL_REGEXPS, views.materials_document),
|
||||||
url(r'^session/?$', views.materials_editable_groups),
|
url(r'^session/?$', views.materials_editable_groups),
|
||||||
url(r'^proceedings(?:.html)?/?$', views.proceedings),
|
url(r'^proceedings(?:.html)?/?$', views.proceedings),
|
||||||
|
|
|
@ -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,
|
from ietf.secr.proceedings.proc_utils import (get_progress_stats, post_process, import_audio_files,
|
||||||
import_youtube_video_urls, create_recording)
|
import_youtube_video_urls, create_recording)
|
||||||
from ietf.utils.decorators import require_api_key
|
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.pipe import pipe
|
||||||
from ietf.utils.pdf import pdf_pages
|
from ietf.utils.pdf import pdf_pages
|
||||||
from ietf.utils.text import xslugify
|
from ietf.utils.text import xslugify
|
||||||
from ietf.utils.validators import get_mime_type
|
from ietf.utils.validators import get_mime_type
|
||||||
|
|
||||||
from .forms import (InterimMeetingModelForm, InterimAnnounceForm, InterimSessionModelForm,
|
from .forms import (InterimMeetingModelForm, InterimAnnounceForm, InterimSessionModelForm,
|
||||||
InterimCancelForm, InterimSessionInlineFormSet, FileUploadForm)
|
InterimCancelForm, InterimSessionInlineFormSet, FileUploadForm, RequestMinutesForm,)
|
||||||
|
|
||||||
|
|
||||||
def get_menu_entries(request):
|
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])
|
if date_list: setattr(event, 'last_update', sorted(date_list, reverse=True)[0])
|
||||||
|
|
||||||
return render(request, "meeting/materials.html", {
|
return render(request, "meeting/materials.html", {
|
||||||
'meeting_num': meeting.number,
|
'meeting': meeting,
|
||||||
'plenaries': plenaries,
|
'plenaries': plenaries,
|
||||||
'ietf': ietf,
|
'ietf': ietf,
|
||||||
'training': training,
|
'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})
|
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)
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
|
|
||||||
{% block bodyAttrs %}data-spy="scroll" data-target="#affix"{% endblock %}
|
{% block bodyAttrs %}data-spy="scroll" data-target="#affix"{% endblock %}
|
||||||
|
|
||||||
{% block title %}IETF {{ meeting_num }} preliminary & interim materials{% endblock %}
|
{% block title %}IETF {{ meeting.number }} preliminary & interim materials{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% origin %}
|
{% origin %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
|
|
||||||
<h1>IETF {{ meeting_num }} meeting materials</h1>
|
<h1>IETF {{ meeting.number }} meeting materials</h1>
|
||||||
|
|
||||||
{% if submission_started %}
|
{% if submission_started %}
|
||||||
<p class="alert alert-info">
|
<p class="alert alert-info">
|
||||||
|
@ -29,8 +29,11 @@
|
||||||
<p>
|
<p>
|
||||||
{% if user|has_role:"Secretariat" %}
|
{% if user|has_role:"Secretariat" %}
|
||||||
<a class="btn btn-default" href="{% url 'ietf.secr.proceedings.views.main' %}">Secretariat proceedings functions</a>
|
<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 %}
|
{% 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>
|
</p>
|
||||||
|
|
||||||
{% with "True" as show_agenda %}
|
{% with "True" as show_agenda %}
|
||||||
|
|
34
ietf/templates/meeting/request_minutes.html
Normal file
34
ietf/templates/meeting/request_minutes.html
Normal 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 %}
|
||||||
|
|
21
ietf/templates/meeting/request_minutes.txt
Normal file
21
ietf/templates/meeting/request_minutes.txt
Normal 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 %}
|
Loading…
Reference in a new issue