Continued iterative-improvements to auto-generated proceedings:

- Migration to create documents and sessionpresentations for ietf95 and 96 bluesheets. Add bluesheets to proceedings.
- Refactor columns for proceedings to group agenda, minutes, and bluesheets into one column.
- Add a column for recordings. Show the recordings for all sessions for a group.
- Refactored all_meeting_ functions on session. Improved (with a hack) how recordings are displayed.
- Add guards against very old meetings. For more modern, past, meetings, add a warning that these are not the official proceedings and provide a link to the official proceedings.

Commit ready for merge.
 - Legacy-Id: 11758
This commit is contained in:
Robert Sparks 2016-08-04 21:20:06 +00:00
commit f2964b9733
6 changed files with 217 additions and 21 deletions

View file

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from django.db import migrations
from django.conf import settings
def official_time(session):
return session.timeslotassignments.filter(schedule=session.meeting.agenda).first()
def forward(apps, schema_editor):
Document = apps.get_model('doc','Document')
State = apps.get_model('doc','State')
Group = apps.get_model('group','Group')
Meeting = apps.get_model('meeting', 'Meeting')
active = State.objects.get(type_id='bluesheets',slug='active')
for num in [95, 96]:
mtg = Meeting.objects.get(number=num)
bs_path = '%s/bluesheets/'% os.path.join(settings.AGENDA_PATH,mtg.number)
bs_files = os.listdir(bs_path)
bs_acronyms = set([x[14:-7] for x in bs_files])
group_acronyms = set([x.group.acronym for x in mtg.session_set.all() if official_time(x) and x.group.type_id in ['wg','rg','ag'] and not x.agenda_note.lower().startswith('cancel')])
if bs_acronyms-group_acronyms:
print "Warning IETF%s : groups that have bluesheets but did not appear to meet: %s"%(num,list(bs_acronyms-group_acronyms))
if group_acronyms-bs_acronyms:
print "Warning IETF%s : groups that appeared to meet but have no bluesheets: %s"%(num,list(group_acronyms-bs_acronyms))
for acronym in group_acronyms & bs_acronyms:
group = Group.objects.get(acronym=acronym)
bs = sorted([x for x in bs_files if '-%s-'%acronym in x])
bs_count = len(bs)
sess = sorted([ x for x in mtg.session_set.filter(group__acronym=acronym) if not x.agenda_note.lower().startswith('cancel')],
key = lambda x: official_time(x).timeslot.time)
sess_count = len(sess)
if bs_count != sess_count:
print "Warning IETF%s: %s : different number of bluesheets (%d) than sessions (%d)"%(num,acronym,bs_count,sess_count)
numdocs = min(bs_count,sess_count)
for n in range(numdocs):
doc = Document.objects.create(
name=bs[n][:-4],
type_id='bluesheets',
title='Bluesheets IETF%d : %s : %s ' % (num,acronym,official_time(sess[n]).timeslot.time.strftime('%a %H:%M')),
group=group,
rev='00',
external_url=bs[n],
)
doc.states.add(active)
sess[n].sessionpresentation_set.create(document=doc,rev='00')
def reverse(apps, schema_editor):
Document = apps.get_model('doc','Document')
Document.objects.filter(type_id='bluesheets',sessionpresentation__session__meeting__number_in=[95,96]).exclude(group__acronym='openpgp').delete()
class Migration(migrations.Migration):
dependencies = [
('meeting', '0028_add_audio_stream_data'),
('doc', '0012_auto_20160207_0537'),
('group','0008_auto_20160505_0523'),
]
operations = [
migrations.RunPython(forward,reverse)
]

View file

@ -1010,6 +1010,9 @@ class Session(models.Model):
def recordings(self):
return list(self.get_material("recording", only_one=False))
def bluesheets(self):
return list(self.get_material("bluesheets", only_one=False))
def slides(self):
if not hasattr(self, "_slides_cache"):
self._slides_cache = list(self.get_material("slides", only_one=False))
@ -1018,9 +1021,28 @@ class Session(models.Model):
def drafts(self):
return list(self.materials.filter(type='draft'))
def all_meeting_sessions_for_group(self):
sessions = [s for s in self.meeting.session_set.filter(group=self.group,type=self.type) if s.official_timeslotassignment()]
return sorted(sessions, key = lambda x: x.official_timeslotassignment().timeslot.time)
def all_meeting_recordings(self):
recordings = []
sessions = self.all_meeting_sessions_for_group()
for session in sessions:
recordings.extend(session.recordings())
return recordings
def all_meeting_bluesheets(self):
bluesheets = []
sessions = self.all_meeting_sessions_for_group()
for session in sessions:
bluesheets.extend(session.bluesheets())
return bluesheets
def all_meeting_drafts(self):
drafts = []
for session in self.meeting.session_set.filter(group=self.group):
sessions = self.all_meeting_sessions_for_group()
for session in sessions:
drafts.extend(session.drafts())
return drafts

View file

@ -0,0 +1,14 @@
from django import template
register = template.Library()
@register.filter
def hack_recording_title(recording,add_timestamp=False):
if recording.title.startswith('Audio recording for') or recording.title.startswith('Video recording for'):
hacked_title = recording.title[:15]
if add_timestamp:
hacked_title += ' '+recording.sessionpresentation_set.first().session.official_timeslotassignment().timeslot.time.strftime("%a %H:%M")
return hacked_title
else:
return recording.title

View file

@ -1525,6 +1525,10 @@ def floor_plan(request, num=None, floor=None, ):
def proceedings(request, num=None):
meeting = get_meeting(num)
if meeting.number <= 64 or not meeting.agenda.assignments.exists():
return HttpResponseRedirect( 'https://www.ietf.org/proceedings/%s' % num )
begin_date = meeting.get_submission_start_date()
cut_off_date = meeting.get_submission_cut_off_date()
cor_cut_off_date = meeting.get_submission_correction_date()

View file

@ -0,0 +1,82 @@
{# Copyright The IETF Trust 2015, All Rights Reserved #}{% load origin %}{% origin %}
{% load ietf_filters %}
{% load proceedings_filters %}
<tr>
<td>
{% comment %}
<a name="{{ session.group.acronym }}"></a>
<a name="wg-{{ session.group.acronym }}"></a>
<a name="session.group-{{ session.group.acronym }}"></a>
{% endcomment %}
{% if session.name %}
<div class="anchor-target" id="{{ session.name|slugify }}">{{ session.name }}</div>
{% else %}
<div class="anchor-target" id="{{session.group.acronym}}"><a href="{% url 'ietf.group.views.group_home' acronym=session.group.acronym %}">{{session.group.acronym}}</a></div>
{% if session.group.state.slug == "bof" %}
<span class="label label-success">{{ session.group.state.slug|upper }}</span>
{% endif %}
{% endif %}
</td>
{% if session.status_id == 'canceled' %}
<td colspan="3"><span class="label label-danger">Session cancelled</span></td>
{% else %}
<td>
{% if session.agenda %}
<a href="https://www.ietf.org/proceedings/{{meeting_num}}/agenda/{{ session.agenda }}">Agenda</a><br>
{% else %}
{% if show_agenda == "True" %}
<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" %}
<span class="label label-warning">No minutes</span><br>
{% endif %}
{% endif %}
{% if session.all_meeting_bluesheets %}
{% if session.all_meeting_bluesheets|length == 1 %}
<a href="{{session.all_meeting_bluesheets.0.get_absolute_url}}">Bluesheets</a></br>
{% else %}
{% for bs in session.all_meeting_bluesheets %}
<a href="{{bs.get_absolute_url}}">Bluesheets {{bs.sessionpresentation_set.first.session.official_timeslotassignment.timeslot.time|date:"D G:i"}}</a></br>
{% endfor %}
{% endif %}
{% endif %}
</td>
<td>
{% if session.all_meeting_sessions_for_group|length == 1 %}
{% for rec in session.all_meeting_recordings %}
<a href="{{rec.get_absolute_url}}">{{rec|hack_recording_title:False}}</a><br>
{% endfor %}
{% else %}
{% for rec in session.all_meeting_recordings %}
<a href="{{rec.get_absolute_url}}">{{rec|hack_recording_title:True}}</a><br>
{% endfor %}
{% endif %}
</td>
<td>
{% with session.slides as slides %}
{% for slide in slides %}
<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>
{% endfor %}
{% endwith %}
</td>
<td>
{% with session.all_meeting_drafts as drafts %}
{% 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>
{% endfor %}
{% endwith %}
</td>
{% endif %}
</tr>

View file

@ -22,6 +22,11 @@
<p class="alert alert-info">
<b>This page is under construction</b>
</p>
{% if meeting_num|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>
</p>
{% endif %}
{# cache for 15 minutes, as long as there's no proceedings activity. takes 4-8 seconds to generate. #}
{% load cache %}
@ -35,16 +40,16 @@
<thead>
<tr>
<th class="col-md-1">Group</th>
<th class="col-md-1">Agenda</th>
<th class="col-md-1">Minutes</th>
<th class="col-md-6">Slides</th>
<th class="col-md-1">Artifacts</th>
<th class="col-md-2">Recordings</th>
<th class="col-md-4">Slides</th>
<th class="col-md-3">Drafts</th>
</tr>
</thead>
<tbody>
{% for session in plenaries %}
{% include "meeting/group_materials.html" %}
{% include "meeting/group_proceedings.html" %}
{% endfor %}
</tbody>
</table>
@ -58,9 +63,9 @@
<thead>
<tr>
<th class="col-md-1">Group</th>
<th class="col-md-1">Agenda</th>
<th class="col-md-1">Minutes</th>
<th class="col-md-6">Slides</th>
<th class="col-md-1">Artifacts</th>
<th class="col-md-2">Recordings</th>
<th class="col-md-4">Slides</th>
<th class="col-md-3">Drafts</th>
</tr>
</thead>
@ -68,7 +73,7 @@
<tbody>
{% for session in sessions.list|dictsort:"group.acronym" %}
{% ifchanged session.group.acronym %}
{% include "meeting/group_materials.html" %}
{% include "meeting/group_proceedings.html" %}
{% endifchanged %}
{% endfor %}
</tbody>
@ -83,9 +88,9 @@
<thead>
<tr>
<th class="col-md-1">Group</th>
<th class="col-md-1">Agenda</th>
<th class="col-md-1">Minutes</th>
<th class="col-md-6">Slides</th>
<th class="col-md-1">Artifacts</th>
<th class="col-md-2">Recordings</th>
<th class="col-md-4">Slides</th>
<th class="col-md-3">Drafts</th>
</tr>
</thead>
@ -93,7 +98,7 @@
<tbody>
{% for session in training %}
{% ifchanged %}
{% include "meeting/group_materials.html" %}
{% include "meeting/group_proceedings.html" %}
{% endifchanged %}
{% endfor %}
</tbody>
@ -108,9 +113,9 @@
<thead>
<tr>
<th class="col-md-1">Group</th>
<th class="col-md-1">Agenda</th>
<th class="col-md-1">Minutes</th>
<th class="col-md-6">Slides</th>
<th class="col-md-1">Artifacts</th>
<th class="col-md-2">Recordings</th>
<th class="col-md-4">Slides</th>
<th class="col-md-3">Drafts</th>
</tr>
</thead>
@ -118,7 +123,7 @@
<tbody>
{% for session in iab %}
{% ifchanged %}
{% include "meeting/group_materials.html" %}
{% include "meeting/group_proceedings.html" %}
{% endifchanged %}
{% endfor %}
</tbody>
@ -132,9 +137,9 @@
<thead>
<tr>
<th class="col-md-1">Group</th>
<th class="col-md-1">Agenda</th>
<th class="col-md-1">Minutes</th>
<th class="col-md-6">Slides</th>
<th class="col-md-1">Artifacts</th>
<th class="col-md-2">Recordings</th>
<th class="col-md-4">Slides</th>
<th class="col-md-3">Drafts</th>
</tr>
</thead>
@ -142,7 +147,7 @@
<tbody>
{% for session in irtf|dictsort:"group.acronym" %}
{% ifchanged %}
{% include "meeting/group_materials.html" %}
{% include "meeting/group_proceedings.html" %}
{% endifchanged %}
{% endfor %}
</tbody>