Merged in ^/branch/proceedings/6.33.1.dev0 from rjsparks@nostrum.com and rcross@amsl.com. This provides new ietf meeting proceedings pages.
- Legacy-Id: 12028
This commit is contained in:
commit
8c34e9d78d
|
@ -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)
|
||||
|
|
|
@ -2,7 +2,6 @@ import factory
|
|||
import random
|
||||
import datetime
|
||||
|
||||
from django.db.models import Max
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from ietf.meeting.models import Meeting, Session, Schedule, TimeSlot, SessionPresentation, FloorPlan
|
||||
|
@ -31,7 +30,8 @@ class MeetingFactory(factory.DjangoModelFactory):
|
|||
def number(self,n):
|
||||
if self.type_id == 'ietf':
|
||||
if Meeting.objects.filter(type='ietf').exists():
|
||||
return '%02d'%(int(Meeting.objects.filter(type='ietf').aggregate(Max('number'))['number__max'])+1)
|
||||
so_far = max([int(x.number) for x in Meeting.objects.filter(type='ietf')])
|
||||
return '%02d'%(so_far+1)
|
||||
else:
|
||||
return '%02d'%(n+80)
|
||||
else:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -7,10 +7,13 @@ from unittest import skipIf
|
|||
|
||||
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
#from django.test.utils import override_settings
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.factories import DocumentFactory
|
||||
from ietf.group import colors
|
||||
from ietf.meeting.factories import SessionFactory
|
||||
from ietf.meeting.test_data import make_meeting_test_data
|
||||
from ietf.meeting.models import SchedTimeSessAssignment
|
||||
from ietf.utils.test_runner import set_coverage_checking
|
||||
|
@ -43,15 +46,23 @@ def condition_data():
|
|||
|
||||
@skipIf(skip_selenium, skip_message)
|
||||
class ScheduleEditTests(StaticLiveServerTestCase):
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
set_coverage_checking(False)
|
||||
condition_data()
|
||||
super(ScheduleEditTests, cls).setUpClass()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(ScheduleEditTests, cls).tearDownClass()
|
||||
set_coverage_checking(True)
|
||||
|
||||
def setUp(self):
|
||||
self.driver = webdriver.PhantomJS(port=0, service_log_path=settings.TEST_GHOSTDRIVER_LOG_PATH)
|
||||
self.driver.set_window_size(1024,768)
|
||||
condition_data()
|
||||
|
||||
def tearDown(self):
|
||||
self.driver.close()
|
||||
set_coverage_checking(True)
|
||||
|
||||
def debugSnapshot(self,filename='debug_this.png'):
|
||||
self.driver.execute_script("document.body.bgColor = 'white';")
|
||||
|
@ -88,6 +99,57 @@ class ScheduleEditTests(StaticLiveServerTestCase):
|
|||
time.sleep(0.1) # The API that modifies the database runs async
|
||||
self.assertEqual(SchedTimeSessAssignment.objects.filter(session__meeting__number=42,session__group__acronym='mars',schedule__name='test-agenda').count(),0)
|
||||
|
||||
@skipIf(skip_selenium, skip_message)
|
||||
class SlideReorderTests(StaticLiveServerTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
set_coverage_checking(False)
|
||||
super(SlideReorderTests, cls).setUpClass()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(SlideReorderTests, cls).tearDownClass()
|
||||
set_coverage_checking(True)
|
||||
|
||||
def setUp(self):
|
||||
self.driver = webdriver.PhantomJS(port=0, service_log_path=settings.TEST_GHOSTDRIVER_LOG_PATH)
|
||||
self.driver.set_window_size(1024,768)
|
||||
self.session = SessionFactory(meeting__type_id='ietf')
|
||||
self.session.sessionpresentation_set.create(document=DocumentFactory(type_id='slides',name='one'),order=1)
|
||||
self.session.sessionpresentation_set.create(document=DocumentFactory(type_id='slides',name='two'),order=2)
|
||||
self.session.sessionpresentation_set.create(document=DocumentFactory(type_id='slides',name='three'),order=3)
|
||||
|
||||
def tearDown(self):
|
||||
self.driver.close()
|
||||
|
||||
def absreverse(self,*args,**kwargs):
|
||||
return '%s%s'%(self.live_server_url,urlreverse(*args,**kwargs))
|
||||
|
||||
def secr_login(self):
|
||||
url = '%s%s'%(self.live_server_url, urlreverse('django.contrib.auth.views.login'))
|
||||
self.driver.get(url)
|
||||
self.driver.find_element_by_name('username').send_keys('secretary')
|
||||
self.driver.find_element_by_name('password').send_keys('secretary+password')
|
||||
self.driver.find_element_by_xpath('//button[@type="submit"]').click()
|
||||
|
||||
#@override_settings(DEBUG=True)
|
||||
def testReorderSlides(self):
|
||||
return
|
||||
url = self.absreverse('ietf.meeting.views.session_details',
|
||||
kwargs=dict(
|
||||
num=self.session.meeting.number,
|
||||
acronym = self.session.group.acronym,))
|
||||
self.secr_login()
|
||||
self.driver.get(url)
|
||||
#debug.show('unicode(self.driver.page_source)')
|
||||
second = self.driver.find_element_by_css_selector('#slides tr:nth-child(2)')
|
||||
third = self.driver.find_element_by_css_selector('#slides tr:nth-child(3)')
|
||||
ActionChains(self.driver).drag_and_drop(second,third).perform()
|
||||
|
||||
time.sleep(0.1) # The API that modifies the database runs async
|
||||
names=self.session.sessionpresentation_set.values_list('document__name',flat=True)
|
||||
self.assertEqual(list(names),[u'one',u'three',u'two'])
|
||||
|
||||
# The following are useful debugging tools
|
||||
|
||||
# If you add this to a LiveServerTestCase and run just this test, you can browse
|
||||
|
|
|
@ -260,7 +260,6 @@ class MeetingTests(TestCase):
|
|||
self.write_materials_files(meeting, session)
|
||||
|
||||
url = urlreverse("ietf.meeting.views.proceedings", kwargs=dict(num=meeting.number))
|
||||
login_testing_unauthorized(self,"secretary",url)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
@ -1271,7 +1270,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 +1283,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 +1301,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 +1316,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 +1324,152 @@ 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')
|
||||
|
||||
def test_remove_sessionpresentation(self):
|
||||
session = SessionFactory(meeting__type_id='ietf')
|
||||
doc = DocumentFactory(type_id='slides')
|
||||
session.sessionpresentation_set.create(document=doc)
|
||||
|
||||
url = urlreverse('ietf.meeting.views.remove_sessionpresentation',kwargs={'num':session.meeting.number,'session_id':session.id,'name':'no-such-doc'})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
url = urlreverse('ietf.meeting.views.remove_sessionpresentation',kwargs={'num':session.meeting.number,'session_id':0,'name':doc.name})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
url = urlreverse('ietf.meeting.views.remove_sessionpresentation',kwargs={'num':session.meeting.number,'session_id':session.id,'name':doc.name})
|
||||
login_testing_unauthorized(self,"secretary",url)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
self.assertEqual(1,session.sessionpresentation_set.count())
|
||||
response = self.client.post(url,{'remove_session':''})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(0,session.sessionpresentation_set.count())
|
||||
self.assertEqual(2,doc.docevent_set.count())
|
||||
|
|
|
@ -11,6 +11,11 @@ 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),
|
||||
url(r'^session/(?P<session_id>\d+)/slides/%(name)s/order$' % settings.URL_REGEXPS, views.set_slide_order),
|
||||
url(r'^session/(?P<session_id>\d+)/doc/%(name)s/remove$' % settings.URL_REGEXPS, views.remove_sessionpresentation),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ from django import forms
|
|||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse,reverse_lazy
|
||||
from django.db.models import Min, Max
|
||||
from django.conf import settings
|
||||
from django.forms.models import modelform_factory, inlineformset_factory
|
||||
|
@ -28,14 +28,17 @@ 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.views.generic import RedirectView
|
||||
from django.template.defaultfilters import filesizeformat
|
||||
|
||||
from ietf.doc.fields import SearchableDocumentsField
|
||||
from ietf.doc.models import Document, State, DocEvent, NewRevisionDocEvent
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_materials
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
from ietf.meeting.models import Meeting, Session, Schedule, Room, FloorPlan
|
||||
from ietf.meeting.models import Meeting, Session, Schedule, Room, FloorPlan, SessionPresentation
|
||||
from ietf.meeting.helpers import get_areas, get_person_by_email, get_schedule_by_name
|
||||
from ietf.meeting.helpers import build_all_agenda_slices, get_wg_name_list
|
||||
from ietf.meeting.helpers import get_all_assignments_from_schedule
|
||||
|
@ -52,7 +55,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
|
||||
|
@ -1031,10 +1033,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)
|
||||
|
@ -1053,10 +1054,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))
|
||||
|
||||
|
@ -1065,7 +1063,6 @@ def session_details(request, num, acronym ):
|
|||
'meeting' :meeting ,
|
||||
'acronym' :acronym,
|
||||
'can_manage_materials' : can_manage,
|
||||
'type_counter': type_counter,
|
||||
})
|
||||
|
||||
class SessionDraftsForm(forms.Form):
|
||||
|
@ -1139,6 +1136,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':
|
||||
|
@ -1163,7 +1162,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)
|
||||
|
@ -1177,6 +1176,348 @@ 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=False,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)
|
||||
if Document.objects.filter(name=name).exists():
|
||||
doc = Document.objects.get(name=name)
|
||||
doc.rev = '%02d' % (int(doc.rev)+1)
|
||||
doc.title = form.cleaned_data['title']
|
||||
else:
|
||||
doc = Document.objects.create(
|
||||
name = name,
|
||||
type_id = 'slides',
|
||||
title = title,
|
||||
group = session.group,
|
||||
rev = '00',
|
||||
)
|
||||
doc.docalias_set.create(name=doc.name)
|
||||
doc.states.add(State.objects.get(type_id='slides',slug='active'))
|
||||
doc.states.add(State.objects.get(type_id='reuse_policy',slug='single'))
|
||||
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,
|
||||
})
|
||||
|
||||
def remove_sessionpresentation(request, session_id, num, name):
|
||||
sp = get_object_or_404(SessionPresentation,session_id=session_id,document__name=name)
|
||||
session = sp.session
|
||||
if not session.can_manage_materials(request.user):
|
||||
return HttpResponseForbidden("You don't have permission to manage materials 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.")
|
||||
if request.method == 'POST':
|
||||
session.sessionpresentation_set.filter(pk=sp.pk).delete()
|
||||
c = DocEvent(type="added_comment", doc=sp.document, by=request.user.person)
|
||||
c.desc = "Removed from session: %s" % (session)
|
||||
c.save()
|
||||
return redirect('ietf.meeting.views.session_details', num=session.meeting.number, acronym=session.group.acronym)
|
||||
|
||||
return render(request,'meeting/remove_sessionpresentation.html', {'sp': sp })
|
||||
|
||||
def set_slide_order(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 Document.objects.filter(type_id='slides',name=name).exists():
|
||||
raise Http404
|
||||
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.")
|
||||
|
||||
if request.method != 'POST' or not request.POST:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'No data submitted or not POST' }),content_type='application/json')
|
||||
order_str = request.POST.get('order', None)
|
||||
try:
|
||||
order = int(order_str)
|
||||
except ValueError:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied order is not valid' }),content_type='application/json')
|
||||
if order <=0 or order > 32767 :
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied order is not valid' }),content_type='application/json')
|
||||
|
||||
sp = session.sessionpresentation_set.get(document__name = name)
|
||||
sp.order = order
|
||||
sp.save()
|
||||
|
||||
return HttpResponse(json.dumps({'success':True}),content_type='application/json')
|
||||
|
||||
@role_required('Secretariat')
|
||||
def make_schedule_official(request, num, owner, name):
|
||||
|
||||
|
@ -1621,7 +1962,6 @@ def floor_plan(request, num=None, floor=None, ):
|
|||
"floors": floors,
|
||||
})
|
||||
|
||||
@role_required('Secretariat')
|
||||
def proceedings(request, num=None):
|
||||
|
||||
meeting = get_meeting(num)
|
||||
|
@ -1689,3 +2029,7 @@ def proceedings_overview(request, num=None):
|
|||
'meeting': meeting,
|
||||
'template': template,
|
||||
})
|
||||
|
||||
class OldUploadRedirect(RedirectView):
|
||||
def get_redirect_url(self, **kwargs):
|
||||
return reverse_lazy('ietf.meeting.views.session_details',kwargs=self.kwargs)
|
||||
|
|
|
@ -25,7 +25,8 @@ from ietf.secr.meetings.blue_sheets import create_blue_sheets
|
|||
from ietf.secr.meetings.forms import ( BaseMeetingRoomFormSet, MeetingModelForm,
|
||||
MeetingRoomForm, NewSessionForm, NonSessionEditForm, NonSessionForm, TimeSlotForm,
|
||||
UploadBlueSheetForm, get_next_slot )
|
||||
from ietf.secr.proceedings.views import build_choices, handle_upload_file
|
||||
from ietf.secr.proceedings.views import build_choices
|
||||
from ietf.secr.proceedings.utils import handle_upload_file
|
||||
from ietf.secr.sreq.forms import GroupSelectForm
|
||||
from ietf.secr.sreq.views import get_initial_session
|
||||
from ietf.secr.utils.meeting import get_session, get_timeslot
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import os
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.template.defaultfilters import filesizeformat
|
||||
|
||||
from ietf.doc.models import Document
|
||||
from ietf.name.models import DocTypeName
|
||||
from ietf.meeting.models import Session
|
||||
|
||||
|
||||
|
@ -22,11 +18,6 @@ VALID_BLUESHEET_EXTENSIONS = ('.pdf','.jpg','.jpeg')
|
|||
# Forms
|
||||
#----------------------------------------------------------
|
||||
|
||||
class EditSlideForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Document
|
||||
fields = ('title',)
|
||||
|
||||
class RecordingForm(forms.Form):
|
||||
external_url = forms.URLField(label='Url')
|
||||
session = forms.ModelChoiceField(queryset=Session.objects,empty_label='')
|
||||
|
@ -46,66 +37,3 @@ class RecordingEditForm(forms.ModelForm):
|
|||
super(RecordingEditForm, self).__init__(*args, **kwargs)
|
||||
self.fields['external_url'].label='Url'
|
||||
|
||||
class ReplaceSlideForm(forms.ModelForm):
|
||||
file = forms.FileField(label='Select File')
|
||||
|
||||
class Meta:
|
||||
model = Document
|
||||
fields = ('title',)
|
||||
|
||||
def clean_file(self):
|
||||
file = self.cleaned_data.get('file')
|
||||
ext = os.path.splitext(file.name)[1].lower()
|
||||
if ext not in VALID_SLIDE_EXTENSIONS:
|
||||
raise forms.ValidationError('Only these file types supported for presentation slides: %s' % ','.join(VALID_SLIDE_EXTENSIONS))
|
||||
if file._size > settings.SECR_MAX_UPLOAD_SIZE:
|
||||
raise forms.ValidationError('Please keep filesize under %s. Current filesize %s' % (filesizeformat(settings.SECR_MAX_UPLOAD_SIZE), filesizeformat(file._size)))
|
||||
return file
|
||||
|
||||
class UnifiedUploadForm(forms.Form):
|
||||
acronym = forms.CharField(widget=forms.HiddenInput())
|
||||
meeting_id = forms.CharField(widget=forms.HiddenInput())
|
||||
material_type = forms.ModelChoiceField(queryset=DocTypeName.objects.filter(slug__in=('minutes','agenda','slides','bluesheets')),empty_label=None)
|
||||
slide_name = forms.CharField(label='Name of Presentation',max_length=255,required=False,help_text="For presentations only")
|
||||
file = forms.FileField(label='Select File',help_text='<div id="id_file_help">Note 1: You can only upload a presentation file in txt, pdf, doc, or ppt/pptx. System will not accept presentation files in any other format.<br><br>Note 2: All uploaded files will be available to the public immediately on the Preliminary Page. However, for the Proceedings, ppt/pptx files will be converted to html format and doc files will be converted to pdf format manually by the Secretariat staff.</div>')
|
||||
|
||||
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. Current filesize %s' % (filesizeformat(settings.SECR_MAX_UPLOAD_SIZE), filesizeformat(file._size)))
|
||||
return file
|
||||
|
||||
def clean(self):
|
||||
super(UnifiedUploadForm, self).clean()
|
||||
# if an invalid file type is supplied no file attribute will exist
|
||||
if self.errors:
|
||||
return self.cleaned_data
|
||||
cleaned_data = self.cleaned_data
|
||||
material_type = cleaned_data['material_type']
|
||||
slide_name = cleaned_data['slide_name']
|
||||
file = cleaned_data['file']
|
||||
ext = os.path.splitext(file.name)[1].lower()
|
||||
|
||||
if material_type.slug == 'slides' and not slide_name:
|
||||
raise forms.ValidationError('ERROR: Name of Presentaion cannot be blank')
|
||||
|
||||
# only supporting PDFs per Alexa 04-05-2011
|
||||
#if material_type == 1 and not file_ext[1] == '.pdf':
|
||||
# raise forms.ValidationError('Presentations must be a PDF file')
|
||||
|
||||
# validate file extensions based on material type (slides,agenda,minutes,bluesheets)
|
||||
# valid extensions per online documentation: meeting-materials.html
|
||||
# 09-14-11 added ppt, pdf per Alexa
|
||||
# 04-19-12 txt/html for agenda, +pdf for minutes per Russ
|
||||
if material_type.slug == 'slides' and ext not in VALID_SLIDE_EXTENSIONS:
|
||||
raise forms.ValidationError('Only these file types supported for presentation slides: %s' % ','.join(VALID_SLIDE_EXTENSIONS))
|
||||
if material_type.slug == 'agenda' and ext not in VALID_AGENDA_EXTENSIONS:
|
||||
raise forms.ValidationError('Only these file types supported for agendas: %s' % ','.join(VALID_AGENDA_EXTENSIONS))
|
||||
if material_type.slug == 'minutes' and ext not in VALID_MINUTES_EXTENSIONS:
|
||||
raise forms.ValidationError('Only these file types supported for minutes: %s' % ','.join(VALID_MINUTES_EXTENSIONS))
|
||||
if material_type.slug == 'bluesheets' and ext not in VALID_BLUESHEET_EXTENSIONS:
|
||||
raise forms.ValidationError('Only these file types supported for bluesheets: %s' % ','.join(VALID_BLUESHEET_EXTENSIONS))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
|
|
|
@ -2,20 +2,19 @@ import debug # pyflakes:ignore
|
|||
import os
|
||||
import shutil
|
||||
|
||||
from StringIO import StringIO
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from ietf.doc.models import Document
|
||||
from ietf.group.models import Group
|
||||
from ietf.meeting.models import Meeting, Session
|
||||
from ietf.meeting.models import Session
|
||||
from ietf.meeting.test_data import make_meeting_test_data
|
||||
from ietf.utils.test_data import make_test_data
|
||||
from ietf.utils.test_utils import TestCase, unicontent
|
||||
from ietf.utils.test_utils import TestCase
|
||||
|
||||
from ietf.name.models import SessionStatusName
|
||||
from ietf.secr.utils.meeting import get_proceedings_path
|
||||
from ietf.meeting.factories import SessionFactory
|
||||
|
||||
from ietf.secr.proceedings.proc_utils import create_proceedings
|
||||
|
||||
SECR_USER='secretary'
|
||||
|
||||
|
@ -64,47 +63,23 @@ class RecordingTestCase(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.failUnless(external_url in response.content)
|
||||
|
||||
|
||||
class BluesheetTestCase(TestCase):
|
||||
class OldProceedingsTestCase(TestCase):
|
||||
''' Ensure coverage of fragments of old proceedings generation until those are removed '''
|
||||
def setUp(self):
|
||||
self.session = SessionFactory(meeting__type_id='ietf')
|
||||
self.proceedings_dir = os.path.abspath("tmp-proceedings-dir")
|
||||
if not os.path.exists(self.proceedings_dir):
|
||||
os.mkdir(self.proceedings_dir)
|
||||
|
||||
# This unintuitive bit is a consequence of the surprising implementation of meeting.get_materials_path
|
||||
self.saved_agenda_path = settings.AGENDA_PATH
|
||||
settings.AGENDA_PATH = self.proceedings_dir
|
||||
|
||||
self.interim_listing_dir = os.path.abspath("tmp-interim-listing-dir")
|
||||
if not os.path.exists(self.interim_listing_dir):
|
||||
os.mkdir(self.interim_listing_dir)
|
||||
self.saved_secr_interim_listing_dir = settings.SECR_INTERIM_LISTING_DIR
|
||||
settings.SECR_INTERIM_LISTING_DIR = self.interim_listing_dir
|
||||
|
||||
settings.AGENDA_PATH= self.proceedings_dir
|
||||
|
||||
target_path = self.session.meeting.get_materials_path()
|
||||
if not os.path.exists(target_path):
|
||||
os.makedirs(target_path)
|
||||
|
||||
def tearDown(self):
|
||||
settings.AGENDA_PATH = self.saved_agenda_path
|
||||
shutil.rmtree(self.proceedings_dir)
|
||||
settings.SECR_INTERIM_LISTING_DIR = self.saved_secr_interim_listing_dir
|
||||
shutil.rmtree(self.interim_listing_dir)
|
||||
|
||||
def test_upload(self):
|
||||
make_meeting_test_data()
|
||||
meeting = Meeting.objects.filter(type='interim',session__status='sched').first()
|
||||
#self.assertTrue(meeting)
|
||||
group = Group.objects.get(acronym='mars')
|
||||
#Session.objects.create(meeting=meeting,group=group,requested_by_id=1,status_id='sched',type_id='session')
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'acronym':'mars'})
|
||||
upfile = StringIO('dummy file')
|
||||
upfile.name = "scan1.pdf"
|
||||
self.client.login(username="marschairman", password="marschairman+password")
|
||||
r = self.client.post(url,
|
||||
dict(acronym='mars',meeting_id=meeting.id,material_type='bluesheets',file=upfile),follow=True)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
doc = Document.objects.get(type='bluesheets')
|
||||
self.failUnless(doc.external_url in unicontent(r))
|
||||
self.failUnless(os.path.exists(os.path.join(doc.get_file_path(),doc.external_url)))
|
||||
# test that proceedings has bluesheets on it
|
||||
path = get_proceedings_path(meeting,group)
|
||||
self.failUnless(os.path.exists(path))
|
||||
with open(path) as f:
|
||||
data = f.read()
|
||||
self.failUnless(doc.external_url.encode('utf-8') in data)
|
||||
|
||||
settings.AGENDA_PATH = self.saved_agenda_path
|
||||
|
||||
def test_old_generate(self):
|
||||
create_proceedings(self.session.meeting,self.session.group,is_final=True)
|
||||
|
|
|
@ -1,26 +1,16 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf import settings
|
||||
from ietf.meeting.views import OldUploadRedirect
|
||||
|
||||
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/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-z0-9]+)/$',
|
||||
'build', name='proceedings_build'),
|
||||
url(r'^delete/(?P<slide_id>[A-Za-z0-9._\-\+]+)/$', 'delete_material', name='proceedings_delete_material'),
|
||||
url(r'^edit-slide/(?P<slide_id>[A-Za-z0-9._\-\+]+)/$', 'edit_slide', name='proceedings_edit_slide'),
|
||||
url(r'^move-slide/(?P<slide_id>[A-Za-z0-9._\-\+]+)/(?P<direction>(up|down))/$',
|
||||
'move_slide', name='proceedings_move_slide'),
|
||||
url(r'^process-pdfs/(?P<meeting_num>\d{1,3})/$', 'process_pdfs', name='proceedings_process_pdfs'),
|
||||
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'),
|
||||
url(r'^(?P<meeting_num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/%(acronym)s/$' % settings.URL_REGEXPS,
|
||||
'upload_unified', name='proceedings_upload_unified'),
|
||||
url(r'^(?P<num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/%(acronym)s/$' % settings.URL_REGEXPS,
|
||||
OldUploadRedirect.as_view()),
|
||||
)
|
||||
|
|
|
@ -8,31 +8,25 @@ import debug # pyflakes:ignore
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
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, redirect
|
||||
from django.template import RequestContext
|
||||
from django.utils.text import slugify
|
||||
|
||||
from ietf.secr.lib.template import jsonapi
|
||||
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_materials, get_timeslot, get_proceedings_path, get_proceedings_url
|
||||
from ietf.doc.models import Document, DocAlias, DocEvent, State, NewRevisionDocEvent
|
||||
from ietf.secr.utils.decorators import sec_only
|
||||
from ietf.secr.utils.group import get_my_groups
|
||||
from ietf.secr.utils.meeting import get_timeslot, get_proceedings_url
|
||||
from ietf.doc.models import Document, DocEvent
|
||||
from ietf.group.models import Group
|
||||
from ietf.person.models import Person
|
||||
from ietf.ietfauth.utils import has_role, role_required
|
||||
from ietf.meeting.models import Meeting, Session, TimeSlot, SchedTimeSessAssignment
|
||||
from ietf.meeting.models import Meeting, Session, TimeSlot
|
||||
|
||||
from ietf.secr.proceedings.forms import EditSlideForm, RecordingForm, RecordingEditForm, ReplaceSlideForm, UnifiedUploadForm
|
||||
from ietf.secr.proceedings.forms import RecordingForm, RecordingEditForm
|
||||
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_recording )
|
||||
from ietf.secr.proceedings.utils import handle_upload_file
|
||||
from ietf.utils.log import log
|
||||
|
||||
# -------------------------------------------------
|
||||
|
@ -226,132 +220,10 @@ def ajax_generate_proceedings(request, meeting_num):
|
|||
RequestContext(request,{}),
|
||||
)
|
||||
|
||||
@jsonapi
|
||||
def ajax_order_slide(request):
|
||||
'''
|
||||
Ajax function to change the order of presentation slides.
|
||||
This function expects a POST request with the following parameters
|
||||
order: new order of slide, 0 based
|
||||
slide_name: slide primary key (name)
|
||||
'''
|
||||
if request.method != 'POST' or not request.POST:
|
||||
return { 'success' : False, 'error' : 'No data submitted or not POST' }
|
||||
slide_name = request.POST.get('slide_name',None)
|
||||
order = request.POST.get('order',None)
|
||||
slide = get_object_or_404(Document, name=slide_name)
|
||||
|
||||
# get all the slides for this session
|
||||
session = slide.session_set.all()[0]
|
||||
qs = session.materials.exclude(states__slug='deleted').filter(type='slides').order_by('order')
|
||||
|
||||
# move slide and reorder list
|
||||
slides = list(qs)
|
||||
index = slides.index(slide)
|
||||
slides.pop(index)
|
||||
slides.insert(int(order),slide)
|
||||
for ord,item in enumerate(slides,start=1):
|
||||
if item.order != ord:
|
||||
item.order = ord
|
||||
item.save()
|
||||
|
||||
return {'success':True,'order':order,'slide':slide_name}
|
||||
|
||||
# --------------------------------------------------
|
||||
# STANDARD VIEW FUNCTIONS
|
||||
# --------------------------------------------------
|
||||
@role_required('Secretariat')
|
||||
def build(request,meeting_num,acronym):
|
||||
'''
|
||||
This is a utility or test view. It simply rebuilds the proceedings html for the specified
|
||||
meeting / group.
|
||||
'''
|
||||
meeting = Meeting.objects.get(number=meeting_num)
|
||||
group = get_object_or_404(Group,acronym=acronym)
|
||||
|
||||
create_proceedings(meeting,group,is_final=True)
|
||||
|
||||
messages.success(request,'proceedings.html was rebuilt')
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting_num,'acronym':acronym})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@check_permissions
|
||||
def delete_material(request,slide_id):
|
||||
'''
|
||||
This view handles deleting meeting materials. We don't actually delete the
|
||||
document object but set the state to deleted and add a 'deleted' DocEvent.
|
||||
'''
|
||||
doc = get_object_or_404(Document, name=slide_id)
|
||||
# derive other objects
|
||||
session = doc.session_set.all()[0]
|
||||
meeting = session.meeting
|
||||
group = session.group
|
||||
|
||||
path = get_full_path(doc)
|
||||
if path and os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
# leave it related
|
||||
#session.materials.remove(doc)
|
||||
|
||||
state = State.objects.get(type=doc.type,slug='deleted')
|
||||
doc.set_state(state)
|
||||
|
||||
# create deleted_document
|
||||
e = DocEvent.objects.create(doc=doc,
|
||||
by=request.user.person,
|
||||
type='deleted',
|
||||
desc="State set to deleted")
|
||||
|
||||
doc.save_with_history([e])
|
||||
|
||||
create_proceedings(meeting,group)
|
||||
|
||||
messages.success(request,'The material was deleted successfully')
|
||||
if group.type.slug in ('wg','rg'):
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'acronym':group.acronym})
|
||||
else:
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'session_id':session.id})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@check_permissions
|
||||
def edit_slide(request, slide_id):
|
||||
'''
|
||||
This view allows the user to edit the name of a slide.
|
||||
'''
|
||||
slide = get_object_or_404(Document, name=slide_id)
|
||||
# derive other objects
|
||||
session = slide.session_set.all()[0]
|
||||
meeting = session.meeting
|
||||
group = session.group
|
||||
|
||||
if group.type.slug in ('wg','rg'):
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'acronym':group.acronym})
|
||||
else:
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'session_id':session.id})
|
||||
|
||||
if request.method == 'POST': # If the form has been submitted...
|
||||
button_text = request.POST.get('submit', '')
|
||||
if button_text == 'Cancel':
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
form = EditSlideForm(request.POST, instance=slide) # A form bound to the POST data
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
|
||||
# rebuild proceedings.html
|
||||
create_proceedings(meeting,group)
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
form = EditSlideForm(instance=slide)
|
||||
|
||||
return render_to_response('proceedings/edit_slide.html',{
|
||||
'group': group,
|
||||
'meeting':meeting,
|
||||
'slide':slide,
|
||||
'form':form},
|
||||
RequestContext(request, {}),
|
||||
)
|
||||
|
||||
@role_required(*AUTHORIZED_ROLES)
|
||||
def main(request):
|
||||
|
@ -391,42 +263,6 @@ def main(request):
|
|||
RequestContext(request,{}),
|
||||
)
|
||||
|
||||
@check_permissions
|
||||
def move_slide(request, slide_id, direction):
|
||||
'''
|
||||
This view will re-order slides. In addition to meeting, group and slide IDs it takes
|
||||
a direction argument which is a string [up|down].
|
||||
'''
|
||||
slide = get_object_or_404(Document, name=slide_id)
|
||||
|
||||
# derive other objects
|
||||
session = slide.session_set.all()[0]
|
||||
meeting = session.meeting
|
||||
group = session.group
|
||||
qs = session.materials.exclude(states__slug='deleted').filter(type='slides').order_by('order')
|
||||
|
||||
# if direction is up and we aren't already the first slide
|
||||
if direction == 'up' and slide_id != str(qs[0].pk):
|
||||
index = find_index(slide_id, qs)
|
||||
slide_before = qs[index-1]
|
||||
slide_before.order, slide.order = slide.order, slide_before.order
|
||||
slide.save()
|
||||
slide_before.save()
|
||||
|
||||
# if direction is down, more than one slide and we aren't already the last slide
|
||||
if direction == 'down' and qs.count() > 1 and slide_id != str(qs[qs.count()-1].pk):
|
||||
index = find_index(slide_id, qs)
|
||||
slide_after = qs[index+1]
|
||||
slide_after.order, slide.order = slide.order, slide_after.order
|
||||
slide.save()
|
||||
slide_after.save()
|
||||
|
||||
if group.type.slug in ('wg','rg'):
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'acronym':group.acronym})
|
||||
else:
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'session_id':session.id})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@sec_only
|
||||
def process_pdfs(request, meeting_num):
|
||||
'''
|
||||
|
@ -554,88 +390,16 @@ def recording_edit(request, meeting_num, name):
|
|||
RequestContext(request, {}),
|
||||
)
|
||||
|
||||
@check_permissions
|
||||
def replace_slide(request, slide_id):
|
||||
'''
|
||||
This view allows the user to upload a new file to replace a slide.
|
||||
'''
|
||||
slide = get_object_or_404(Document, name=slide_id)
|
||||
# derive other objects
|
||||
session = slide.session_set.all()[0]
|
||||
meeting = session.meeting
|
||||
group = session.group
|
||||
|
||||
if group.type.slug in ('wg','rg'):
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'acronym':group.acronym})
|
||||
else:
|
||||
url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'session_id':session.id})
|
||||
|
||||
if request.method == 'POST': # If the form has been submitted...
|
||||
button_text = request.POST.get('submit', '')
|
||||
if button_text == 'Cancel':
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
form = ReplaceSlideForm(request.POST,request.FILES,instance=slide) # A form bound to the POST data
|
||||
if form.is_valid():
|
||||
new_slide = form.save(commit=False)
|
||||
new_slide.time = datetime.datetime.now()
|
||||
|
||||
file = request.FILES[request.FILES.keys()[0]]
|
||||
file_ext = os.path.splitext(file.name)[1]
|
||||
disk_filename = new_slide.name + file_ext
|
||||
handle_upload_file(file,disk_filename,meeting,'slides')
|
||||
|
||||
new_slide.external_url = disk_filename
|
||||
|
||||
# create DocEvent uploaded
|
||||
e = DocEvent.objects.create(doc=slide,
|
||||
by=request.user.person,
|
||||
type='uploaded',
|
||||
desc="Uploaded")
|
||||
new_slide.save_with_history([e])
|
||||
|
||||
post_process(new_slide)
|
||||
|
||||
# rebuild proceedings.html
|
||||
create_proceedings(meeting,group)
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
form = ReplaceSlideForm(instance=slide)
|
||||
|
||||
return render_to_response('proceedings/replace_slide.html',{
|
||||
'group': group,
|
||||
'meeting':meeting,
|
||||
'slide':slide,
|
||||
'form':form},
|
||||
RequestContext(request, {}),
|
||||
)
|
||||
|
||||
@role_required(*AUTHORIZED_ROLES)
|
||||
# TODO - should probably rename this since it's not selecting groups anymore
|
||||
def select(request, meeting_num):
|
||||
'''
|
||||
A screen to select which group you want to upload material for. Users of this view area
|
||||
Secretariat staff and community (WG Chairs, ADs, etc). Only those groups with sessions
|
||||
scheduled for the given meeting will appear in drop-downs. For Group and IRTF selects, the
|
||||
value will be group.acronym to use in pretty URLs. Since Training sessions have no acronym
|
||||
we'll use the session id.
|
||||
Provide the secretariat only functions related to meeting materials management
|
||||
'''
|
||||
if request.method == 'POST':
|
||||
if request.POST.get('group',None):
|
||||
redirect_url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting_num,'acronym':request.POST['group']})
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
else:
|
||||
messages.error(request, 'No Group selected')
|
||||
|
||||
if not has_role(request.user,'Secretariat'):
|
||||
return HttpResponseRedirect(reverse('ietf.meeting.views.materials', kwargs={'num':meeting_num}))
|
||||
|
||||
meeting = get_object_or_404(Meeting, number=meeting_num)
|
||||
user = request.user
|
||||
try:
|
||||
person = user.person
|
||||
except ObjectDoesNotExist:
|
||||
messages.warning(request, 'The account %s is not associated with any groups. If you have multiple Datatracker accounts you may try another or report a problem to ietf-action@ietf.org' % request.user)
|
||||
return HttpResponseRedirect(reverse('proceedings'))
|
||||
groups_session, groups_no_session = groups_by_session(user, meeting)
|
||||
proceedings_url = get_proceedings_url(meeting)
|
||||
|
||||
# get the time proceedings were generated
|
||||
|
@ -645,57 +409,13 @@ def select(request, meeting_num):
|
|||
else:
|
||||
last_run = None
|
||||
|
||||
# initialize group form
|
||||
wgs = filter(lambda x: x.type_id in ('wg','ag','team'),groups_session)
|
||||
group_form = GroupSelectForm(choices=build_choices(wgs))
|
||||
|
||||
# intialize IRTF form, only show if user is sec or irtf chair
|
||||
if has_role(user,'Secretariat') or person.role_set.filter(name__slug='chair',group__type__slug__in=('irtf','rg')):
|
||||
rgs = filter(lambda x: x.type_id == 'rg',groups_session)
|
||||
irtf_form = GroupSelectForm(choices=build_choices(rgs))
|
||||
else:
|
||||
irtf_form = None
|
||||
|
||||
# initialize Training form, this select widget needs to have a session id, because
|
||||
# it's utilmately the session that we associate material with
|
||||
other_groups = filter(lambda x: x.type_id not in ('wg','ag','rg'),groups_session)
|
||||
if other_groups:
|
||||
add_choices = []
|
||||
sessions = Session.objects.filter(meeting=meeting,group__in=other_groups)
|
||||
for session in sessions:
|
||||
if session.name.lower().find('plenary') != -1:
|
||||
continue
|
||||
if session.name:
|
||||
name = (session.name[:75] + '..') if len(session.name) > 75 else session.name
|
||||
add_choices.append((session.id,name))
|
||||
else:
|
||||
add_choices.append((session.id,session.group.name))
|
||||
choices = sorted(add_choices,key=lambda x: x[1])
|
||||
training_form = GroupSelectForm(choices=choices)
|
||||
else:
|
||||
training_form = None
|
||||
|
||||
# iniialize plenary form
|
||||
if has_role(user,['Secretariat','IETF Chair','IETF Trust Chair','IAB Chair','IAOC Chair','IAD']):
|
||||
ss = SchedTimeSessAssignment.objects.filter(schedule=meeting.agenda,timeslot__type='plenary')
|
||||
choices = [ (i.session.id, i.session.name) for i in sorted(ss,key=lambda x: x.session.name) ]
|
||||
plenary_form = GroupSelectForm(choices=choices)
|
||||
else:
|
||||
plenary_form = None
|
||||
|
||||
# count PowerPoint files waiting to be converted
|
||||
if has_role(user,'Secretariat'):
|
||||
ppt = Document.objects.filter(session__meeting=meeting,type='slides',external_url__endswith='.ppt').exclude(states__slug='deleted')
|
||||
pptx = Document.objects.filter(session__meeting=meeting,type='slides',external_url__endswith='.pptx').exclude(states__slug='deleted')
|
||||
ppt_count = ppt.count() + pptx.count()
|
||||
else:
|
||||
ppt_count = 0
|
||||
# TODO : This should look at SessionPresentation instead
|
||||
ppt = Document.objects.filter(session__meeting=meeting,type='slides',external_url__endswith='.ppt').exclude(states__slug='deleted')
|
||||
pptx = Document.objects.filter(session__meeting=meeting,type='slides',external_url__endswith='.pptx').exclude(states__slug='deleted')
|
||||
ppt_count = ppt.count() + pptx.count()
|
||||
|
||||
return render_to_response('proceedings/select.html', {
|
||||
'group_form': group_form,
|
||||
'irtf_form': irtf_form,
|
||||
'training_form': training_form,
|
||||
'plenary_form': plenary_form,
|
||||
'meeting': meeting,
|
||||
'last_run': last_run,
|
||||
'proceedings_url': proceedings_url,
|
||||
|
@ -703,151 +423,3 @@ def select(request, meeting_num):
|
|||
RequestContext(request,{}),
|
||||
)
|
||||
|
||||
@check_permissions
|
||||
def upload_unified(request, meeting_num, acronym=None, session_id=None):
|
||||
'''
|
||||
This view is the main view for uploading / re-ordering material for regular and interim
|
||||
meetings. There are two urls.py entries which map to this view. The acronym_id option is used
|
||||
most often for groups of regular and interim meetings. session_id is used for uploading
|
||||
material for Training sessions (where group is not a unique identifier). We could have used
|
||||
session_id all the time but this makes for an ugly URL which most of the time would be
|
||||
avoided by using acronym.
|
||||
'''
|
||||
def redirection_back(meeting, group):
|
||||
if meeting.type.slug == 'interim':
|
||||
url = reverse('proceedings')
|
||||
else:
|
||||
url = reverse('proceedings_select', kwargs={'meeting_num':meeting.number})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
meeting = get_object_or_404(Meeting, number=meeting_num)
|
||||
now = datetime.datetime.now()
|
||||
if acronym:
|
||||
group = get_object_or_404(Group, acronym=acronym)
|
||||
sessions = Session.objects.filter(meeting=meeting,group=group)
|
||||
if not sessions.exists():
|
||||
meeting_name = "IETF %s"%meeting.number if meeting.number.isdigit() else meeting.number
|
||||
messages.warning(request, 'There does not seem to be a %s session in %s.' % (group.acronym, meeting_name))
|
||||
return redirection_back(meeting, group)
|
||||
session = sessions[0]
|
||||
session_name = ''
|
||||
elif session_id:
|
||||
session = get_object_or_404(Session, id=int(session_id))
|
||||
sessions = [session]
|
||||
group = session.group
|
||||
session_name = session.name
|
||||
|
||||
if request.method == 'POST':
|
||||
button_text = request.POST.get('submit','')
|
||||
if button_text == 'Back':
|
||||
return redirection_back(meeting, group)
|
||||
form = UnifiedUploadForm(request.POST,request.FILES)
|
||||
if form.is_valid():
|
||||
material_type = form.cleaned_data['material_type']
|
||||
slide_name = form.cleaned_data['slide_name']
|
||||
|
||||
file = request.FILES[request.FILES.keys()[0]]
|
||||
file_ext = os.path.splitext(file.name)[1]
|
||||
|
||||
# set the filename
|
||||
if meeting.type.slug == 'ietf':
|
||||
filename = '%s-%s-%s' % (material_type.slug,meeting.number,group.acronym)
|
||||
elif meeting.type.slug == 'interim':
|
||||
filename = '%s-%s' % (material_type.slug,meeting.number)
|
||||
|
||||
# NonSession material, use short name for shorter URLs
|
||||
if session.short:
|
||||
filename += "-%s" % session.short
|
||||
elif session_name:
|
||||
filename += "-%s" % slugify(session_name)
|
||||
# --------------------------------
|
||||
|
||||
if material_type.slug == 'slides':
|
||||
order_num = get_next_order_num(session)
|
||||
slide_num = get_next_slide_num(session)
|
||||
filename += "-%s" % slide_num
|
||||
|
||||
disk_filename = filename + file_ext
|
||||
|
||||
# create the Document object, in the case of slides the name will always be unique
|
||||
# so you'll get a new object, agenda and minutes will reuse doc object if it exists
|
||||
doc, created = Document.objects.get_or_create(type=material_type,
|
||||
group=group,
|
||||
name=filename)
|
||||
doc.external_url = disk_filename
|
||||
doc.time = now
|
||||
if created:
|
||||
doc.rev = '1'
|
||||
else:
|
||||
doc.rev = str(int(doc.rev) + 1)
|
||||
if material_type.slug == 'slides':
|
||||
doc.order=order_num
|
||||
if slide_name:
|
||||
doc.title = slide_name
|
||||
else:
|
||||
doc.title = doc.name
|
||||
else:
|
||||
doc.title = '%s for %s at %s' % (material_type.slug.capitalize(), group.acronym.upper(), meeting)
|
||||
|
||||
DocAlias.objects.get_or_create(name=doc.name, document=doc)
|
||||
|
||||
handle_upload_file(file,disk_filename,meeting,material_type.slug)
|
||||
|
||||
# set Doc state
|
||||
if doc.type.slug=='slides':
|
||||
doc.set_state(State.objects.get(type=doc.type,slug='archived'))
|
||||
doc.set_state(State.objects.get(type='reuse_policy',slug='single'))
|
||||
else:
|
||||
doc.set_state(State.objects.get(type=doc.type,slug='active'))
|
||||
|
||||
# create session relationship, per Henrik we should associate documents to all sessions
|
||||
# for the current meeting (until tools support different materials for diff sessions)
|
||||
for s in sessions:
|
||||
try:
|
||||
sp = s.sessionpresentation_set.get(document=doc)
|
||||
sp.rev = doc.rev
|
||||
sp.save()
|
||||
except ObjectDoesNotExist:
|
||||
s.sessionpresentation_set.create(document=doc,rev=doc.rev)
|
||||
|
||||
# create NewRevisionDocEvent instead of uploaded, per Ole
|
||||
e = NewRevisionDocEvent.objects.create(type='new_revision',
|
||||
by=request.user.person,
|
||||
doc=doc,
|
||||
rev=doc.rev,
|
||||
desc='New revision available')
|
||||
|
||||
doc.save_with_history([e])
|
||||
|
||||
post_process(doc)
|
||||
create_proceedings(meeting,group)
|
||||
messages.success(request,'File uploaded sucessfully')
|
||||
|
||||
else:
|
||||
form = UnifiedUploadForm(initial={'meeting_id':meeting.id,'acronym':group.acronym,'material_type':'slides'})
|
||||
|
||||
materials = get_materials(group,meeting)
|
||||
|
||||
# gather DocEvents
|
||||
# include deleted material to catch deleted doc events
|
||||
#docs = session.materials.all()
|
||||
# Don't report on draft DocEvents since the secr/materials app isn't managing them
|
||||
docs = session.materials.exclude(type='draft')
|
||||
docevents = DocEvent.objects.filter(doc__in=docs)
|
||||
|
||||
path = get_proceedings_path(meeting,group)
|
||||
if os.path.exists(path):
|
||||
proceedings_url = get_proceedings_url(meeting,group)
|
||||
else:
|
||||
proceedings_url = ''
|
||||
|
||||
return render_to_response('proceedings/upload_unified.html', {
|
||||
'docevents': docevents,
|
||||
'meeting': meeting,
|
||||
'group': group,
|
||||
'materials': materials,
|
||||
'form': form,
|
||||
'session_name': session_name, # for Tutorials, etc
|
||||
'proceedings_url': proceedings_url},
|
||||
RequestContext(request, {}),
|
||||
)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<div class="button-group">
|
||||
<ul>
|
||||
<li><button type="submit" name="submit" value="Submit">Submit</button></li>
|
||||
<li><button type="submit" name="submit" value="Back">Back</button></li>
|
||||
</ul>
|
||||
</div> <!-- button-group -->
|
|
@ -1,25 +0,0 @@
|
|||
<h2>Activies Log</h2>
|
||||
<div class="inline-related last-related">
|
||||
<table class="full-width">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Document</th>
|
||||
<th>Action</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in docevents %}
|
||||
<tr class="{% cycle 'row1' 'row2' %}">
|
||||
<td>{{ entry.time|date:"M d, Y" }}</td>
|
||||
<td>{{ entry.time|date:"H:i" }}</td>
|
||||
<td>{{ entry.doc }}</td>
|
||||
<td>{{ entry.type }}</td>
|
||||
<td>{{ entry.by }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <!-- inline-related -->
|
|
@ -1,25 +0,0 @@
|
|||
{% load ams_filters %}
|
||||
|
||||
<table id="slides" class="center sortable" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Slide</th>
|
||||
<th>Filename</th>
|
||||
<th>Edit</th>
|
||||
<th>Replace</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% 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>
|
||||
<td><a href="{% url "proceedings_edit_slide" slide_id=slide.pk %}">Edit</a></td>
|
||||
<td><a href="{% url "proceedings_replace_slide" slide_id=slide.pk %}">Replace</a></td>
|
||||
<td><a href="{% url "proceedings_delete_material" slide_id=slide.name %}">Delete</a></td>
|
||||
<td class="hidden">{{ slide.pk }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
|
@ -1,3 +1,5 @@
|
|||
<li><a href="https://www.ietf.org/instructions/meeting_materials_tool.html" target="_blank">Instructions</a>.</li>
|
||||
<li>If you require assistance in using this tool, or wish to report a bug, then please send a message to <a href="mailto:ietf-action@ietf.org">ietf-action@ietf.org</a>.</li>
|
||||
<li>To submit your materials via email, please send agendas to <a href="mailto:agenda@ietf.org">agenda@ietf.org</a> and minutes/presentation slides to <a href="mailto:proceedings@ietf.org">proceedings@ietf.org</a>.</li>
|
||||
<li><bold>Note:</bold> Normal session materials materials management is now performed using the {% if meeting.number %}<a href="{% url 'ietf.meeting.views.materials' num=meeting.number %}">{% endif %}materials page{% if meeting.number %}</a>{% endif %}
|
||||
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
{% extends "base_site.html" %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}Edit Slide{% endblock %}
|
||||
|
||||
{% block extrahead %}{{ block.super }}
|
||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}{{ block.super }}
|
||||
{% if meeting.type_id == "interim" %}
|
||||
» <a href="{% url "proceedings" %}">Proceedings</a>
|
||||
» <a href="{% url "proceedings_upload_unified" meeting_num=meeting.number acronym=group.acronym %}">{{ meeting }}</a>
|
||||
» {{ slide.title }}
|
||||
{% else %}
|
||||
» <a href="{% url "proceedings" %}">Proceedings</a>
|
||||
» <a href="{% url "proceedings_select" meeting_num=meeting.number %}">Select</a>
|
||||
» <a href="{% url "proceedings_upload_unified" meeting_num=meeting.number acronym=group.acronym%}">{{ group.acronym }}</a>
|
||||
» {{ slide.title }}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="module interim-container">
|
||||
<h2>Working Group - {{ group.acronym }}</h2>
|
||||
<p><h3>Edit Slide:</h3></p>
|
||||
<form enctype="multipart/form-data" action="." method="post">{% csrf_token %}
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
|
||||
{% include "includes/buttons_save_cancel.html" %}
|
||||
|
||||
</form>
|
||||
</div> <!-- module -->
|
||||
|
||||
{% endblock %}
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
<tr class = "{% cycle 'row1' 'row2' %}">
|
||||
<td>{{ meeting.group.acronym }}</td>
|
||||
<td><a href="{% url "proceedings_upload_unified" meeting_num=meeting.number acronym=meeting.group.acronym %}">{{ meeting.date }}</a></td>
|
||||
<td><a href="{% url "ietf.meeting.views.session_details" num=meeting.number acronym=meeting.group.acronym %}">{{ meeting.date }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
{% extends "base_site.html" %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}Replace Slide{% endblock %}
|
||||
|
||||
{% block extrahead %}{{ block.super }}
|
||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}{{ block.super }}
|
||||
{% if meeting.type_id == "interim" %}
|
||||
» <a href="{% url "proceedings" %}">Proceedings</a>
|
||||
» <a href="{% url "proceedings_upload_unified" meeting_num=meeting.number acronym=group.acronym %}">{{ meeting }}</a>
|
||||
» {{ slide.title }}
|
||||
{% else %}
|
||||
» <a href="{% url "proceedings" %}">Proceedings</a>
|
||||
» <a href="{% url "proceedings_select" meeting_num=meeting.number %}">Select</a>
|
||||
» <a href="{% url "proceedings_upload_unified" meeting_num=meeting.number acronym=group.acronym %}">{{ group.acronym }}</a>
|
||||
» {{ slide.title }}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="module interim-container">
|
||||
<h2>Working Group - {{ group.acronym }}</h2>
|
||||
<p><h3>Replace Slide:</h3></p>
|
||||
<form enctype="multipart/form-data" action="." method="post">{% csrf_token %}
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
|
||||
{% include "includes/buttons_save_cancel.html" %}
|
||||
|
||||
</form>
|
||||
</div> <!-- module -->
|
||||
|
||||
{% endblock %}
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
{% block breadcrumbs %}{{ block.super }}
|
||||
» <a href="{% url "proceedings" %}">Proceedings</a>
|
||||
» {{ meeting.number }} - Select Group
|
||||
» {{ meeting.number }}
|
||||
{% endblock %}
|
||||
|
||||
{% block instructions %}
|
||||
|
@ -39,49 +39,7 @@
|
|||
{% block content %}
|
||||
|
||||
<div class="module interim-container">
|
||||
<h2>IETF {{ meeting.number }} - Upload Material</span></h2>
|
||||
<div class="inline-related">
|
||||
<h3><b>Select Group</b></h3>
|
||||
<p>The list below includes those working groups and approved BOFs that are scheduled to
|
||||
meet at IETF {{meeting.number }}. You must request a session slot in order for your group(s) to appear on
|
||||
this list.</p>
|
||||
<p>- To request a session slot for a working group, please use the
|
||||
<a href="{% url "sessions" %}">IETF Meeting Session Request Tool</a>.
|
||||
<br>
|
||||
- To request a session slot for a BOF, please send a message to <a href="mailto:ietf-action@ietf.org">agenda@ietf.org</a>.
|
||||
Additional information is available at
|
||||
<a href="https://www.ietf.org/instructions/MTG-SLOTS.html">"Requesting Meeting Slots at IETF Meetings."</a>
|
||||
<br>
|
||||
- To upload meeting materials for a scheduled session, please select the session name below.</p>
|
||||
<form class="internal-form" action="" method="post">{% csrf_token %}
|
||||
<label for="id_group">Working Groups</label>
|
||||
{{ group_form.group }}
|
||||
<input type="submit" name="submit" value="Select" />
|
||||
</form>
|
||||
{% if irtf_form %}
|
||||
<form class="internal-form" action="" method="post">{% csrf_token %}
|
||||
<label for="id_group">IRTF Groups</label>
|
||||
{{ irtf_form.group }}
|
||||
<input type="submit" name="submit" value="Select" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if training_form %}
|
||||
<form class="internal-form" action="" method="post">{% csrf_token %}
|
||||
<label for="id_group">Training / Other</label>
|
||||
{{ training_form.group }}
|
||||
<input type="submit" name="submit" value="Select" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if plenary_form %}
|
||||
<form class="internal-form" action="" method="post">{% csrf_token %}
|
||||
<label for="id_group">Plenaries</label>
|
||||
{{ plenary_form.group }}
|
||||
<input type="submit" name="submit" value="Select" />
|
||||
</form>
|
||||
{% endif %}
|
||||
</div> <!-- inline-related -->
|
||||
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<div class="inline-related">
|
||||
<h2>Secretariat Only Functions</h2>
|
||||
<div id="private-functions">
|
||||
|
@ -90,7 +48,6 @@
|
|||
|
||||
</div> <!-- private-functions -->
|
||||
</div> <!-- inline-group -->
|
||||
{% endif %}
|
||||
|
||||
</div> <!-- module -->
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
{% extends "base_site.html" %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}Proceedings - Upload Presentations {% endblock %}
|
||||
|
||||
{% block extrahead %}{{ block.super }}
|
||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}{{ block.super }}
|
||||
» <a href="../../../">Proceedings</a>
|
||||
» <a href="../../">{{ meeting.meeting_num }}</a>
|
||||
» <a href="../../convert">Convert Material</a>
|
||||
» Upload Presentation
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="module">
|
||||
<form enctype="multipart/form-data" action="" method="post">{% csrf_token %}
|
||||
<h2>Proceedings - Upload (HTML-Zipped) Presentation : <font color="RED">{{ slide.group_name }}</font></h2>
|
||||
<p>For Presentation : {{ slide.slide_name }}</p>
|
||||
<table>
|
||||
{{ upload_presentation.as_table }}
|
||||
</table>
|
||||
<div class="button-group">
|
||||
<ul>
|
||||
<li><input type="submit" value="Upload" class="standard" /></li>
|
||||
<!--li><input type="submit" value="Cancel" class="standard" /></li-->
|
||||
</ul>
|
||||
</div> <!-- button-group -->
|
||||
</form>
|
||||
</div> <!-- module -->
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
{% extends "base_site.html" %}
|
||||
{% load ietf_filters %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}Proceedings{% endblock %}
|
||||
|
||||
{% block extrastyle %}{{ block.super }}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'secr/css/jquery-ui-1.11.4.custom.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block extrahead %}{{ block.super }}
|
||||
<script type="text/javascript" src="{% static 'secr/js/jquery-ui-1.11.4.custom.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}{{ block.super }}
|
||||
|
||||
{% if meeting.type_id == "interim" %}
|
||||
» <a href="{% url "proceedings" %}">Proceedings</a>
|
||||
» {{ meeting }}
|
||||
{% else %}
|
||||
» <a href="{% url "proceedings" %}">Proceedings</a>
|
||||
» <a href="{% url "proceedings_select" meeting_num=meeting.number %}">{{ meeting }}</a>
|
||||
» {% if session_name %}{{ session_name }}{% else %}{{ group.acronym }}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="module interim-container">
|
||||
<h2>{{ meeting }} - Upload Material - {% if session_name %}{{ session_name }}{% else %}Group: {{ group.acronym }}{% endif %}
|
||||
</h2>
|
||||
<table class="center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Filename</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
{% if proceedings_url %}
|
||||
<td><a href="{{ proceedings_url|safe }}" target="_blank">Proceedings</a></td>
|
||||
<td>proceedings.html</td>
|
||||
{% else %}
|
||||
<td>Proceedings</td>
|
||||
<td>Proceedings not yet generated</td>
|
||||
{% endif %}
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
{% 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>
|
||||
<td></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
{% 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>
|
||||
<td></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% if materials.bluesheets %}
|
||||
{% for item in materials.bluesheets %}
|
||||
<tr>
|
||||
<td><a href="{{ item.get_absolute_url }}" target="_blank">Bluesheet</a></td>
|
||||
<td>{{ item.external_url }}</td>
|
||||
<td>{% if user|has_role:"Secretariat" %}<a href="{% url "proceedings_delete_material" slide_id=item.name %}">Delete</a>{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="inline-related">
|
||||
<h2>Slides <span class="highlight">NEW! Drag and drop to re-order slides</span></h2>
|
||||
{% include "includes/slides.html" %}
|
||||
<p>(<span class="required"> *</span> - Waiting to be converted to PDF format.)</p>
|
||||
</div> <!-- inline-group -->
|
||||
|
||||
<div class="inline-related">
|
||||
<h2>Upload Materials</h2>
|
||||
<form id="upload_materials_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> <!-- 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 %}
|
|
@ -15,9 +15,7 @@
|
|||
<td>
|
||||
{% ifchanged s.meeting %}
|
||||
{% if s.meeting.type.slug == 'ietf' %}
|
||||
<a href="{% url 'ietf.meeting.views.agenda' num=s.meeting.number %}">
|
||||
IETF {{s.meeting.number}}
|
||||
</a>
|
||||
IETF {{s.meeting.number}}
|
||||
{% else %}
|
||||
{{s.meeting.number}}
|
||||
{% endif %}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
{% load ietf_filters session_filters %}
|
||||
{% if user|has_role:"Secretariat" or session|can_manage_materials:user and not session.is_material_submission_cutoff %}
|
||||
<a class="button btn-default btn-sm" href="{% url 'ietf.meeting.views.session_details' num=session.meeting.number acronym=session.group.acronym %}">Edit</a>
|
||||
{% with gt=session.group.type_id %}
|
||||
<a class="button btn-default btn-sm" href="{% url 'ietf.meeting.views.session_details' num=session.meeting.number acronym=session.group.acronym %}{% if gt == 'wg' or gt == 'rg' or gt == 'ag' %}{% else %}#session_{{session.pk}}{% endif %}">Edit</a>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
{% endif %}
|
||||
|
||||
<p>
|
||||
<a class="btn btn-default" href="{% url "proceedings" %}">Meeting materials manager</a>
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<a class="btn btn-default" href="{% url "proceedings" %}">Secretariat proceedings functions</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-default" href="/meeting/{{meeting_num}}/requests">Meeting requests/conflicts</a>
|
||||
</p>
|
||||
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
{% endif %}
|
||||
</h1>
|
||||
|
||||
<p class="alert alert-info">
|
||||
<b>This page is under construction</b>
|
||||
</p>
|
||||
{% if meeting.number|add:0 <= 96 %}
|
||||
<p class="alert alert-info">
|
||||
<b>These are not the official proceedings for IETF{{meeting.number}}. This page shows what would be generated by the new automatic proceedings generator for that meeting. The official proceedings are located at <a href="https://www.ietf.org/proceedings/{{meeting.number}}">https://www.ietf.org/proceedings/{{meeting.number}}</a></b>
|
||||
|
|
31
ietf/templates/meeting/remove_sessionpresentation.html
Normal file
31
ietf/templates/meeting/remove_sessionpresentation.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Remove {{sp.document}} from session{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Confirm removing document from session {{sp.session}}</h1>
|
||||
|
||||
{% if sp.session.is_material_submission_cutoff %}
|
||||
<p class="alert alert-warning">The deadline for submission corrections has passed. This may affect published proceedings.</p>
|
||||
{% endif %}
|
||||
|
||||
<h2>Document</h2>
|
||||
<p><strong>{{sp.document.name}}{% if sp.rev %}-{{sp.rev}}{% else %} (current version){% endif %}</strong></p>
|
||||
<p>{{sp.document.title}}</p>
|
||||
<h2>Session</h2>
|
||||
<p>{{sp.session}}</p>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% buttons %}
|
||||
<button type="submit" class="btn btn-{% if sp.session.is_material_submission_cutoff %}warning{% else %}primary{% endif %}" name="remove_session">Remove document from session</button>
|
||||
<a class="btn btn-default href="{% url 'ietf.meeting.views.session_details' num=sp.session.meeting.number acronym=sp.session.group.acronym%}">Cancel</a>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -1,106 +1,196 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin ietf_filters %}
|
||||
{% load origin ietf_filters staticfiles %}
|
||||
|
||||
{% block title %}{{ meeting }} : {{ acronym }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.ui-sortable tr {
|
||||
cursor:pointer;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>{{ meeting }} : {{ acronym }}</h1>
|
||||
|
||||
{% for session in sessions %}
|
||||
<h2>{% if sessions|length > 1 %}Session {{ forloop.counter }} : {% endif %}{{ session.time }}{% if session.name %} : {{ session.name }}{% endif %}</h2>
|
||||
<h2 class="anchor-target" id="session_{{session.pk}}">{% 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">Agenda, Minutes, and Bluesheets</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="{{pres.document.get_absolute_url}}">{{pres.document.title}}</a>
|
||||
<a href="{{url}}">({{ 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" data-toggle="tooltip" title="Drag and drop to reorder slides">Slides</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped" id="slides">
|
||||
<tbody>
|
||||
{% for pres in session.filtered_slides %}
|
||||
<tr data-order="{{pres.order}}" data-url="{% url 'ietf.meeting.views.set_slide_order' session_id=session.pk num=session.meeting.number name=pres.document.name %}">
|
||||
{% 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="{{pres.document.get_absolute_url}}">{{pres.document.title}} </a>
|
||||
<a href="{{url}}">({{ 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>
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Remove</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</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>
|
||||
{% if can_manage_materials %}
|
||||
<div class="panel-footer small">Drag-and-drop to reorder slides</div>
|
||||
{% endif %}
|
||||
</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>
|
||||
{% if can_manage_materials %}
|
||||
<td class="col-md-2">
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Remove</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</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 %}
|
||||
|
||||
{# TODO don't rely on secr/js version of jquery-ui #}
|
||||
{# Sorting based loosely on the original secr upload sorting and on http://www.avtex.com/blog/2015/01/27/drag-and-drop-sorting-of-table-rows-in-priority-order/ #}
|
||||
{% block js %}
|
||||
{% if can_manage_materials %}
|
||||
<script type="text/javascript" src="{% static 'jquery/jquery.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'secr/js/jquery-ui-1.11.4.custom.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'jquery.cookie/jquery.cookie.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$.ajaxSetup({
|
||||
crossDomain: false,
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type)) {
|
||||
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
var rowWidthHelper = function (e, tr) {
|
||||
var $originals = tr.children();
|
||||
var $helper = tr.clone();
|
||||
$helper.children().each(function(index)
|
||||
{
|
||||
$(this).width($originals.eq(index).width())
|
||||
});
|
||||
return $helper;
|
||||
};
|
||||
|
||||
$("#slides tbody").sortable({
|
||||
helper: rowWidthHelper,
|
||||
stop: function(event,ui) {adjustDatabase("#slides")}
|
||||
}).disableSelection();
|
||||
});
|
||||
|
||||
function adjustDatabase(tableID) {
|
||||
$(tableID + " tr").each(function() {
|
||||
count = $(this).parent().children().index($(this)) + 1;
|
||||
old_order = $(this).attr("data-order");
|
||||
if ( count != old_order ) {
|
||||
$(this).attr("data-order", count);
|
||||
$.post($(this).attr("data-url"),{'order':count});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endif %}
|
||||
{% 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