diff --git a/ietf/meeting/migrations/0031_add_proceedings_final.py b/ietf/meeting/migrations/0031_add_proceedings_final.py
new file mode 100644
index 000000000..8cfdaec82
--- /dev/null
+++ b/ietf/meeting/migrations/0031_add_proceedings_final.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+def reverse(apps, schema_editor):
+ pass
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('meeting', '0030_add_material_day_offsets'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='meeting',
+ name='proceedings_final',
+ field=models.BooleanField(default=False, help_text='Are the proceedings for this meeting complete?'),
+ preserve_default=True,
+ ),
+ ]
diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py
index 9a3445d5a..57d5eb470 100644
--- a/ietf/meeting/models.py
+++ b/ietf/meeting/models.py
@@ -88,6 +88,7 @@ class Meeting(models.Model):
agenda_note = models.TextField(blank=True, help_text="Text in this field will be placed at the top of the html agenda page for the meeting. HTML can be used, but will not be validated.")
agenda = models.ForeignKey('Schedule',null=True,blank=True, related_name='+')
session_request_lock_message = models.CharField(blank=True,max_length=255) # locked if not empty
+ proceedings_final = models.BooleanField(default=False, help_text=u"Are the proceedings for this meeting complete?")
def __unicode__(self):
if self.type_id == "ietf":
diff --git a/ietf/meeting/resources.py b/ietf/meeting/resources.py
index ccb21d8f8..ef4f59edf 100644
--- a/ietf/meeting/resources.py
+++ b/ietf/meeting/resources.py
@@ -32,6 +32,9 @@ class MeetingResource(ModelResource):
"idsubmit_cutoff_day_offset_01": ALL,
"idsubmit_cutoff_time_utc": ALL,
"idsubmit_cutoff_warning_days": ALL,
+ "submission_start_day_offset": ALL,
+ "submmission_cutoff_day_offset": ALL,
+ "submission_correction_day_offset": ALL,
"venue_name": ALL,
"venue_addr": ALL,
"break_area": ALL,
@@ -40,6 +43,7 @@ class MeetingResource(ModelResource):
"session_request_lock_message": ALL,
"type": ALL_WITH_RELATIONS,
"agenda": ALL_WITH_RELATIONS,
+ "proceedings_final": ALL,
}
api.meeting.register(MeetingResource())
diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py
index 9ac736406..a6ba80e1b 100644
--- a/ietf/meeting/tests_views.py
+++ b/ietf/meeting/tests_views.py
@@ -1146,3 +1146,22 @@ class FloorPlanTests(TestCase):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
+class FinalizeProceedingsTests(TestCase):
+ def test_finalize_proceedings(self):
+ make_meeting_test_data()
+ meeting = Meeting.objects.filter(type_id='ietf').order_by('id').last()
+ meeting.session_set.filter(group__acronym='mars').first().sessionpresentation_set.create(document=Document.objects.filter(type='draft').first(),rev=None)
+
+ url = urlreverse('ietf.meeting.views.finalize_proceedings',kwargs={'num':meeting.number})
+ login_testing_unauthorized(self,"secretary",url)
+ r = self.client.get(url)
+ self.assertEqual(r.status_code, 200)
+
+ self.assertEqual(meeting.proceedings_final,False)
+ self.assertEqual(meeting.session_set.filter(group__acronym="mars").first().sessionpresentation_set.filter(document__type="draft").first().rev,None)
+ r = self.client.post(url,{'finalize':1})
+ self.assertEqual(r.status_code, 302)
+ meeting = Meeting.objects.get(pk=meeting.pk)
+ self.assertEqual(meeting.proceedings_final,True)
+ self.assertEqual(meeting.session_set.filter(group__acronym="mars").first().sessionpresentation_set.filter(document__type="draft").first().rev,'00')
+
diff --git a/ietf/meeting/urls.py b/ietf/meeting/urls.py
index 5cee0de7b..3e4a185db 100644
--- a/ietf/meeting/urls.py
+++ b/ietf/meeting/urls.py
@@ -67,6 +67,7 @@ type_ietf_only_patterns_id_optional = [
url(r'^room-view(?:.html)?/?$', views.room_view),
url(r'^materials(?:.html)?/?$', views.materials),
url(r'^proceedings(?:.html)?/?$', views.proceedings),
+ url(r'^proceedings(?:.html)?/finalize/?$', views.finalize_proceedings),
]
urlpatterns = [
diff --git a/ietf/meeting/utils.py b/ietf/meeting/utils.py
index 4a48ca746..8a5a08ed2 100644
--- a/ietf/meeting/utils.py
+++ b/ietf/meeting/utils.py
@@ -71,3 +71,19 @@ def sort_sessions(sessions):
meeting_sorted = sorted(acronym_sorted,key=lambda x: x.meeting.number)
return meeting_sorted
+
+def finalize(meeting):
+ end_date = meeting.end_date()
+ end_time = datetime.datetime.combine(end_date, datetime.datetime.min.time())+datetime.timedelta(days=1)
+ for session in meeting.session_set.all():
+ for sp in session.sessionpresentation_set.filter(document__type='draft',rev=None):
+ rev_before_end = [e for e in sp.document.docevent_set.filter(newrevisiondocevent__isnull=False).order_by('-time') if e.time <= end_time ]
+ if rev_before_end:
+ sp.rev = rev_before_end[-1].newrevisiondocevent.rev
+ else:
+ sp.rev = '00'
+ sp.save()
+ meeting.proceedings_final = True
+ meeting.save()
+ return
+
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index cd7cdfba1..df2aa888b 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -48,6 +48,7 @@ from ietf.meeting.helpers import sessions_post_save, is_meeting_approved
from ietf.meeting.helpers import send_interim_cancellation_notice
from ietf.meeting.helpers import send_interim_approval_request
from ietf.meeting.helpers import send_interim_announcement_request
+from ietf.meeting.utils import finalize
from ietf.utils.mail import send_mail_message
from ietf.utils.pipe import pipe
from ietf.utils.pdf import pdf_pages
@@ -1465,10 +1466,26 @@ def proceedings(request, num=None):
cache_version = Document.objects.filter(session__meeting__number=meeting.number).aggregate(Max('time'))["time__max"]
return render(request, "meeting/proceedings.html", {
- 'meeting_num': meeting.number,
+ 'meeting': meeting,
'plenaries': plenaries, 'ietf': ietf, 'training': training, 'irtf': irtf, 'iab': iab,
'cut_off_date': cut_off_date,
'cor_cut_off_date': cor_cut_off_date,
'submission_started': now > begin_date,
'cache_version': cache_version,
})
+
+
+@role_required('Secretariat')
+def finalize_proceedings(request, num=None):
+
+ meeting = get_meeting(num)
+
+ if meeting.number <= 64 or not meeting.agenda.assignments.exists() or meeting.proceedings_final:
+ raise Http404
+
+ if request.method=='POST':
+ finalize(meeting)
+ return HttpResponseRedirect(reverse('ietf.meeting.views.proceedings',kwargs={'num':meeting.number}))
+
+ return render(request, "meeting/finalize.html", {'meeting':meeting,})
+
diff --git a/ietf/templates/meeting/group_proceedings.html b/ietf/templates/meeting/group_proceedings.html
index 386a2be1d..4c94c4528 100644
--- a/ietf/templates/meeting/group_proceedings.html
+++ b/ietf/templates/meeting/group_proceedings.html
@@ -25,14 +25,14 @@
{% if session.agenda %}
Agenda
{% else %}
- {% if show_agenda == "True" %}
+ {% if show_agenda == "True" and not meeting.proceedings_final %}
No agenda
{% endif %}
{% endif %}
{% if session.minutes %}
Minutes
{% else %}
- {% if show_agenda == "True" %}
+ {% if show_agenda == "True" and not meeting.proceedings_final %}
No minutes
{% endif %}
{% endif %}
@@ -64,7 +64,9 @@
{{ slide.title|clean_whitespace }}
{% empty %}
- No slides
+ {% if not meeting.proceedings_final %}
+ No slides
+ {% endif %}
{% endfor %}
{% endwith %}
@@ -73,7 +75,9 @@
{% for draft in drafts %}
{{ draft.canonical_name }}
{% empty %}
- No drafts
+ {% if not meeting.proceedings_final %}
+ No drafts
+ {% endif %}
{% endfor %}
{% endwith %}
diff --git a/ietf/templates/meeting/proceedings.html b/ietf/templates/meeting/proceedings.html
index 3676741f5..38e2aa7db 100644
--- a/ietf/templates/meeting/proceedings.html
+++ b/ietf/templates/meeting/proceedings.html
@@ -10,27 +10,31 @@
{% block bodyAttrs %}data-spy="scroll" data-target="#affix"{% endblock %}
-{% block title %}IETF {{ meeting_num }} Proceedings {% endblock %}
+{% block title %}IETF {{ meeting.number }} {% if not meeting.proceedings_final %}Draft{% endif %} Proceedings {% endblock %}
{% block content %}
{% origin %}
This page is under construction
- {% if meeting_num|add:0 <= 96 %} + {% if meeting.number|add:0 <= 96 %}- These are not the official proceedings for IETF{{meeting_num}}. This page shows what would be generated by the new automatic proceedings generator for that meeting. The official proceedings are located at https://www.ietf.org/proceedings/{{meeting_num}} + These are not the official proceedings for IETF{{meeting.number}}. This page shows what would be generated by the new automatic proceedings generator for that meeting. The official proceedings are located at https://www.ietf.org/proceedings/{{meeting.number}}
{% endif %} {# cache for 15 minutes, as long as there's no proceedings activity. takes 4-8 seconds to generate. #} {% load cache %} - {% cache 900 ietf_meeting_materials meeting_num cache_version %} + {% cache 900 ietf_meeting_materials meeting.number cache_version %} {% with "True" as show_agenda %}