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 %}
-

IETF {{ meeting_num }} Proceedings

+

IETF {{ meeting.number }} {% if not meeting.proceedings_final %}Draft{% endif %} Proceedings + {% if user|has_role:"Secretariat" and not meeting.proceedings_final %} + Finalize Proceedings + {% endif %} +

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 %}