changes to support input of session recordings

- Legacy-Id: 8216
This commit is contained in:
Ryan Cross 2014-07-30 21:55:42 +00:00
parent e9a7133fec
commit 61668dba80
16 changed files with 442 additions and 61 deletions

View file

@ -90,6 +90,9 @@ class DocumentInfo(models.Model):
return settings.DOCUMENT_PATH_PATTERN.format(doc=self)
def href(self):
if self.external_url.startswith == 'http://':
return self.external_url
meeting_related = self.meeting_related()
settings_var = settings.DOC_HREFS

View file

@ -5,9 +5,9 @@ from django.conf import settings
from django.template.defaultfilters import filesizeformat
from ietf.doc.models import Document
from ietf.group.models import Group
from ietf.name.models import DocTypeName
from ietf.meeting.models import Meeting
from ietf.meeting.models import Meeting, Session
# ---------------------------------------------
@ -22,6 +22,14 @@ VALID_AGENDA_EXTENSIONS = ('.txt','.html','.htm')
# Forms
#----------------------------------------------------------
class AjaxChoiceField(forms.ChoiceField):
'''
Special ChoiceField to use when populating options with Ajax. The submitted value
is not in the initial choices list so we need to override valid_value().
'''
def valid_value(self, value):
return True
class EditSlideForm(forms.ModelForm):
class Meta:
model = Document
@ -42,6 +50,46 @@ class InterimMeetingForm(forms.Form):
raise forms.ValidationError('A meeting already exists for this date.')
return cleaned_data
class RecordingForm(forms.Form):
group = forms.CharField(max_length=40)
external_url = forms.CharField(max_length=255,label='Url')
session = AjaxChoiceField(choices=(('','----'),))
def clean_session(self):
'''
Emulate ModelChoiceField functionality
'''
id = self.cleaned_data.get('session')
try:
return Session.objects.get(id=id)
except Session.DoesNotExist:
raise forms.ValidationError('Invalid Session')
def clean_group(self):
acronym = self.cleaned_data.get('group')
try:
return Group.objects.get(acronym=acronym)
except Group.DoesNotExist:
raise forms.ValidationError('Invalid group name')
class RecordingEditForm(forms.ModelForm):
class Meta:
model = Document
fields = ['external_url']
def __init__(self, *args, **kwargs):
super(RecordingEditForm, self).__init__(*args, **kwargs)
self.fields['external_url'].label='Url'
"""
class RecordingEditForm(forms.Form):
name = forms.CharField(max_length=255,widget=forms.HiddenInput)
url = forms.CharField(max_length=255)
def save(self):
recording = get_object_or_404(Document,name=name)
recording.external_url = self.cleaned_data['url']
"""
class ReplaceSlideForm(forms.ModelForm):
file = forms.FileField(label='Select File')

View file

@ -12,22 +12,68 @@ import shutil
from django.conf import settings
from django.shortcuts import render_to_response
from ietf.doc.models import Document, RelatedDocument, DocEvent
from ietf.doc.models import Document, RelatedDocument, DocEvent, NewRevisionDocEvent, State
from ietf.group.models import Group, Role
from ietf.group.utils import get_charter_text
from ietf.meeting.helpers import get_schedule
from ietf.meeting.models import Session, Meeting, ScheduledSession
from ietf.person.models import Person
from ietf.secr.proceedings.models import InterimMeeting # proxy model
from ietf.secr.proceedings.models import Registration
from ietf.secr.utils.document import get_rfc_num
from ietf.secr.utils.group import groups_by_session
from ietf.secr.utils.meeting import get_upload_root, get_proceedings_path, get_material, get_session
from ietf.secr.utils.meeting import get_upload_root, get_proceedings_path, get_materials, get_session
# -------------------------------------------------
# Helper Functions
# -------------------------------------------------
def check_audio_files(group,meeting):
'''
Checks for audio files and creates corresponding materials (docs) for the Session
Expects audio files in the format ietf[meeting num]-[room]-YYYMMDD-HHMM-*,
Example: ietf90-salonb-20140721-1710-pm3.mp3
'''
for session in Session.objects.filter(group=group,meeting=meeting,status__in=('sched','schedw')):
timeslot = session.official_scheduledsession().timeslot
room = timeslot.location.name.lower()
room = room.replace(' ','')
room = room.replace('/','')
time = timeslot.time.strftime("%Y%m%d-%H%M")
filename = 'ietf{}-{}-{}-*'.format(meeting.number,room,time)
path = os.path.join(settings.MEETING_RECORDINGS_DIR,'ietf{}'.format(meeting.number),filename)
for file in glob.glob(path):
url = 'http://www.ietf.org/audio/ietf{}/{}'.format(meeting.number,os.path.basename(file))
doc = Document.objects.filter(external_url=url).first()
if not doc:
create_recording(session,meeting,group,url)
def create_recording(session,meeting,group,url):
sequence = get_next_sequence(group,meeting,'record')
name = 'record-{}-{}-{}'.format(meeting.number,group.acronym,sequence)
time = session.official_scheduledsession().timeslot.time.strftime('%Y-%m-%d %H:%M')
if url.endswith('mp3'):
title = 'Audio recording for {}'.format(time)
else:
title = 'Video recording for {}'.format(time)
doc = Document.objects.create(name=name,
title=title,
external_url=url,
group=group,
rev='00',
type_id='record')
doc.set_state(State.objects.get(type='record', slug='active'))
# create DocEvent
NewRevisionDocEvent.objects.create(type='new_revision',
by=Person.objects.get(name='(system)'),
doc=doc,
rev=doc.rev,
desc='New revision available',
time=doc.time)
session.materials.add(doc)
def mycomp(timeslot):
'''
This takes a timeslot object and returns a key to sort by the area acronym or None
@ -141,6 +187,13 @@ def get_progress_stats(sdate,edate):
return data
def get_next_sequence(group,meeting,type):
'''
Returns the next sequence number to use for a document of type = type.
Takes a group=Group object, meeting=Meeting object, type = string
'''
return Document.objects.filter(name__startswith='{}-{}-{}-'.format(type,meeting.number,group.acronym)).count() + 1
def write_html(path,content):
f = open(path,'w')
f.write(content)
@ -188,14 +241,8 @@ def create_proceedings(meeting, group, is_final=False):
if meeting.type_id == 'ietf' and int(meeting.number) < 79:
return
sessions = Session.objects.filter(meeting=meeting,group=group)
if sessions:
session = sessions[0]
agenda,minutes,slides = get_material(session)
else:
agenda = None
minutes = None
slides = None
check_audio_files(group,meeting)
materials = get_materials(group,meeting)
chairs = group.role_set.filter(name='chair')
secretaries = group.role_set.filter(name='secr')
@ -215,7 +262,7 @@ def create_proceedings(meeting, group, is_final=False):
settings.MEDIA_URL,
meeting.date.strftime('%Y/%m/%d'),
group.acronym)
# Only do these tasks if we are running official proceedings generation,
# otherwise skip them for expediency. This procedure is called any time meeting
# materials are uploaded/deleted, and we don't want to do all this work each time.
@ -313,9 +360,7 @@ def create_proceedings(meeting, group, is_final=False):
'tas': tas,
'meeting': meeting,
'rfcs': rfcs,
'slides': slides,
'minutes': minutes,
'agenda': agenda}
'materials': materials}
)
# save proceedings

View file

@ -2,10 +2,12 @@ import debug # pyflakes:ignore
from django.core.urlresolvers import reverse
from ietf.utils.test_utils import TestCase
from ietf.meeting.models import Meeting
from ietf.group.models import Group
from ietf.meeting.models import Meeting, Session
from ietf.meeting.test_data import make_meeting_test_data
from ietf.person.models import Person
from ietf.utils.test_data import make_test_data
from ietf.utils.test_utils import TestCase
SECR_USER='secretary'
@ -18,11 +20,30 @@ class MainTestCase(TestCase):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_view(self):
"View Test"
class RecordingsTestCase(TestCase):
def test_page(self):
make_test_data()
meeting = Meeting.objects.all()[0]
url = reverse('meetings_view', kwargs={'meeting_id':meeting.number})
meeting = Meeting.objects.first()
url = reverse('proceedings_recording', kwargs={'meeting_num':meeting.number})
self.client.login(username="secretary", password="secretary+password")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_post(self):
make_meeting_test_data()
meeting = Meeting.objects.first()
group = Group.objects.get(acronym='mars')
#session = Session.objects.create(group=group,
# requested_by=Person.objects.get(name="(System)"),
# meeting=meeting,
# status_id='sched')
# need ss and timeslot
session = Session.objects.filter(meeting=meeting,group=group,status__in=('sched','schedw')).first()
url = reverse('proceedings_recording', kwargs={'meeting_num':meeting.number})
data = dict(group=group.acronym,external_url='http://youtube.com/xyz',session=session.pk)
self.client.login(username="secretary", password="secretary+password")
response = self.client.post(url,data,follow=True)
self.assertEqual(response.status_code, 200)
print response.content
self.failUnless(group.acronym in response.content)
#def test_edit(self):

View file

@ -3,6 +3,7 @@ from django.conf.urls import patterns, url
urlpatterns = patterns('ietf.secr.proceedings.views',
url(r'^$', 'main', name='proceedings'),
url(r'^ajax/generate-proceedings/(?P<meeting_num>\d{1,3})/$', 'ajax_generate_proceedings', name='proceedings_ajax_generate_proceedings'),
url(r'^ajax/get-sessions/(?P<meeting_num>\d{1,3})/(?P<acronym>[A-Za-z0-9_\-\+]+)/', 'ajax_get_sessions', name='proceedings_ajax_get_sessions'),
url(r'^ajax/order-slide/$', 'ajax_order_slide', name='proceedings_ajax_order_slide'),
# special offline URL for testing proceedings build
url(r'^build/(?P<meeting_num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/(?P<acronym>[A-Za-z0-9_\-\+]+)/$',
@ -15,6 +16,8 @@ urlpatterns = patterns('ietf.secr.proceedings.views',
url(r'^progress-report/(?P<meeting_num>\d{1,3})/$', 'progress_report', name='proceedings_progress_report'),
url(r'^replace-slide/(?P<slide_id>[A-Za-z0-9._\-\+]+)/$', 'replace_slide', name='proceedings_replace_slide'),
url(r'^(?P<meeting_num>\d{1,3})/$', 'select', name='proceedings_select'),
url(r'^(?P<meeting_num>\d{1,3})/recording/$', 'recording', name='proceedings_recording'),
url(r'^(?P<meeting_num>\d{1,3})/recording/edit/(?P<name>[A-Za-z0-9_\-\+]+)$', 'recording_edit', name='proceedings_recording_edit'),
# NOTE: we have two entries here which both map to upload_unified, passing session_id or acronym
url(r'^(?P<meeting_num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/(?P<session_id>\d{1,6})/$',
'upload_unified', name='proceedings_upload_unified'),

View file

@ -10,7 +10,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db.models import Max
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.utils.text import slugify
@ -19,15 +19,15 @@ from ietf.secr.sreq.forms import GroupSelectForm
from ietf.secr.utils.decorators import check_permissions, sec_only
from ietf.secr.utils.document import get_full_path
from ietf.secr.utils.group import get_my_groups, groups_by_session
from ietf.secr.utils.meeting import get_upload_root, get_material, get_timeslot
from ietf.secr.utils.meeting import get_upload_root, get_materials, get_timeslot
from ietf.doc.models import Document, DocAlias, DocEvent, State, NewRevisionDocEvent
from ietf.group.models import Group
from ietf.ietfauth.utils import has_role
from ietf.meeting.models import Meeting, Session, TimeSlot, ScheduledSession
from ietf.secr.proceedings.forms import EditSlideForm, InterimMeetingForm, ReplaceSlideForm, UnifiedUploadForm
from ietf.secr.proceedings.forms import EditSlideForm, InterimMeetingForm, RecordingForm, RecordingEditForm, ReplaceSlideForm, UnifiedUploadForm
from ietf.secr.proceedings.proc_utils import ( gen_acknowledgement, gen_agenda, gen_areas, gen_attendees,
gen_group_pages, gen_index, gen_irtf, gen_overview, gen_plenaries, gen_progress, gen_research,
gen_training, create_proceedings, create_interim_directory )
gen_training, create_proceedings, create_interim_directory, create_recording )
from ietf.secr.proceedings.models import InterimMeeting # proxy model
@ -250,6 +250,33 @@ def ajax_generate_proceedings(request, meeting_num):
RequestContext(request,{}),
)
@jsonapi
def ajax_get_sessions(request, meeting_num, acronym):
'''
Ajax function to get session info for group / meeting
returns JSON format response: [{id:session_id, value:session info},...]
If there are no sessions an empty list is returned.
'''
results=[]
try:
meeting = Meeting.objects.get(number=meeting_num)
group = Group.objects.get(acronym=acronym)
except ObjectDoesNotExist:
return results
sessions = Session.objects.filter(meeting=meeting,group=group,status='sched')
# order by time scheduled
sessions = sorted(sessions,key = lambda x: x.official_scheduledsession().timeslot.time)
for n,session in enumerate(sessions,start=1):
timeslot = session.official_scheduledsession().timeslot
val = '{}: {} {}'.format(n,timeslot.time.strftime('%m-%d %H:%M'),timeslot.location.name)
d = {'id':session.id, 'value': val}
results.append(d)
return results
@jsonapi
def ajax_order_slide(request):
'''
@ -573,6 +600,73 @@ def progress_report(request, meeting_num):
url = reverse('proceedings_select', kwargs={'meeting_num':meeting_num})
return HttpResponseRedirect(url)
@sec_only
def recording(request, meeting_num):
'''
Enter Session recording info. Creates Document and associates it with Session
'''
meeting = get_object_or_404(Meeting, number=meeting_num)
recordings = Document.objects.filter(name__startswith='record-{}'.format(meeting.number),states__slug='active').order_by('group__acronym')
if request.method == 'POST':
form = RecordingForm(request.POST)
if form.is_valid():
group = form.cleaned_data['group']
external_url = form.cleaned_data['external_url']
session = form.cleaned_data['session']
if Document.objects.filter(type='record',external_url=external_url):
messages.error(request, "Recording already exists")
return redirect('proceedings_recording', meeting_num=meeting_num)
else:
create_recording(session,meeting,group,external_url)
# rebuild proceedings
create_proceedings(meeting,group)
messages.success(request,'Recording added')
return redirect('proceedings_recording', meeting_num=meeting_num)
else:
form = RecordingForm()
return render_to_response('proceedings/recording.html',{
'meeting':meeting,
'form':form,
'recordings':recordings},
RequestContext(request, {}),
)
@sec_only
def recording_edit(request, meeting_num, name):
'''
Edit recording Document
'''
recording = get_object_or_404(Document, name=name)
meeting = get_object_or_404(Meeting, number=meeting_num)
if request.method == 'POST':
button_text = request.POST.get('submit', '')
if button_text == 'Cancel':
return redirect('proceedings_recording', meeting_num=meeting_num)
form = RecordingEditForm(request.POST, instance=recording)
if form.is_valid():
form.save()
# rebuild proceedings
create_proceedings(meeting,recording.group)
messages.success(request,'Recording saved')
return redirect('proceedings_recording', meeting_num=meeting_num)
else:
form = RecordingEditForm(instance=recording)
return render_to_response('proceedings/recording_edit.html',{
'meeting':meeting,
'form':form,
'recording':recording},
RequestContext(request, {}),
)
@check_permissions
def replace_slide(request, slide_id):
'''
@ -860,7 +954,7 @@ def upload_unified(request, meeting_num, acronym=None, session_id=None):
else:
form = UnifiedUploadForm(initial={'meeting_id':meeting.id,'acronym':group.acronym,'material_type':'slides'})
agenda,minutes,slides = get_material(session)
materials = get_materials(group,meeting)
# gather DocEvents
# include deleted material to catch deleted doc events
@ -877,11 +971,9 @@ def upload_unified(request, meeting_num, acronym=None, session_id=None):
'docevents': docevents,
'meeting': meeting,
'group': group,
'minutes': minutes,
'agenda': agenda,
'materials': materials,
'form': form,
'session_name': session_name, # for Tutorials, etc
'slides':slides,
'proceedings_url': proceedings_url},
RequestContext(request, {}),
)

View file

@ -24,3 +24,8 @@
&nbsp;&nbsp;<a href="{{ MEDIA_URL }}proceedings/{{ meeting.number }}/progress-report.html">Progress Report</a>
</li>
</ul>
<p>Use this to input session recording information.</p>
<ul class="none">
<li><button onclick="window.location='{% url "proceedings_recording" meeting_num=meeting.number %}'">Recordings</button>
</li>
</ul>

View file

@ -11,7 +11,7 @@
</tr>
</thead>
<tbody>
{% for slide in slides %}
{% for slide in materials.slides %}
<tr id="slide_{{ forloop.counter }}" class="{% cycle 'row1' 'row2' %}">
<td><span class="ui-icon ui-icon-arrowthick-2-n-s"></span><a href="{{ slide.get_absolute_url }}" target="_blank">{{ slide.title }}</a></td>
<td>{{ slide.external_url }}{% if slide.external_url|is_ppt %}<span class="required"> *</span>{% endif %}</td>

View file

@ -22,16 +22,16 @@ and end with
{% endif %}
<h3>
{% if minutes %}
<a href="{{ minutes.get_absolute_url }}">Minutes</a>
{% if materials.minutes %}
<a href="{{ materials.minutes.get_absolute_url }}">Minutes</a>
{% else %}
Minutes
{% endif %}&nbsp;&nbsp;|&nbsp;&nbsp;
{% if meeting.type.slug == "ietf" %}
<a href="/audio/ietf{{ meeting.number }}/">Audio Archives</a>&nbsp;&nbsp;|&nbsp;&nbsp;
{% comment %}<a href="/audio/ietf{{ meeting.number }}/">Audio Archives</a>&nbsp;&nbsp;|&nbsp;&nbsp; {% endcomment %}
{% else %}
{% if agenda %}
<a href="{{ agenda.get_absolute_url }}">Agenda</a>
{% if materials.agenda %}
<a href="{{ materials.agenda.get_absolute_url }}">Agenda</a>
{% else %}
Agenda
{% endif %}&nbsp;&nbsp;|&nbsp;&nbsp;
@ -84,10 +84,21 @@ and end with
{% endif %}
<br /><br /></td></tr></table>
<h3>Meeting Slides:</h3>
{% if slides %}
<h3>Recordings:</h3>
{% if materials.record %}
<ul>
{% for slide in slides %}
{% for record in materials.record %}
<li><a href="{{ record.href }}" target="_blank">{{ record.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No Recordings Present</p>
{% endif %}
<h3>Meeting Slides:</h3>
{% if materials.slides %}
<ul>
{% for slide in materials.slides %}
<li><a href="{{ slide.get_absolute_url }}" target="_blank">{{ slide.title }}</a></li>
{% endfor %}
</ul>

View file

@ -0,0 +1,80 @@
{% extends "base_site.html" %}
{% block title %}Proceedings{% endblock %}
{% block extrastyle %}{{ block.super }}
<link rel="stylesheet" type="text/css" href="{{ SECR_STATIC_URL }}css/jquery-ui-modified.css" />
{% endblock %}
{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="{{ SECR_STATIC_URL }}js/jquery-ui-1.8.9.min.js"></script>
<script type="text/javascript" src="{{ SECR_STATIC_URL }}js/proceedings-recording.js"></script>
{% endblock %}
{% block breadcrumbs %}{{ block.super }}
{% if meeting.type_id == "interim" %}
&raquo; <a href="{% url "proceedings" %}">Proceedings</a>
&raquo; <a href="{% url "proceedings_select_interim" %}">Interim Select Group</a>
&raquo; <a href="{% url "proceedings_interim" acronym=group.acronym%}">{{ group.acronym }}</a>
&raquo; {{ meeting }}
{% else %}
&raquo; <a href="{% url "proceedings" %}">Proceedings</a>
&raquo; <a href="{% url "proceedings_select" meeting_num=meeting.number %}">{{ meeting.number }}</a>
&raquo; Recording
{% endif %}
{% endblock %}
{% block content %}
<div class="module interim-container">
<h2>Recording Metadata</h2>
<form id="recording-form" enctype="multipart/form-data" action="." method="post">{% csrf_token %}
<table class="center" id="proceedings-upload-table">
{{ form.as_table }}
</table>
{% include "includes/buttons_submit_back.html" %}
</form>
<div class="inline-related">
<h2>{{ meeting }} - Recordings
</h2>
<table class="center">
<thead>
<tr>
<th>Group</th>
<th>Session</th>
<th>Name</th>
<th>URL</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{% for record in recordings %}
<tr>
<td>{{ record.group.acronym }}</td>
<td>{{ record.session_set.first.official_scheduledsession.timeslot.time|date:"m-d H:i" }}</td>
<td>{{ record.name }}</td>
<td><a href="{{ record.href }}">{{ record.href }}</a></td>
<td><a href="{% url "proceedings_recording_edit" meeting_num=meeting.number name=record.name %}">Edit</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div> <!-- inline-group -->
</div> <!-- module -->
{% if docevents %}
<br>
<div class="module interim-container">
{% include "includes/docevents.html" %}
</div>
{% endif %}
{% endblock %}
{% block footer-extras %}
{% include "includes/upload_footer.html" %}
{% endblock %}

View file

@ -0,0 +1,40 @@
{% extends "base_site.html" %}
{% block title %}Edit Recording{% endblock %}
{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="{{ SECR_STATIC_URL }}js/utils.js"></script>
{% endblock %}
{% block breadcrumbs %}{{ block.super }}
{% if meeting.type_id == "interim" %}
&raquo; <a href="{% url "proceedings" %}">Proceedings</a>
&raquo; <a href="{% url "proceedings_select_interim" %}">Interim Select Group</a>
&raquo; <a href="{% url "proceedings_interim" acronym=group.acronym%}">{{ group.acronym }}</a>
&raquo; {{ meeting }}
&raquo; <a href="{% url "proceedings_recording" meeting_num=meeting.number %}">Recording</a>
&raquo; {{ recording.name }}
{% else %}
&raquo; <a href="{% url "proceedings" %}">Proceedings</a>
&raquo; <a href="{% url "proceedings_select" meeting_num=meeting.number %}">{{ meeting.number }}</a>
&raquo; <a href="{% url "proceedings_recording" meeting_num=meeting.number %}">Recording</a>
&raquo; {{ recording.name }}
{% endif %}
{% endblock %}
{% block content %}
<div class="module interim-container">
<h2>Recording Metadata for Group: {{ form.instance.group.acronym }} | Session: {{ form.instance.session_set.first.official_scheduledsession.timeslot.time }}</h2>
<p><h3>Edit Recording Metadata:</h3></p>
<form id="recording-form" action="" method="post">{% csrf_token %}
<table>
{{ form.as_table }}
</table>
{% include "includes/buttons_save_cancel.html" %}
</form>
</div> <!-- module -->
{% endblock %}

View file

@ -51,10 +51,10 @@
<td></td>
</tr>
<tr>
{% if minutes %}
<td><a href="{{ minutes.get_absolute_url }}" target="_blank">Minutes</td>
<td>{{ minutes.external_url }}</td>
<td><a href="{% url "proceedings_delete_material" slide_id=minutes.name %}">Delete</a></td>
{% if materials.minutes %}
<td><a href="{{ materials.minutes.get_absolute_url }}" target="_blank">Minutes</td>
<td>{{ materials.minutes.external_url }}</td>
<td><a href="{% url "proceedings_delete_material" slide_id=materials.minutes.name %}">Delete</a></td>
{% else %}
<td>Minutes</td>
<td>(not uploaded)</td>
@ -62,10 +62,10 @@
{% endif %}
</tr>
<tr>
{% if agenda %}
<td><a href="{{ agenda.get_absolute_url }}" target="_blank">Agenda</a></td>
<td>{{ agenda.external_url }}</td>
<td><a href="{% url "proceedings_delete_material" slide_id=agenda.name %}">Delete</a></td>
{% if materials.agenda %}
<td><a href="{{ materials.agenda.get_absolute_url }}" target="_blank">Agenda</a></td>
<td>{{ materials.agenda.external_url }}</td>
<td><a href="{% url "proceedings_delete_material" slide_id=materials.agenda.name %}">Delete</a></td>
{% else %}
<td>Agenda</td>
<td>(not uploaded)</td>

View file

@ -1,27 +1,30 @@
import os
import re
from django.conf import settings
from ietf.meeting.models import Meeting
from ietf.meeting.models import Meeting, Session
def get_current_meeting():
'''Returns the most recent IETF meeting'''
return Meeting.objects.filter(type='ietf').order_by('-number')[0]
def get_material(session):
def get_materials(group,meeting):
'''
This function takes a session object and returns a tuple of active materials:
agenda(Document), minutes(Document), slides(list of Documents)
Returns the materials as a dictionary with keys = doctype.
NOTE, if the group has multiple sessions all materials but recordings will be
attached to all sessions.
'''
active_materials = session.materials.exclude(states__slug='deleted')
slides = active_materials.filter(type='slides').order_by('order')
minutes = active_materials.filter(type='minutes')
minutes = minutes[0] if minutes else None
agenda = active_materials.filter(type='agenda')
agenda = agenda[0] if agenda else None
return agenda,minutes,slides
materials = dict(slides=[],record=[])
# TODO: status should only be sched, but there is a bug in the scheduler
for session in Session.objects.filter(group=group,meeting=meeting,status__in=('sched','schedw')):
for doc in session.materials.exclude(states__slug='deleted').order_by('order'):
if doc.type.slug in ('minutes','agenda'):
materials[doc.type.slug] = doc
elif doc not in materials[doc.type.slug]:
materials[doc.type.slug].append(doc)
return materials
def get_proceedings_path(meeting, group):
if meeting.type.slug == 'interim':

View file

@ -273,6 +273,7 @@ IESG_ROLL_CALL_FILE = '/a/www/www6/iesg/internal/rollcall.txt'
IESG_MINUTES_FILE = '/a/www/www6/iesg/internal/minutes.txt'
IESG_WG_EVALUATION_DIR = "/a/www/www6/iesg/evaluation"
INTERNET_DRAFT_ARCHIVE_DIR = '/a/www/www6s/draft-archive'
MEETING_RECORDINGS_DIR = '/a/www/audio'
# Mailing list info URL for lists hosted on the IETF servers
MAILING_LIST_INFO_URL = "https://www.ietf.org/mailman/listinfo/%(list_addr)s"
@ -295,6 +296,7 @@ MEETING_DOC_HREFS = {
"agenda": "/meeting/{meeting}/agenda/{doc.group.acronym}/",
"minutes": "http://www.ietf.org/proceedings/{meeting}/minutes/{doc.external_url}",
"slides": "http://www.ietf.org/proceedings/{meeting}/slides/{doc.external_url}",
"record": "{doc.external_url}",
}
# Override this in settings_local.py if needed

View file

@ -575,6 +575,10 @@ div.interim-scroll {
border-left: 1px solid #CCCCCC;
}
#recording-form #id_external_url {
width: 40em;
}
td.hidden {
display: none;
}

View file

@ -0,0 +1,24 @@
/* proceedings-recordings.js - utility functions */
$(document).ready(function() {
// auto populate Session select list
$('#id_group').blur(function(){
var loadUrl = "/secr/proceedings/ajax/get-sessions/";
var url = window.location.pathname;
var parts = url.split("/");
var acronym = $(this).val();
loadUrl = loadUrl+parts[3]+"/"+acronym+"/";
$('.errorlist').remove();
$.getJSON(loadUrl,function(data) {
$('#id_session').find('option').remove();
if (data.length == 0) {
$( '<ul class="errorlist"><li>No sessions found</li></ul>' ).insertBefore( "#id_group" );
} else {
$.each(data,function(i,item) {
$('#id_session').append('<option value="'+item.id+'">'+item.value+'</option>');
});
}
});
});
});