Added an order field to SessionPresentation.
Set up removing the order field from Document. Modified the meeting materials, proceedings, and session details views to use the order field on SessionPresentation. Added bootstrapped views to upload session materials (agendas, slides, minutes, and bluesheets). Integrated upload into the session details view. Commit ready for merge. - Legacy-Id: 11989
This commit is contained in:
parent
89a3afe025
commit
53f41a6327
|
@ -59,7 +59,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)
|
||||
|
|
|
@ -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',)},
|
||||
),
|
||||
]
|
|
@ -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:
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -27,7 +27,9 @@ from django.forms.models import modelform_factory, inlineformset_factory
|
|||
from django.forms import ModelForm
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.functional import curry
|
||||
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
|
||||
|
@ -51,7 +53,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
|
||||
|
@ -1006,10 +1007,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)
|
||||
|
@ -1028,10 +1028,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))
|
||||
|
||||
|
@ -1040,7 +1037,6 @@ def session_details(request, num, acronym ):
|
|||
'meeting' :meeting ,
|
||||
'acronym' :acronym,
|
||||
'can_manage_materials' : can_manage,
|
||||
'type_counter': type_counter,
|
||||
})
|
||||
|
||||
class SessionDraftsForm(forms.Form):
|
||||
|
@ -1114,6 +1110,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':
|
||||
|
@ -1138,7 +1136,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,time=doc.time,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,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])
|
||||
handle_upload_file(file, filename, session.meeting, 'bluesheets')
|
||||
return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
|
||||
|
@ -1152,6 +1150,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):
|
||||
|
||||
|
|
|
@ -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 %}
|
||||
|
|
22
ietf/templates/meeting/upload_session_agenda.html
Normal file
22
ietf/templates/meeting/upload_session_agenda.html
Normal 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 %}
|
|
@ -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 %}
|
||||
|
|
22
ietf/templates/meeting/upload_session_minutes.html
Normal file
22
ietf/templates/meeting/upload_session_minutes.html
Normal 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 %}
|
23
ietf/templates/meeting/upload_session_slides.html
Normal file
23
ietf/templates/meeting/upload_session_slides.html
Normal 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 %}
|
Loading…
Reference in a new issue