(somewhat bumpy) merge forward from proceedings/6.31.1.dev0

- Legacy-Id: 11992
This commit is contained in:
Robert Sparks 2016-09-14 22:09:30 +00:00
commit 02ee5dc5d7
11 changed files with 631 additions and 111 deletions

View file

@ -60,7 +60,7 @@ class DocumentInfo(models.Model):
abstract = models.TextField(blank=True)
rev = models.CharField(verbose_name="revision", max_length=16, blank=True)
pages = models.IntegerField(blank=True, null=True)
order = models.IntegerField(default=1, blank=True)
order = models.IntegerField(default=1, blank=True) # This is probably obviated by SessionPresentaion.order
intended_std_level = models.ForeignKey(IntendedStdLevelName, verbose_name="Intended standardization level", blank=True, null=True)
std_level = models.ForeignKey(StdLevelName, verbose_name="Standardization level", blank=True, null=True)
ad = models.ForeignKey(Person, verbose_name="area director", related_name='ad_%(class)s_set', blank=True, null=True)

View file

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('meeting', '0036_add_order_to_sessionpresentation'),
]
operations = [
migrations.AlterModelOptions(
name='sessionpresentation',
options={'ordering': ('order',)},
),
]

View file

@ -963,6 +963,7 @@ class SessionPresentation(models.Model):
class Meta:
db_table = 'meeting_session_materials'
ordering = ('order',)
def __unicode__(self):
return u"%s -> %s-%s" % (self.session, self.document.name, self.rev)
@ -1005,7 +1006,7 @@ class Session(models.Model):
for d in l:
d.meeting_related = lambda: True
else:
l = self.materials.filter(type=material_type).exclude(states__type=material_type, states__slug='deleted').order_by("order")
l = self.materials.filter(type=material_type).exclude(states__type=material_type, states__slug='deleted').order_by('sessionpresentation__order')
if only_one:
if l:

View file

@ -1271,7 +1271,7 @@ class FinalizeProceedingsTests(TestCase):
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')
class BluesheetsTests(TestCase):
class MaterialsTests(TestCase):
def setUp(self):
self.materials_dir = os.path.abspath(settings.TEST_MATERIALS_DIR)
@ -1284,14 +1284,14 @@ class BluesheetsTests(TestCase):
settings.AGENDA_PATH = self.saved_agenda_path
shutil.rmtree(self.materials_dir)
def test_upload_blusheets(self):
def test_upload_bluesheets(self):
session = SessionFactory(meeting__type_id='ietf')
url = urlreverse('ietf.meeting.views.upload_session_bluesheets',kwargs={'num':session.meeting.number,'session_id':session.id})
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertFalse(q("div.alert"))
self.assertTrue('Upload' in unicode(q("title")))
self.assertFalse(session.sessionpresentation_set.exists())
test_file = StringIO('this is some text for a test')
test_file.name = "not_really.pdf"
@ -1302,7 +1302,7 @@ class BluesheetsTests(TestCase):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q("div.alert"))
self.assertTrue('Revise' in unicode(q("title")))
test_file = StringIO('this is some different text for a test')
test_file.name = "also_not_really.pdf"
r = self.client.post(url,dict(file=test_file))
@ -1317,7 +1317,7 @@ class BluesheetsTests(TestCase):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertFalse(q("div.alert"))
self.assertTrue('Upload' in unicode(q("title")))
self.assertFalse(session.sessionpresentation_set.exists())
test_file = StringIO('this is some text for a test')
test_file.name = "not_really.pdf"
@ -1325,3 +1325,129 @@ class BluesheetsTests(TestCase):
self.assertEqual(r.status_code, 302)
bs_doc = session.sessionpresentation_set.filter(document__type_id='bluesheets').first().document
self.assertEqual(bs_doc.rev,'00')
def test_upload_minutes_agenda(self):
for doctype in ('minutes','agenda'):
session = SessionFactory(meeting__type_id='ietf')
if doctype == 'minutes':
url = urlreverse('ietf.meeting.views.upload_session_minutes',kwargs={'num':session.meeting.number,'session_id':session.id})
else:
url = urlreverse('ietf.meeting.views.upload_session_agenda',kwargs={'num':session.meeting.number,'session_id':session.id})
self.client.logout()
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue('Upload' in unicode(q("Title")))
self.assertFalse(session.sessionpresentation_set.exists())
self.assertFalse(q('form input[type="checkbox"]'))
session2 = SessionFactory(meeting=session.meeting,group=session.group)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('form input[type="checkbox"]'))
test_file = StringIO('this is some text for a test')
test_file.name = "not_really.json"
r = self.client.post(url,dict(file=test_file))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('form .has-error'))
test_file = StringIO('this is some text for a test'*1510000)
test_file.name = "not_really.pdf"
r = self.client.post(url,dict(file=test_file))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('form .has-error'))
test_file = StringIO('this is some text for a test')
test_file.name = "not_really.txt"
r = self.client.post(url,dict(file=test_file,apply_to_all=False))
self.assertEqual(r.status_code, 302)
doc = session.sessionpresentation_set.filter(document__type_id=doctype).first().document
self.assertEqual(doc.rev,'00')
self.assertFalse(session2.sessionpresentation_set.filter(document__type_id=doctype))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue('Revise' in unicode(q("Title")))
test_file = StringIO('this is some different text for a test')
test_file.name = "also_not_really.txt"
r = self.client.post(url,dict(file=test_file,apply_to_all=True))
self.assertEqual(r.status_code, 302)
doc = Document.objects.get(pk=doc.pk)
self.assertEqual(doc.rev,'01')
self.assertTrue(session2.sessionpresentation_set.filter(document__type_id=doctype))
def test_upload_minutes_agenda_interim(self):
session=SessionFactory(meeting__type_id='interim')
for doctype in ('minutes','agenda'):
if doctype=='minutes':
url = urlreverse('ietf.meeting.views.upload_session_minutes',kwargs={'num':session.meeting.number,'session_id':session.id})
else:
url = urlreverse('ietf.meeting.views.upload_session_agenda',kwargs={'num':session.meeting.number,'session_id':session.id})
self.client.logout()
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue('Upload' in unicode(q("title")))
self.assertFalse(session.sessionpresentation_set.filter(document__type_id=doctype))
test_file = StringIO('this is some text for a test')
test_file.name = "not_really.txt"
r = self.client.post(url,dict(file=test_file))
self.assertEqual(r.status_code, 302)
doc = session.sessionpresentation_set.filter(document__type_id=doctype).first().document
self.assertEqual(doc.rev,'00')
def test_upload_slides(self):
session1 = SessionFactory(meeting__type_id='ietf')
session2 = SessionFactory(meeting=session1.meeting,group=session1.group)
url = urlreverse('ietf.meeting.views.upload_session_slides',kwargs={'num':session1.meeting.number,'session_id':session1.id})
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue('Upload' in unicode(q("title")))
self.assertFalse(session1.sessionpresentation_set.filter(document__type_id='slides'))
test_file = StringIO('this is not really a slide')
test_file.name = 'not_really.txt'
r = self.client.post(url,dict(file=test_file,title='a test slide file',apply_to_all=True))
self.assertEqual(r.status_code, 302)
self.assertEqual(session1.sessionpresentation_set.count(),1)
self.assertEqual(session2.sessionpresentation_set.count(),1)
sp = session2.sessionpresentation_set.first()
self.assertEqual(sp.document.name, 'slides-%s-%s-a-test-slide-file' % (session1.meeting.number,session1.group.acronym ) )
self.assertEqual(sp.order,1)
url = urlreverse('ietf.meeting.views.upload_session_slides',kwargs={'num':session2.meeting.number,'session_id':session2.id})
test_file = StringIO('some other thing still not slidelike')
test_file.name = 'also_not_really.txt'
r = self.client.post(url,dict(file=test_file,title='a different slide file',apply_to_all=False))
self.assertEqual(r.status_code, 302)
self.assertEqual(session1.sessionpresentation_set.count(),1)
self.assertEqual(session2.sessionpresentation_set.count(),2)
sp = session2.sessionpresentation_set.get(document__name__endswith='-a-different-slide-file')
self.assertEqual(sp.order,2)
self.assertEqual(sp.rev,u'00')
self.assertEqual(sp.document.rev,u'00')
url = urlreverse('ietf.meeting.views.upload_session_slides',kwargs={'num':session2.meeting.number,'session_id':session2.id,'name':session2.sessionpresentation_set.get(order=2).document.name})
r = self.client.get(url)
self.assertTrue(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue('Revise' in unicode(q("title")))
test_file = StringIO('new content for the second slide deck')
test_file.name = 'doesnotmatter.txt'
r = self.client.post(url,dict(file=test_file,title='rename the presentation',apply_to_all=False))
self.assertEqual(r.status_code, 302)
self.assertEqual(session1.sessionpresentation_set.count(),1)
self.assertEqual(session2.sessionpresentation_set.count(),2)
sp = session2.sessionpresentation_set.get(order=2)
self.assertEqual(sp.rev,u'01')
self.assertEqual(sp.document.rev,u'01')

View file

@ -11,6 +11,9 @@ safe_for_all_meeting_types = [
url(r'^session/(?P<acronym>[-a-z0-9]+)/?$', views.session_details),
url(r'^session/(?P<session_id>\d+)/drafts$', views.add_session_drafts),
url(r'^session/(?P<session_id>\d+)/bluesheets$', views.upload_session_bluesheets),
url(r'^session/(?P<session_id>\d+)/minutes$', views.upload_session_minutes),
url(r'^session/(?P<session_id>\d+)/agenda$', views.upload_session_agenda),
url(r'^session/(?P<session_id>\d+)/slides(?:/%(name)s)?$' % settings.URL_REGEXPS, views.upload_session_slides),
]

View file

@ -28,7 +28,9 @@ from django.forms import ModelForm
from django.template.loader import render_to_string
from django.utils.functional import curry
from django.views.decorators.cache import cache_page
from django.utils.text import slugify
from django.views.decorators.csrf import ensure_csrf_cookie
from django.template.defaultfilters import filesizeformat
from ietf.doc.fields import SearchableDocumentsField
from ietf.doc.models import Document, State, DocEvent, NewRevisionDocEvent
@ -52,7 +54,6 @@ 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.person.models import Person
from ietf.secr.proceedings.utils import handle_upload_file
from ietf.utils.mail import send_mail_message
from ietf.utils.pipe import pipe
@ -1011,10 +1012,9 @@ def session_details(request, num, acronym ):
if not sessions:
raise Http404
type_counter = Counter()
for session in sessions:
session.type_counter = Counter()
ss = session.timeslotassignments.filter(schedule=meeting.agenda).order_by('timeslot__time')
if ss:
session.time = ', '.join(x.timeslot.time.strftime("%A %b-%d-%Y %H%M") for x in ss)
@ -1033,10 +1033,7 @@ def session_details(request, num, acronym ):
# TODO FIXME Deleted materials shouldn't be in the sessionpresentation_set
for qs in [session.filtered_artifacts,session.filtered_slides,session.filtered_drafts]:
qs = [p for p in qs if p.document.get_state_slug(p.document.type_id)!='deleted']
type_counter.update([p.document.type.slug for p in qs])
#session.filtered_sessionpresentation_set = [p for p in session.sessionpresentation_set.all() if p.document.get_state_slug(p.document.type_id)!='deleted']
#type_counter.update([p.document.type.slug for p in session.filtered_sessionpresentation_set])
session.type_counter.update([p.document.type.slug for p in qs])
can_manage = can_manage_materials(request.user, Group.objects.get(acronym=acronym))
@ -1045,7 +1042,6 @@ def session_details(request, num, acronym ):
'meeting' :meeting ,
'acronym' :acronym,
'can_manage_materials' : can_manage,
'type_counter': type_counter,
})
class SessionDraftsForm(forms.Form):
@ -1119,6 +1115,8 @@ def upload_session_bluesheets(request, session_id, num):
if bluesheet_sp:
doc = bluesheet_sp.document
doc.rev = '%02d' % (int(doc.rev)+1)
bluesheet_sp.rev = doc.rev
bluesheet_sp.save()
else:
sess_time = session.official_timeslotassignment().timeslot.time
if session.meeting.type_id=='ietf':
@ -1143,7 +1141,7 @@ def upload_session_bluesheets(request, session_id, num):
session.sessionpresentation_set.create(document=doc,rev='00')
filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
doc.external_url = filename
e = NewRevisionDocEvent.objects.create(doc=doc, by=Person.objects.get(name='(System)'),type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
e = NewRevisionDocEvent.objects.create(doc=doc,by=request.user.person,type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
doc.save_with_history([e])
handle_upload_file(file, filename, session.meeting, 'bluesheets')
return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
@ -1157,6 +1155,301 @@ def upload_session_bluesheets(request, session_id, num):
'form': form,
})
VALID_MINUTES_EXTENSIONS = ('.txt','.html','.htm','.pdf')
# FIXME: This form validation code (based on the secretariat upload code) only looks at filename extensions
# It should look at the contents of the files instead.
class UploadMinutesForm(forms.Form):
file = forms.FileField(label='Minutes file to upload. Note that you can only upload minutes in txt, html, or pdf formats.')
apply_to_all = forms.BooleanField(label='Apply to all group sessions at this meeting',initial=True,required=False)
def __init__(self, num_sessions, *args, **kwargs):
super(UploadMinutesForm, self).__init__(*args, **kwargs)
if num_sessions<2:
self.fields.pop('apply_to_all')
def clean_file(self):
file = self.cleaned_data['file']
if file._size > settings.SECR_MAX_UPLOAD_SIZE:
raise forms.ValidationError('Please keep filesize under %s. Requested upload size is %s' % (filesizeformat(settings.SECR_MAX_UPLOAD_SIZE),filesizeformat(file._size)))
if os.path.splitext(file.name)[1].lower() not in VALID_MINUTES_EXTENSIONS:
raise forms.ValidationError('Only these file types supported for minutes: %s' % ','.join(VALID_MINUTES_EXTENSIONS))
return file
def upload_session_minutes(request, session_id, num):
# num is redundant, but we're dragging it along an artifact of where we are in the current URL structure
session = get_object_or_404(Session,pk=session_id)
if not session.can_manage_materials(request.user):
return HttpResponseForbidden("You don't have permission to upload minutes for this session.")
if session.is_material_submission_cutoff() and not has_role(request.user, "Secretariat"):
return HttpResponseForbidden("The materials cutoff for this session has passed. Contact the secretariat for further action.")
session_number = None
sessions = get_sessions(session.meeting.number,session.group.acronym)
num_sessions = len(sessions)
if len(sessions) > 1:
session_number = 1 + sessions.index(session)
minutes_sp = session.sessionpresentation_set.filter(document__type='minutes').first()
if request.method == 'POST':
form = UploadMinutesForm(num_sessions,request.POST,request.FILES)
if form.is_valid():
file = request.FILES['file']
_, ext = os.path.splitext(file.name)
apply_to_all = True
if num_sessions > 1:
apply_to_all = form.cleaned_data['apply_to_all']
if minutes_sp:
doc = minutes_sp.document
doc.rev = '%02d' % (int(doc.rev)+1)
minutes_sp.rev = doc.rev
minutes_sp.save()
else:
sess_time = session.official_timeslotassignment().timeslot.time
if session.meeting.type_id=='ietf':
name = 'minutes-%s-%s' % (session.meeting.number,
session.group.acronym)
title = 'Minutes IETF%s: %s' % (session.meeting.number,
session.group.acronym)
if not apply_to_all:
name += '-%s' % (sess_time.strftime("%Y%m%d%H%M"),)
title += ': %s' % (sess_time.strftime("%a %H:%M"),)
else:
name = 'minutes-%s-%s' % (session.meeting.number, sess_time.strftime("%Y%m%d%H%M"))
title = 'Minutes %s: %s' % (session.meeting.number, sess_time.strftime("%a %H:%M"))
doc = Document.objects.create(
name = name,
type_id = 'minutes',
title = title,
group = session.group,
rev = '00',
)
doc.states.add(State.objects.get(type_id='minutes',slug='active'))
doc.docalias_set.create(name=doc.name)
session.sessionpresentation_set.create(document=doc,rev='00')
if apply_to_all:
for other_session in sessions:
if other_session != session:
other_session.sessionpresentation_set.filter(document__type='minutes').delete()
other_session.sessionpresentation_set.create(document=doc,rev=doc.rev)
filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
doc.external_url = filename
e = NewRevisionDocEvent.objects.create(doc=doc,time=doc.time,by=request.user.person,type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
doc.save_with_history([e])
# The way this function builds the filename it will never trigger the file delete in handle_file_upload.
handle_upload_file(file, filename, session.meeting, 'minutes')
return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
else:
form = UploadMinutesForm(num_sessions)
return render(request, "meeting/upload_session_minutes.html",
{'session': session,
'session_number': session_number,
'minutes_sp' : minutes_sp,
'form': form,
})
VALID_AGENDA_EXTENSIONS = ('.txt','.html','.htm',)
# FIXME: This form validation code (based on the secretariat upload code) only looks at filename extensions
# It should look at the contents of the files instead.
class UploadAgendaForm(forms.Form):
file = forms.FileField(label='Agenda file to upload. Note that you can only upload agendas in txt or html formats.')
apply_to_all = forms.BooleanField(label='Apply to all group sessions at this meeting',initial=True,required=False)
def __init__(self, num_sessions, *args, **kwargs):
super(UploadAgendaForm, self).__init__(*args, **kwargs)
if num_sessions<2:
self.fields.pop('apply_to_all')
def clean_file(self):
file = self.cleaned_data['file']
if file._size > settings.SECR_MAX_UPLOAD_SIZE:
raise forms.ValidationError('Please keep filesize under %s. Requested upload size is %s' % (filesizeformat(settings.SECR_MAX_UPLOAD_SIZE),filesizeformat(file._size)))
if os.path.splitext(file.name)[1].lower() not in VALID_AGENDA_EXTENSIONS:
raise forms.ValidationError('Only these file types supported for agendas: %s' % ','.join(VALID_AGENDA_EXTENSIONS))
return file
def upload_session_agenda(request, session_id, num):
# num is redundant, but we're dragging it along an artifact of where we are in the current URL structure
session = get_object_or_404(Session,pk=session_id)
if not session.can_manage_materials(request.user):
return HttpResponseForbidden("You don't have permission to upload an agenda for this session.")
if session.is_material_submission_cutoff() and not has_role(request.user, "Secretariat"):
return HttpResponseForbidden("The materials cutoff for this session has passed. Contact the secretariat for further action.")
session_number = None
sessions = get_sessions(session.meeting.number,session.group.acronym)
num_sessions = len(sessions)
if len(sessions) > 1:
session_number = 1 + sessions.index(session)
agenda_sp = session.sessionpresentation_set.filter(document__type='agenda').first()
if request.method == 'POST':
form = UploadAgendaForm(num_sessions,request.POST,request.FILES)
if form.is_valid():
file = request.FILES['file']
_, ext = os.path.splitext(file.name)
apply_to_all = True
if num_sessions > 1:
apply_to_all = form.cleaned_data['apply_to_all']
if agenda_sp:
doc = agenda_sp.document
doc.rev = '%02d' % (int(doc.rev)+1)
agenda_sp.rev = doc.rev
agenda_sp.save()
else:
sess_time = session.official_timeslotassignment().timeslot.time
if session.meeting.type_id=='ietf':
name = 'agenda-%s-%s' % (session.meeting.number,
session.group.acronym)
title = 'Agenda IETF%s: %s' % (session.meeting.number,
session.group.acronym)
if not apply_to_all:
name += '-%s' % (sess_time.strftime("%Y%m%d%H%M"),)
title += ': %s' % (sess_time.strftime("%a %H:%M"),)
else:
name = 'agenda-%s-%s' % (session.meeting.number, sess_time.strftime("%Y%m%d%H%M"))
title = 'Agenda %s: %s' % (session.meeting.number, sess_time.strftime("%a %H:%M"))
doc = Document.objects.create(
name = name,
type_id = 'agenda',
title = title,
group = session.group,
rev = '00',
)
doc.states.add(State.objects.get(type_id='agenda',slug='active'))
doc.docalias_set.create(name=doc.name)
session.sessionpresentation_set.create(document=doc,rev='00')
if apply_to_all:
for other_session in sessions:
if other_session != session:
other_session.sessionpresentation_set.filter(document__type='agenda').delete()
other_session.sessionpresentation_set.create(document=doc,rev=doc.rev)
filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
doc.external_url = filename
e = NewRevisionDocEvent.objects.create(doc=doc,time=doc.time,by=request.user.person,type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
doc.save_with_history([e])
# The way this function builds the filename it will never trigger the file delete in handle_file_upload.
handle_upload_file(file, filename, session.meeting, 'agenda')
return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
else:
form = UploadAgendaForm(num_sessions)
return render(request, "meeting/upload_session_agenda.html",
{'session': session,
'session_number': session_number,
'agenda_sp' : agenda_sp,
'form': form,
})
VALID_SLIDE_EXTENSIONS = ('.doc','.docx','.pdf','.ppt','.pptx','.txt') # Note the removal of .zip
# FIXME: This form validation code (based on the secretariat upload code) only looks at filename extensions
# It should look at the contents of the files instead.
class UploadSlidesForm(forms.Form):
title = forms.CharField(max_length=255)
file = forms.FileField(label='Slides file to upload.')
apply_to_all = forms.BooleanField(label='Apply to all group sessions at this meeting',initial=True,required=False)
def __init__(self, num_sessions, *args, **kwargs):
super(UploadSlidesForm, self).__init__(*args, **kwargs)
if num_sessions<2:
self.fields.pop('apply_to_all')
def clean_file(self):
file = self.cleaned_data['file']
if file._size > settings.SECR_MAX_UPLOAD_SIZE:
raise forms.ValidationError('Please keep filesize under %s. Requested upload size is %s' % (filesizeformat(settings.SECR_MAX_UPLOAD_SIZE),filesizeformat(file._size)))
if os.path.splitext(file.name)[1].lower() not in VALID_SLIDE_EXTENSIONS:
raise forms.ValidationError('Only these file types supported for slides: %s' % ','.join(VALID_SLIDE_EXTENSIONS))
return file
def upload_session_slides(request, session_id, num, name):
# num is redundant, but we're dragging it along an artifact of where we are in the current URL structure
session = get_object_or_404(Session,pk=session_id)
if not session.can_manage_materials(request.user):
return HttpResponseForbidden("You don't have permission to upload slides for this session.")
if session.is_material_submission_cutoff() and not has_role(request.user, "Secretariat"):
return HttpResponseForbidden("The materials cutoff for this session has passed. Contact the secretariat for further action.")
session_number = None
sessions = get_sessions(session.meeting.number,session.group.acronym)
num_sessions = len(sessions)
if len(sessions) > 1:
session_number = 1 + sessions.index(session)
slides = None
slides_sp = None
if name:
slides = Document.objects.filter(name=name).first()
if not (slides and slides.type_id=='slides'):
raise Http404
slides_sp = session.sessionpresentation_set.filter(document=slides).first()
if request.method == 'POST':
form = UploadSlidesForm(num_sessions,request.POST,request.FILES)
if form.is_valid():
file = request.FILES['file']
_, ext = os.path.splitext(file.name)
apply_to_all = True
if num_sessions > 1:
apply_to_all = form.cleaned_data['apply_to_all']
if slides_sp:
doc = slides_sp.document
doc.rev = '%02d' % (int(doc.rev)+1)
doc.title = form.cleaned_data['title']
slides_sp.rev = doc.rev
slides_sp.save()
else:
title = form.cleaned_data['title']
sess_time = session.official_timeslotassignment().timeslot.time
if session.meeting.type_id=='ietf':
name = 'slides-%s-%s' % (session.meeting.number,
session.group.acronym)
if not apply_to_all:
name += '-%s' % (sess_time.strftime("%Y%m%d%H%M"),)
else:
name = 'slides-%s-%s' % (session.meeting.number, sess_time.strftime("%Y%m%d%H%M"))
name = name + '-' + slugify(title)
doc = Document.objects.create(
name = name,
type_id = 'slides',
title = title,
group = session.group,
rev = '00',
)
doc.states.add(State.objects.get(type_id='slides',slug='active'))
doc.states.add(State.objects.get(type_id='reuse_policy',slug='single'))
doc.docalias_set.create(name=doc.name)
max_order = session.sessionpresentation_set.filter(document__type='slides').aggregate(Max('order'))['order__max'] or 0
session.sessionpresentation_set.create(document=doc,rev=doc.rev,order=max_order+1)
if apply_to_all:
for other_session in sessions:
if other_session != session:
max_order = other_session.sessionpresentation_set.filter(document__type='slides').aggregate(Max('order'))['order__max'] or 0
other_session.sessionpresentation_set.create(document=doc,rev=doc.rev,order=max_order+1)
filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
doc.external_url = filename
e = NewRevisionDocEvent.objects.create(doc=doc,time=doc.time,by=request.user.person,type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
doc.save_with_history([e])
# The way this function builds the filename it will never trigger the file delete in handle_file_upload.
handle_upload_file(file, filename, session.meeting, 'slides')
return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
else:
initial = {}
if slides:
initial = {'title':slides.title}
form = UploadSlidesForm(num_sessions, initial=initial)
return render(request, "meeting/upload_session_slides.html",
{'session': session,
'session_number': session_number,
'slides_sp' : slides_sp,
'form': form,
})
@role_required('Secretariat')
def make_schedule_official(request, num, owner, name):

View file

@ -12,95 +12,115 @@
<h2>{% if sessions|length > 1 %}Session {{ forloop.counter }} : {% endif %}{{ session.time }}{% if session.name %} : {{ session.name }}{% endif %}</h2>
{% if session.agenda_note %}<h3>{{session.agenda_note}}</h3>{% endif %}
{% if can_manage_materials %}
{% if session.status.slug == 'sched' or session.status.slug == 'schedw' %}
<div class="buttonlist">
{% if meeting.type.slug == 'interim' and user|has_role:"Secretariat" %}
<a class="btn btn-default" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">Meeting Details</a>
{% endif %}
<a class="btn btn-default" href="{% url 'ietf.secr.proceedings.views.upload_unified' meeting_num=session.meeting.number acronym=session.group.acronym %}">
Upload/Edit materials
</a>
<a class="btn btn-default" href="{% url 'ietf.meeting.views.add_session_drafts' session_id=session.pk num=session.meeting.number %}">
Link additional drafts to session
</a>
{% if user|has_role:"Secretariat" %}
<a class="btn btn-default" href="{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number %}">Upload Bluesheets</a>
{% endif %}
{% if not type_counter.agenda %}
<span class="label label-warning">This session does not yet have an agenda</span>
{% endif %}
</div>
{% endif %}
{% endif %}
{% if can_manage_materials %}
{% if session.status.slug == 'sched' or session.status.slug == 'schedw' %}
<div class="buttonlist">
{% if meeting.type.slug == 'interim' and user|has_role:"Secretariat" %}
<a class="btn btn-default" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">Meeting Details</a>
{% endif %}
</div>
{% if not session.type_counter.agenda %}
<span class="label label-warning">This session does not yet have an agenda</span>
{% endif %}
{% endif %}
{% endif %}
{% if session.filtered_artifacts %}
<div class="panel panel-default">
<div class="panel-heading">Artifacts</div>
<div class="panel-body">
<table class="table table-condensed table-striped">
{% for pres in session.filtered_artifacts %}
<tr>
<td>
{% if pres.rev %}
{% url 'doc_view' name=pres.document.name rev=pres.rev as url %}
{% else %}
{% url 'doc_view' name=pres.document.name as url %}
{% endif %}
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}{% if pres.rev %}-{{ pres.rev }}{% endif %})
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Artifacts</div>
<div class="panel-body">
<table class="table table-condensed table-striped">
{% for pres in session.filtered_artifacts %}
<tr>
{% if pres.rev %}
{% url 'doc_view' name=pres.document.name rev=pres.rev as url %}
{% else %}
{% url 'doc_view' name=pres.document.name as url %}
{% endif %}
<td>
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}{% if pres.rev %}-{{ pres.rev }}{% endif %})</a>
</td>
{% if user|has_role:"Secretariat" or can_manage_materials %}
<td class="col-md-2">
{% if pres.document.type.slug == 'minutes' %}
{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number as upload_url %}
{% elif pres.document.type.slug == 'agenda' %}
{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number as upload_url %}
{% else %}
{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number as upload_url %}
{% endif %}
{% if pres.document.type.slug != 'bluesheets' or user|has_role:"Secretariat" %}
<a class="btn btn-default btn-sm pull-right" href="{{upload_url}}">Upload Revision</a>
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
</table>
{% if can_manage_materials %}
{% if not session.type_counter.agenda %}
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number %}">Upload Agenda</a>
{% endif %}
{% if not session.type_counter.minutes %}
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number %}">Upload Minutes</a>
{% endif %}
{% endif %}
{% if session.filtered_slides %}
<div class="panel panel-default">
<div class="panel-heading">Slides</div>
<div class="panel-body">
<table class="table table-condensed table-striped">
{% for pres in session.filtered_slides %}
<tr>
<td>
{% if pres.rev %}
{% url 'doc_view' name=pres.document.name rev=pres.rev as url %}
{% else %}
{% url 'doc_view' name=pres.document.name as url %}
{% endif %}
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}{% if pres.rev %}-{{ pres.rev }}{% endif %})
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% if user|has_role:"Secretariat" and not session.type_counter.bluesheets %}
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number %}">Upload Bluesheets</a>
{% endif %}
{% if session.filtered_drafts %}
<div class="panel panel-default">
<div class="panel-heading">Drafts</div>
<div class="panel-body">
<table class="table table-condensed table-striped">
{% for pres in session.filtered_drafts %}
<tr>
<td>
{% if pres.rev %}
{% url 'doc_view' name=pres.document.name rev=pres.rev as url %}
{% else %}
{% url 'doc_view' name=pres.document.name as url %}
{% endif %}
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}{% if pres.rev %}-{{ pres.rev }}{% endif %})
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Slides</div>
<div class="panel-body">
<table class="table table-condensed table-striped">
{% for pres in session.filtered_slides %}
<tr>
{% if pres.rev %}
{% url 'doc_view' name=pres.document.name rev=pres.rev as url %}
{% else %}
{% url 'doc_view' name=pres.document.name as url %}
{% endif %}
<td>
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}{% if pres.rev %}-{{ pres.rev }}{% endif %}) </a>
</td>
{% if can_manage_materials %}
<td class="col-md-2">
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Upload Revision</a>
</td>
{% endif %}
</tr>
{% endfor %}
</table>
{% if can_manage_materials %}
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number %}">Upload New Slides</a>
{% endif %}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Drafts
</div>
<div class="panel-body">
<table class="table table-condensed table-striped">
{% for pres in session.filtered_drafts %}
<tr>
<td>
{% if pres.rev %}
{% url 'doc_view' name=pres.document.name rev=pres.rev as url %}
{% else %}
{% url 'doc_view' name=pres.document.name as url %}
{% endif %}
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}{% if pres.rev %}-{{ pres.rev }}{% endif %})</a>
</td>
</tr>
{% endfor %}
</table>
{% if can_manage_materials %}
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.add_session_drafts' session_id=session.pk num=session.meeting.number %}">
Link additional drafts to session
</a>
{% endif %}
</div>
</div>
{% endfor %}
{% endblock %}

View file

@ -0,0 +1,22 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin staticfiles bootstrap3 %}
{% block title %}{% if agenda_sp %}Revise{% else %}Upload{% endif %} Agenda for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
{% block content %}
{% origin %}
<h1>{% if agenda_sp %}Revise{% else %}Upload{% endif %} Agenda for {{ session.meeting }} : {{ session.group.acronym }}{% if session.name %} : {{session.name}}{% endif %}</h1>
{% if session_number %}<h2> Session {{session_number}} : {{session.official_timeslotassignment.timeslot.time|date:"D M-d-Y Hi"}}</h2>{% endif %}
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Upload</button>
{% endbuttons %}
</form>
{% endblock %}

View file

@ -2,22 +2,14 @@
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin staticfiles bootstrap3 %}
{% block title %}Upload Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
{% block title %}{% if bluesheet_sp %}Revise{% else %}Upload{% endif %} Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
{% block content %}
{% origin %}
<h1>Upload Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% if session.name %} : {{session.name}}{% endif %}</h1>
<h1>{% if bluesheet_sp %}Revise{% else %}Upload{% endif %} Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% if session.name %} : {{session.name}}{% endif %}</h1>
{% if session_number %}<h2> Session {{session_number}} : {{session.official_timeslotassignment.timeslot.time|date:"D M-d-Y Hi"}}</h2>{% endif %}
{% if bluesheet_sp %}
<div class="alert alert-warning">
Bluesheets have alrady been uploaded for this session.
See <a href="{% url 'ietf.doc.views_doc.document_main' name=bluesheet_sp.document.name %}">{{bluesheet_sp.document.name}}-{{bluesheet_sp.document.rev}}</a>.
Continue with this upload to provide an updated version of that document.
</div>
{% endif %}
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{% bootstrap_form form %}

View file

@ -0,0 +1,22 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin staticfiles bootstrap3 %}
{% block title %}{% if minutes_sp %}Revise{% else %}Upload{% endif %} Minutes for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
{% block content %}
{% origin %}
<h1>{% if minutes_sp %}Revise{% else %}Upload{% endif %} Minutes for {{ session.meeting }} : {{ session.group.acronym }}{% if session.name %} : {{session.name}}{% endif %}</h1>
{% if session_number %}<h2> Session {{session_number}} : {{session.official_timeslotassignment.timeslot.time|date:"D M-d-Y Hi"}}</h2>{% endif %}
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Upload</button>
{% endbuttons %}
</form>
{% endblock %}

View file

@ -0,0 +1,23 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin staticfiles bootstrap3 %}
{% block title %}{% if slides_sp %}Revise{% else %}Upload New{% endif %} Slides for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
{% block content %}
{% origin %}
<h1>{% if slides_sp %}Revise{% else %}Upload New{% endif %} Slides for {{ session.meeting }} : {{ session.group.acronym }}{% if session.name %} : {{session.name}}{% endif %}</h1>
{% if session_number %}<h2> Session {{session_number}} : {{session.official_timeslotassignment.timeslot.time|date:"D M-d-Y Hi"}}</h2>{% endif %}
{% if slides_sp %}<h3>{{slides_sp.document.name}}</h3>{% endif %}
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Upload</button>
{% endbuttons %}
</form>
{% endblock %}