Skip to content

Commit

Permalink
Moved the materials start, cutoff, and revision dates into the Meetin…
Browse files Browse the repository at this point in the history
…g object

Add a bit to meeting to note whether proceedings are final. 
Update proceedings view to reflect the status of that bit. 
Add a function that finalizes a meetings proceedings.
Straighten out a migration numbering collision introduced in an earlier merge.
Commit ready for merge.
 - Legacy-Id: 11764
  • Loading branch information
rjsparks committed Aug 8, 2016
2 parents f617e26 + 162845d commit 57afa06
Show file tree
Hide file tree
Showing 16 changed files with 187 additions and 21 deletions.
2 changes: 1 addition & 1 deletion ietf/doc/tests.py
Expand Up @@ -928,7 +928,7 @@ def setUp(self):
self.other_group.role_set.create(name_id='chair',person=self.other_chair,email=self.other_chair.email())

today = datetime.date.today()
cut_days = settings.MEETING_MATERIALS_SUBMISSION_CORRECTION_DAYS
cut_days = settings.MEETING_MATERIALS_DEFAULT_SUBMISSION_CORRECTION_DAYS
self.past_cutoff = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=1+cut_days))
self.past = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=cut_days/2))
self.inprog = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=1))
Expand Down
32 changes: 32 additions & 0 deletions ietf/meeting/migrations/0030_add_material_day_offsets.py
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('meeting', '0029_add_time_to_room_and_floorplan'),
]

operations = [
migrations.AddField(
model_name='meeting',
name='submission_correction_day_offset',
field=models.IntegerField(default=50, help_text=b'The number of days after the meeting start date in which updates to existing meeting materials will be accepted.', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='meeting',
name='submission_cutoff_day_offset',
field=models.IntegerField(default=26, help_text=b'The number of days after the meeting start date in which new meeting materials will be accepted.', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='meeting',
name='submission_start_day_offset',
field=models.IntegerField(default=90, help_text=b'The number of days before the meeting start date after which meeting materials will be accepted.', blank=True),
preserve_default=True,
),
]
23 changes: 23 additions & 0 deletions 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,
),
]
Expand Up @@ -59,7 +59,7 @@ def reverse(apps, schema_editor):
class Migration(migrations.Migration):

dependencies = [
('meeting', '0028_add_audio_stream_data'),
('meeting', '0031_add_proceedings_final'),
('doc', '0012_auto_20160207_0537'),
('group','0008_auto_20160505_0523'),
]
Expand Down
17 changes: 13 additions & 4 deletions ietf/meeting/models.py
Expand Up @@ -72,14 +72,23 @@ class Meeting(models.Model):
idsubmit_cutoff_warning_days = timedelta.fields.TimedeltaField(blank=True,
default=settings.IDSUBMIT_DEFAULT_CUTOFF_WARNING_DAYS,
help_text = "How long before the 00 cutoff to start showing cutoff warnings. Use for example 21 days or 3 weeks.")
#
submission_start_day_offset = models.IntegerField(blank=True,
default=settings.MEETING_MATERIALS_DEFAULT_SUBMISSION_START_DAYS,
help_text = "The number of days before the meeting start date after which meeting materials will be accepted.")
submission_cutoff_day_offset = models.IntegerField(blank=True,
default=settings.MEETING_MATERIALS_DEFAULT_SUBMISSION_CUTOFF_DAYS,
help_text = "The number of days after the meeting start date in which new meeting materials will be accepted.")
submission_correction_day_offset = models.IntegerField(blank=True,
default=settings.MEETING_MATERIALS_DEFAULT_SUBMISSION_CORRECTION_DAYS,
help_text = "The number of days after the meeting start date in which updates to existing meeting materials will be accepted.")
venue_name = models.CharField(blank=True, max_length=255)
venue_addr = models.TextField(blank=True)
break_area = models.CharField(blank=True, max_length=255)
reg_area = models.CharField(blank=True, max_length=255)
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":
Expand Down Expand Up @@ -149,11 +158,11 @@ def get_materials_path(self):

# the various dates are currently computed
def get_submission_start_date(self):
return self.date + datetime.timedelta(days=settings.MEETING_MATERIALS_SUBMISSION_START_DAYS)
return self.date - datetime.timedelta(days=self.submission_start_day_offset)
def get_submission_cut_off_date(self):
return self.date + datetime.timedelta(days=settings.MEETING_MATERIALS_SUBMISSION_CUTOFF_DAYS)
return self.date + datetime.timedelta(days=self.submission_cutoff_day_offset)
def get_submission_correction_date(self):
return self.date + datetime.timedelta(days=settings.MEETING_MATERIALS_SUBMISSION_CORRECTION_DAYS)
return self.date + datetime.timedelta(days=self.submission_correction_day_offset)

def get_schedule_by_name(self, name):
return self.schedule_set.filter(name=name).first()
Expand Down
4 changes: 4 additions & 0 deletions ietf/meeting/resources.py
Expand Up @@ -32,6 +32,9 @@ class Meta:
"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,
Expand All @@ -40,6 +43,7 @@ class Meta:
"session_request_lock_message": ALL,
"type": ALL_WITH_RELATIONS,
"agenda": ALL_WITH_RELATIONS,
"proceedings_final": ALL,
}
api.meeting.register(MeetingResource())

Expand Down
22 changes: 21 additions & 1 deletion ietf/meeting/tests_views.py
Expand Up @@ -1146,7 +1146,7 @@ def test_floor_plan_page(self):
url = urlreverse('ietf.meeting.views.floor_plan', kwargs={'floor': xslugify(floorplan.name)} )
r = self.client.get(url)
self.assertEqual(r.status_code, 200)

class IphoneAppJsonTests(TestCase):
def setUp(self):
pass
Expand All @@ -1168,3 +1168,23 @@ def test_iphone_app_json(self):
url = urlreverse('ietf.meeting.views.json_agenda',kwargs={'num':meeting.number})
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')

1 change: 1 addition & 0 deletions ietf/meeting/urls.py
Expand Up @@ -68,6 +68,7 @@
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 = [
Expand Down
16 changes: 16 additions & 0 deletions ietf/meeting/utils.py
Expand Up @@ -71,3 +71,19 @@ def time_sort_key(session):
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

19 changes: 18 additions & 1 deletion ietf/meeting/views.py
Expand Up @@ -50,6 +50,7 @@
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
Expand Down Expand Up @@ -1546,10 +1547,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,})

6 changes: 6 additions & 0 deletions ietf/secr/meetings/tests.py
Expand Up @@ -77,6 +77,9 @@ def test_add_meeting(self):
idsubmit_cutoff_day_offset_01=20,
idsubmit_cutoff_time_utc =datetime.timedelta(hours=23, minutes=59, seconds=59),
idsubmit_cutoff_warning_days =datetime.timedelta(days=21),
submission_start_day_offset=90,
submission_cutoff_day_offset=26,
submission_correction_day_offset=50,
)
self.client.login(username='secretary', password='secretary+password')
response = self.client.post(url, post_data, follow=True)
Expand All @@ -95,6 +98,9 @@ def test_edit_meeting(self):
idsubmit_cutoff_day_offset_01=20,
idsubmit_cutoff_time_utc =datetime.timedelta(hours=23, minutes=59, seconds=59),
idsubmit_cutoff_warning_days =datetime.timedelta(days=21),
submission_start_day_offset=90,
submission_cutoff_day_offset=26,
submission_correction_day_offset=50,
)
self.client.login(username="secretary", password="secretary+password")
response = self.client.post(url, post_data,follow=True)
Expand Down
3 changes: 2 additions & 1 deletion ietf/secr/proceedings/views.py
Expand Up @@ -394,7 +394,8 @@ def main(request):
meetings = Meeting.objects.filter(type='ietf').order_by('-number')
else:
# select meetings still within the cutoff period
meetings = Meeting.objects.filter(type='ietf',date__gt=datetime.datetime.today() - datetime.timedelta(days=settings.MEETING_MATERIALS_SUBMISSION_CORRECTION_DAYS)).order_by('number')
today = datetime.datetime.today()
meetings = [m for m in Meeting.objects.filter(type='ietf').order_by('-number') if m.get_submission_correction_date()>=today]

groups = get_my_groups(request.user)
interim_meetings = Meeting.objects.filter(type='interim',session__group__in=groups,session__status='sched').order_by('-date')
Expand Down
6 changes: 3 additions & 3 deletions ietf/settings.py
Expand Up @@ -558,9 +558,9 @@ def skip_unreadable_post(record):

# === Meeting Related Settings =================================================

MEETING_MATERIALS_SUBMISSION_START_DAYS = -90
MEETING_MATERIALS_SUBMISSION_CUTOFF_DAYS = 26
MEETING_MATERIALS_SUBMISSION_CORRECTION_DAYS = 50
MEETING_MATERIALS_DEFAULT_SUBMISSION_START_DAYS = 90
MEETING_MATERIALS_DEFAULT_SUBMISSION_CUTOFF_DAYS = 26
MEETING_MATERIALS_DEFAULT_SUBMISSION_CORRECTION_DAYS = 50

INTERNET_DRAFT_DAYS_TO_EXPIRE = 185

Expand Down
29 changes: 29 additions & 0 deletions ietf/templates/meeting/finalize.html
@@ -0,0 +1,29 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% load bootstrap3 %}

{% block title %}Finalize IETF{{meeting.number}} Proceedings{% endblock %}

{% block content %}
{% origin %}
<div class="panel panel-default col-md-5">
<div class="panel-heading">
Finalize IETF{{meeting.number}} Proceedings
</div>
<div class="panel-body">
<p>This will make the proceedings for IETF{{meeting.number}} final.</p>
<p>All drafts associated with sessions that are marked "current version" will have their version set to whatever the version was at the end of the meeting.</p>
{% comment %} This would be a good place to put any warnings about important things missing from the proceedings {% endcomment %}
<div class="pull-right">
<form method="post">
{% csrf_token %}
{% buttons %}
<button type="submit" class="btn btn-primary " name="finalize" value="Finalize">Finalize</button>
<a class="btn btn-default " href="{% url 'ietf.meeting.views.proceedings' num=meeting.number %}">Cancel</a>
{% endbuttons %}
</form>
</div>
</div
</div>
{% endblock %}
12 changes: 8 additions & 4 deletions ietf/templates/meeting/group_proceedings.html
Expand Up @@ -25,14 +25,14 @@
{% if session.agenda %}
<a href="https://www.ietf.org/proceedings/{{meeting_num}}/agenda/{{ session.agenda }}">Agenda</a><br>
{% else %}
{% if show_agenda == "True" %}
{% if show_agenda == "True" and not meeting.proceedings_final %}
<span class="label label-warning">No agenda</span><br>
{% endif %}
{% endif %}
{% if session.minutes %}
<a href="https://www.ietf.org/proceedings/{{ meeting_num }}/minutes/{{ session.minutes }}">Minutes</a><br>
{% else %}
{% if show_agenda == "True" %}
{% if show_agenda == "True" and not meeting.proceedings_final %}
<span class="label label-warning">No minutes</span><br>
{% endif %}
{% endif %}
Expand Down Expand Up @@ -64,7 +64,9 @@
<a href="https://www.ietf.org/proceedings/{{meeting_num}}/slides/{{ slide.external_url }}">{{ slide.title|clean_whitespace }}</a>
<br>
{% empty %}
<span class="label label-warning">No slides</span>
{% if not meeting.proceedings_final %}
<span class="label label-warning">No slides</span>
{% endif %}
{% endfor %}
{% endwith %}
</td>
Expand All @@ -73,7 +75,9 @@
{% for draft in drafts %}
<a href="{% url "doc_view" name=draft.canonical_name %}">{{ draft.canonical_name }}</a><br>
{% empty %}
<span class="label label-warning">No drafts</span>
{% if not meeting.proceedings_final %}
<span class="label label-warning">No drafts</span>
{% endif %}
{% endfor %}
{% endwith %}
</td>
Expand Down
14 changes: 9 additions & 5 deletions ietf/templates/meeting/proceedings.html
Expand Up @@ -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 %}
<div class="row">
<div class="col-md-10">

<h1>IETF {{ meeting_num }} Proceedings</h1>
<h1>IETF {{ meeting.number }} {% if not meeting.proceedings_final %}Draft{% endif %} Proceedings
{% if user|has_role:"Secretariat" and not meeting.proceedings_final %}
<a class="btn btn-default" href="{% url 'ietf.meeting.views.finalize_proceedings' num=meeting.number %}">Finalize Proceedings</a>
{% endif %}
</h1>

<p class="alert alert-info">
<b>This page is under construction</b>
</p>
{% if meeting_num|add:0 <= 96 %}
{% if meeting.number|add:0 <= 96 %}
<p class="alert alert-info">
<b>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 <a href="https://www.ietf.org/proceedings/{{meeting_num}}">https://www.ietf.org/proceedings/{{meeting_num}}</a></b>
<b>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 <a href="https://www.ietf.org/proceedings/{{meeting.number}}">https://www.ietf.org/proceedings/{{meeting.number}}</a></b>
</p>
{% 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 %}
<!-- Plenaries -->
Expand Down

0 comments on commit 57afa06

Please sign in to comment.