Allow slides drag-drop between sessions for groups meeting with multiple sessions. Fixes #2700. Commit ready to merge.
- Legacy-Id: 17024
This commit is contained in:
parent
34f93932a2
commit
1016b3a514
2
ietf/externals/static/Sortable/Sortable.min.js
vendored
Normal file
2
ietf/externals/static/Sortable/Sortable.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -23,6 +23,7 @@ from django.urls import reverse as urlreverse
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import Client
|
||||
from django.db.models import F
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
|
@ -34,7 +35,7 @@ from ietf.meeting.helpers import send_interim_cancellation_notice
|
|||
from ietf.meeting.helpers import send_interim_minutes_reminder, populate_important_dates, update_important_dates
|
||||
from ietf.meeting.models import Session, TimeSlot, Meeting, SchedTimeSessAssignment, Schedule, SessionPresentation, SlideSubmission
|
||||
from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting
|
||||
from ietf.meeting.utils import finalize
|
||||
from ietf.meeting.utils import finalize, condition_slide_order
|
||||
from ietf.name.models import SessionStatusName, ImportantDateName
|
||||
from ietf.utils.decorators import skip_coverage
|
||||
from ietf.utils.mail import outbox, empty_outbox
|
||||
|
@ -569,18 +570,330 @@ class MeetingTests(TestCase):
|
|||
self.assertEqual(response.status_code,200)
|
||||
self.assertEqual(response.get('Content-Type'), 'text/calendar')
|
||||
|
||||
def test_edit_slide_order(self):
|
||||
session=SessionFactory(meeting__type_id='iestf',type_id='session')
|
||||
slides = DocumentFactory(type_id='slides')
|
||||
session.sessionpresentation_set.create(document=slides,order=0)
|
||||
url = urlreverse('ietf.meeting.views.set_slide_order',kwargs={'session_id':session.id,'num':session.meeting.number,'name':slides.name})
|
||||
response = self.client.put(url,{'order':2})
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.client.login(username='secretary', password='secretary+password')
|
||||
response = self.client.post(url,{'order':'2'})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.get('Content-Type'), 'application/json')
|
||||
self.assertEqual(session.sessionpresentation_set.first().order,2)
|
||||
class ReorderSlidesTests(TestCase):
|
||||
|
||||
def test_add_slides_to_session(self):
|
||||
for type_id in ('ietf','interim'):
|
||||
chair_role = RoleFactory(name_id='chair')
|
||||
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90), meeting__type_id=type_id)
|
||||
slides = DocumentFactory(type_id='slides')
|
||||
url = urlreverse('ietf.meeting.views.ajax_add_slides_to_session', kwargs={'session_id':session.pk, 'num':session.meeting.number})
|
||||
|
||||
# Not a valid user
|
||||
r = self.client.post(url, {'order':1, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.assertIn('have permission', unicontent(r))
|
||||
|
||||
self.client.login(username=chair_role.person.user.username, password=chair_role.person.user.username+"+password")
|
||||
|
||||
# Past submission cutoff
|
||||
r = self.client.post(url, {'order':0, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.assertIn('materials cutoff', unicontent(r))
|
||||
|
||||
session.meeting.date = datetime.date.today()
|
||||
session.meeting.save()
|
||||
|
||||
# Invalid order
|
||||
r = self.client.post(url, {})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('No data',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'garbage':'garbage'})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('order is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'order':0, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('order is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'order':2, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('order is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'order':'garbage', 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('order is not valid',r.json()['error'])
|
||||
|
||||
# Invalid name
|
||||
r = self.client.post(url, {'order':1 })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('name is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'order':1, 'name':'garbage' })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('name is not valid',r.json()['error'])
|
||||
|
||||
# Valid post
|
||||
r = self.client.post(url, {'order':1, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(session.sessionpresentation_set.count(),1)
|
||||
|
||||
# Ingore a request to add slides that are already in a session
|
||||
r = self.client.post(url, {'order':1, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(session.sessionpresentation_set.count(),1)
|
||||
|
||||
|
||||
session2 = SessionFactory(group=session.group, meeting=session.meeting)
|
||||
SessionPresentationFactory.create_batch(3, document__type_id='slides', session=session2)
|
||||
for num, sp in enumerate(session2.sessionpresentation_set.filter(document__type_id='slides'),start=1):
|
||||
sp.order = num
|
||||
sp.save()
|
||||
|
||||
url = urlreverse('ietf.meeting.views.ajax_add_slides_to_session', kwargs={'session_id':session2.pk, 'num':session2.meeting.number})
|
||||
|
||||
more_slides = DocumentFactory.create_batch(3, type_id='slides')
|
||||
|
||||
# Insert at beginning
|
||||
r = self.client.post(url, {'order':1, 'name':more_slides[0].name})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(session2.sessionpresentation_set.get(document=more_slides[0]).order,1)
|
||||
self.assertEqual(list(session2.sessionpresentation_set.order_by('order').values_list('order',flat=True)), range(1,5))
|
||||
|
||||
# Insert at end
|
||||
r = self.client.post(url, {'order':5, 'name':more_slides[1].name})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(session2.sessionpresentation_set.get(document=more_slides[1]).order,5)
|
||||
self.assertEqual(list(session2.sessionpresentation_set.order_by('order').values_list('order',flat=True)), range(1,6))
|
||||
|
||||
# Insert in middle
|
||||
r = self.client.post(url, {'order':3, 'name':more_slides[2].name})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(session2.sessionpresentation_set.get(document=more_slides[2]).order,3)
|
||||
self.assertEqual(list(session2.sessionpresentation_set.order_by('order').values_list('order',flat=True)), range(1,7))
|
||||
|
||||
def test_remove_slides_from_session(self):
|
||||
for type_id in ['ietf','interim']:
|
||||
chair_role = RoleFactory(name_id='chair')
|
||||
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90), meeting__type_id=type_id)
|
||||
slides = DocumentFactory(type_id='slides')
|
||||
url = urlreverse('ietf.meeting.views.ajax_remove_slides_from_session', kwargs={'session_id':session.pk, 'num':session.meeting.number})
|
||||
|
||||
# Not a valid user
|
||||
r = self.client.post(url, {'oldIndex':1, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.assertIn('have permission', unicontent(r))
|
||||
|
||||
self.client.login(username=chair_role.person.user.username, password=chair_role.person.user.username+"+password")
|
||||
|
||||
# Past submission cutoff
|
||||
r = self.client.post(url, {'oldIndex':0, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.assertIn('materials cutoff', unicontent(r))
|
||||
|
||||
session.meeting.date = datetime.date.today()
|
||||
session.meeting.save()
|
||||
|
||||
# Invalid order
|
||||
r = self.client.post(url, {})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('No data',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'garbage':'garbage'})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('index is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'oldIndex':0, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('index is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'oldIndex':'garbage', 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('index is not valid',r.json()['error'])
|
||||
|
||||
# No matching thing to delete
|
||||
r = self.client.post(url, {'oldIndex':1, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('index is not valid',r.json()['error'])
|
||||
|
||||
session.sessionpresentation_set.create(document=slides, rev=slides.rev, order=1)
|
||||
|
||||
# Bad names
|
||||
r = self.client.post(url, {'oldIndex':1})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('name is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'oldIndex':1, 'name':'garbage' })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('name is not valid',r.json()['error'])
|
||||
|
||||
slides2 = DocumentFactory(type_id='slides')
|
||||
|
||||
# index/name mismatch
|
||||
r = self.client.post(url, {'oldIndex':1, 'name':slides2.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('SessionPresentation not found',r.json()['error'])
|
||||
|
||||
session.sessionpresentation_set.create(document=slides2, rev=slides2.rev, order=2)
|
||||
r = self.client.post(url, {'oldIndex':1, 'name':slides2.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('Name does not match index',r.json()['error'])
|
||||
|
||||
# valid removal
|
||||
r = self.client.post(url, {'oldIndex':1, 'name':slides.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(session.sessionpresentation_set.count(),1)
|
||||
|
||||
session2 = SessionFactory(group=session.group, meeting=session.meeting)
|
||||
sp_list = SessionPresentationFactory.create_batch(5, document__type_id='slides', session=session2)
|
||||
for num, sp in enumerate(session2.sessionpresentation_set.filter(document__type_id='slides'),start=1):
|
||||
sp.order = num
|
||||
sp.save()
|
||||
|
||||
url = urlreverse('ietf.meeting.views.ajax_remove_slides_from_session', kwargs={'session_id':session2.pk, 'num':session2.meeting.number})
|
||||
|
||||
# delete at first of list
|
||||
r = self.client.post(url, {'oldIndex':1, 'name':sp_list[0].document.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertFalse(session2.sessionpresentation_set.filter(pk=sp_list[0].pk).exists())
|
||||
self.assertEqual(list(session2.sessionpresentation_set.order_by('order').values_list('order',flat=True)), range(1,5))
|
||||
|
||||
# delete in middle of list
|
||||
r = self.client.post(url, {'oldIndex':4, 'name':sp_list[4].document.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertFalse(session2.sessionpresentation_set.filter(pk=sp_list[4].pk).exists())
|
||||
self.assertEqual(list(session2.sessionpresentation_set.order_by('order').values_list('order',flat=True)), range(1,4))
|
||||
|
||||
# delete at end of list
|
||||
r = self.client.post(url, {'oldIndex':2, 'name':sp_list[2].document.name })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertFalse(session2.sessionpresentation_set.filter(pk=sp_list[2].pk).exists())
|
||||
self.assertEqual(list(session2.sessionpresentation_set.order_by('order').values_list('order',flat=True)), range(1,3))
|
||||
|
||||
|
||||
def test_reorder_slides_in_session(self):
|
||||
chair_role = RoleFactory(name_id='chair')
|
||||
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90))
|
||||
sp_list = SessionPresentationFactory.create_batch(5, document__type_id='slides', session=session)
|
||||
for num, sp in enumerate(sp_list, start=1):
|
||||
sp.order = num
|
||||
sp.save()
|
||||
url = urlreverse('ietf.meeting.views.ajax_reorder_slides_in_session', kwargs={'session_id':session.pk, 'num':session.meeting.number})
|
||||
|
||||
for type_id in ['ietf','interim']:
|
||||
|
||||
session.meeting.type_id = type_id
|
||||
session.meeting.date = datetime.date.today()-datetime.timedelta(days=90)
|
||||
session.meeting.save()
|
||||
|
||||
# Not a valid user
|
||||
r = self.client.post(url, {'oldIndex':1, 'newIndex':2 })
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.assertIn('have permission', unicontent(r))
|
||||
|
||||
self.client.login(username=chair_role.person.user.username, password=chair_role.person.user.username+"+password")
|
||||
|
||||
# Past submission cutoff
|
||||
r = self.client.post(url, {'oldIndex':1, 'newIndex':2 })
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.assertIn('materials cutoff', unicontent(r))
|
||||
|
||||
session.meeting.date = datetime.date.today()
|
||||
session.meeting.save()
|
||||
|
||||
# Bad index values
|
||||
r = self.client.post(url, {'oldIndex':0, 'newIndex':2 })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('index is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'oldIndex':2, 'newIndex':6 })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('index is not valid',r.json()['error'])
|
||||
|
||||
r = self.client.post(url, {'oldIndex':2, 'newIndex':2 })
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],False)
|
||||
self.assertIn('index is not valid',r.json()['error'])
|
||||
|
||||
# Move from beginning
|
||||
r = self.client.post(url, {'oldIndex':1, 'newIndex':3})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('pk',flat=True)),[2,3,1,4,5])
|
||||
|
||||
# Move to beginning
|
||||
r = self.client.post(url, {'oldIndex':3, 'newIndex':1})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('pk',flat=True)),[1,2,3,4,5])
|
||||
|
||||
# Move from end
|
||||
r = self.client.post(url, {'oldIndex':5, 'newIndex':3})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('pk',flat=True)),[1,2,5,3,4])
|
||||
|
||||
# Move to end
|
||||
r = self.client.post(url, {'oldIndex':3, 'newIndex':5})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('pk',flat=True)),[1,2,3,4,5])
|
||||
|
||||
# Move beginning to end
|
||||
r = self.client.post(url, {'oldIndex':1, 'newIndex':5})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('pk',flat=True)),[2,3,4,5,1])
|
||||
|
||||
# Move middle to middle
|
||||
r = self.client.post(url, {'oldIndex':3, 'newIndex':4})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('pk',flat=True)),[2,3,5,4,1])
|
||||
|
||||
r = self.client.post(url, {'oldIndex':3, 'newIndex':2})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.json()['success'],True)
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('pk',flat=True)),[2,5,3,4,1])
|
||||
|
||||
# Reset for next iteration in the loop
|
||||
session.sessionpresentation_set.update(order=F('pk'))
|
||||
self.client.logout()
|
||||
|
||||
|
||||
def test_slide_order_reconditioning(self):
|
||||
chair_role = RoleFactory(name_id='chair')
|
||||
session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90))
|
||||
sp_list = SessionPresentationFactory.create_batch(5, document__type_id='slides', session=session)
|
||||
for num, sp in enumerate(sp_list, start=1):
|
||||
sp.order = 2*num
|
||||
sp.save()
|
||||
|
||||
try:
|
||||
condition_slide_order(session)
|
||||
except AssertionError:
|
||||
pass
|
||||
|
||||
self.assertEqual(list(session.sessionpresentation_set.order_by('order').values_list('order',flat=True)),range(1,6))
|
||||
|
||||
|
||||
class EditTests(TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
# Copyright The IETF Trust 2007-2019, All Rights Reserved
|
||||
|
||||
from django.conf.urls import include
|
||||
from django.views.generic import RedirectView
|
||||
|
@ -15,7 +15,9 @@ safe_for_all_meeting_types = [
|
|||
url(r'^session/(?P<session_id>\d+)/agenda$', views.upload_session_agenda),
|
||||
url(r'^session/(?P<session_id>\d+)/propose_slides$', views.propose_session_slides),
|
||||
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+)/add_to_session$', views.ajax_add_slides_to_session),
|
||||
url(r'^session/(?P<session_id>\d+)/remove_from_session$', views.ajax_remove_slides_from_session),
|
||||
url(r'^session/(?P<session_id>\d+)/reorder_in_session$', views.ajax_reorder_slides_in_session),
|
||||
url(r'^session/(?P<session_id>\d+)/doc/%(name)s/remove$' % settings.URL_REGEXPS, views.remove_sessionpresentation),
|
||||
url(r'^session/(?P<session_id>\d+)\.ics$', views.ical_agenda),
|
||||
url(r'^sessions/(?P<acronym>[-a-z0-9]+)\.ics$', views.ical_agenda),
|
||||
|
|
|
@ -19,6 +19,7 @@ from ietf.meeting.models import Session, Meeting
|
|||
from ietf.group.utils import can_manage_materials
|
||||
from ietf.person.models import Email
|
||||
from ietf.secr.proceedings.proc_utils import import_audio_files
|
||||
from ietf.utils.log import unreachable
|
||||
|
||||
def group_sessions(sessions):
|
||||
|
||||
|
@ -178,3 +179,15 @@ def sort_accept_tuple(accept):
|
|||
tup.append((keys[0], q))
|
||||
return sorted(tup, key = lambda x: float(x[1]), reverse = True)
|
||||
return tup
|
||||
|
||||
|
||||
|
||||
def condition_slide_order(session):
|
||||
qs = session.sessionpresentation_set.filter(document__type_id='slides').order_by('order')
|
||||
order_list = qs.values_list('order',flat=True)
|
||||
#assertion('list(order_list) == range(1,qs.count()+1)')
|
||||
if list(order_list) != range(1,qs.count()+1):
|
||||
for num, sp in enumerate(qs, start=1):
|
||||
sp.order=num
|
||||
sp.save()
|
||||
unreachable('2019-11-15')
|
||||
|
|
|
@ -34,7 +34,7 @@ from django.contrib.auth.decorators import login_required
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import URLValidator
|
||||
from django.urls import reverse,reverse_lazy
|
||||
from django.db.models import Min, Max, Q
|
||||
from django.db.models import Min, Max, Q, F
|
||||
from django.forms.models import modelform_factory, inlineformset_factory
|
||||
from django.template import TemplateDoesNotExist
|
||||
from django.template.loader import render_to_string
|
||||
|
@ -67,8 +67,7 @@ from ietf.meeting.helpers import sessions_post_save, is_meeting_approved
|
|||
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.meeting.utils import sort_accept_tuple
|
||||
from ietf.meeting.utils import finalize, sort_accept_tuple, condition_slide_order
|
||||
from ietf.message.utils import infer_message
|
||||
from ietf.secr.proceedings.utils import handle_upload_file
|
||||
from ietf.secr.proceedings.proc_utils import (get_progress_stats, post_process, import_audio_files,
|
||||
|
@ -1663,11 +1662,9 @@ def remove_sessionpresentation(request, session_id, num, name):
|
|||
|
||||
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
|
||||
def ajax_add_slides_to_session(request, session_id, num):
|
||||
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"):
|
||||
|
@ -1675,19 +1672,109 @@ def set_slide_order(request, session_id, num, name):
|
|||
|
||||
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:
|
||||
except (ValueError, TypeError):
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied order is not valid' }),content_type='application/json')
|
||||
if order <=0 or order > 32767 :
|
||||
if order < 1 or order > session.sessionpresentation_set.filter(document__type_id='slides').count() + 1 :
|
||||
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
|
||||
name = request.POST.get('name', None)
|
||||
doc = Document.objects.filter(name=name).first()
|
||||
if not doc:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied name is not valid' }),content_type='application/json')
|
||||
|
||||
if not session.sessionpresentation_set.filter(document=doc).exists():
|
||||
condition_slide_order(session)
|
||||
session.sessionpresentation_set.filter(document__type_id='slides', order__gte=order).update(order=F('order')+1)
|
||||
session.sessionpresentation_set.create(document=doc,rev=doc.rev,order=order)
|
||||
DocEvent.objects.create(type="added_comment", doc=doc, rev=doc.rev, by=request.user.person, desc="Added to session: %s" % session)
|
||||
|
||||
return HttpResponse(json.dumps({'success':True}), content_type='application/json')
|
||||
|
||||
|
||||
def ajax_remove_slides_from_session(request, session_id, num):
|
||||
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.")
|
||||
|
||||
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')
|
||||
|
||||
oldIndex_str = request.POST.get('oldIndex', None)
|
||||
try:
|
||||
oldIndex = int(oldIndex_str)
|
||||
except (ValueError, TypeError):
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied index is not valid' }),content_type='application/json')
|
||||
if oldIndex < 1 or oldIndex > session.sessionpresentation_set.filter(document__type_id='slides').count() :
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied index is not valid' }),content_type='application/json')
|
||||
|
||||
name = request.POST.get('name', None)
|
||||
doc = Document.objects.filter(name=name).first()
|
||||
if not doc:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied name is not valid' }),content_type='application/json')
|
||||
|
||||
condition_slide_order(session)
|
||||
affected_presentations = session.sessionpresentation_set.filter(document=doc).first()
|
||||
if affected_presentations:
|
||||
if affected_presentations.order == oldIndex:
|
||||
affected_presentations.delete()
|
||||
session.sessionpresentation_set.filter(document__type_id='slides', order__gt=oldIndex).update(order=F('order')-1)
|
||||
DocEvent.objects.create(type="added_comment", doc=doc, rev=doc.rev, by=request.user.person, desc="Removed from session: %s" % session)
|
||||
return HttpResponse(json.dumps({'success':True}), content_type='application/json')
|
||||
else:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Name does not match index' }),content_type='application/json')
|
||||
else:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'SessionPresentation not found' }),content_type='application/json')
|
||||
|
||||
|
||||
def ajax_reorder_slides_in_session(request, session_id, num):
|
||||
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.")
|
||||
|
||||
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')
|
||||
|
||||
num_slides_in_session = session.sessionpresentation_set.filter(document__type_id='slides').count()
|
||||
oldIndex_str = request.POST.get('oldIndex', None)
|
||||
try:
|
||||
oldIndex = int(oldIndex_str)
|
||||
except (ValueError, TypeError):
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied index is not valid' }),content_type='application/json')
|
||||
if oldIndex < 1 or oldIndex > num_slides_in_session :
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied index is not valid' }),content_type='application/json')
|
||||
|
||||
newIndex_str = request.POST.get('newIndex', None)
|
||||
try:
|
||||
newIndex = int(newIndex_str)
|
||||
except (ValueError, TypeError):
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied index is not valid' }),content_type='application/json')
|
||||
if newIndex < 1 or newIndex > num_slides_in_session :
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied index is not valid' }),content_type='application/json')
|
||||
|
||||
if newIndex == oldIndex:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied index is not valid' }),content_type='application/json')
|
||||
|
||||
condition_slide_order(session)
|
||||
sp = session.sessionpresentation_set.get(order=oldIndex)
|
||||
if oldIndex < newIndex:
|
||||
session.sessionpresentation_set.filter(order__gt=oldIndex, order__lte=newIndex).update(order=F('order')-1)
|
||||
else:
|
||||
session.sessionpresentation_set.filter(order__gte=newIndex, order__lt=oldIndex).update(order=F('order')+1)
|
||||
sp.order = newIndex
|
||||
sp.save()
|
||||
|
||||
return HttpResponse(json.dumps({'success':True}),content_type='application/json')
|
||||
return HttpResponse(json.dumps({'success':True}), content_type='application/json')
|
||||
|
||||
|
||||
@role_required('Secretariat')
|
||||
def make_schedule_official(request, num, owner, name):
|
||||
|
|
|
@ -61,16 +61,15 @@
|
|||
|
||||
{% 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" src={% static 'Sortable/Sortable.min.js' %}></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
$.ajaxSetup({
|
||||
crossDomain: false,
|
||||
beforeSend: function(xhr, settings) {
|
||||
|
@ -80,33 +79,53 @@
|
|||
}
|
||||
});
|
||||
|
||||
$(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(ui.item.parent())}
|
||||
}).disableSelection();
|
||||
});
|
||||
var sortables=[];
|
||||
var options = {
|
||||
group: "slides",
|
||||
animation: 150,
|
||||
onAdd: function(event) {onAdd(event)},
|
||||
onRemove: function(event) {onRemove(event)},
|
||||
onEnd: function(event) {onEnd(event)}
|
||||
};
|
||||
|
||||
function adjustDatabase(tbody) {
|
||||
tbody.find('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});
|
||||
}
|
||||
function onAdd(event) {
|
||||
var old_session = event.from.getAttribute("session");
|
||||
var new_session = event.to.getAttribute("session");
|
||||
$.post(event.to.getAttribute("addToSession"), {
|
||||
'order': event.newIndex + 1,
|
||||
'name': event.item.getAttribute("name")
|
||||
});
|
||||
$(event.item).find("td:eq(1)").find("a").each(function(){
|
||||
$(this).attr("href", $(this).attr("href").replace(old_session,new_session) );
|
||||
});
|
||||
}
|
||||
|
||||
function onRemove(event) {
|
||||
var old_session = event.from.getAttribute("session");
|
||||
$.post(event.from.getAttribute("removeFromSession"),{
|
||||
'oldIndex': event.oldIndex + 1,
|
||||
'name': event.item.getAttribute("name")
|
||||
});
|
||||
}
|
||||
|
||||
function onEnd(event) {
|
||||
if (event.to == event.from) {
|
||||
$.post(event.from.getAttribute("reorderInSession"),{
|
||||
'oldIndex': event.oldIndex + 1,
|
||||
'newIndex': event.newIndex + 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$(".slides tbody").each(function() {
|
||||
sortables.push(Sortable.create(this, options));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endif %}
|
||||
|
|
|
@ -66,9 +66,9 @@
|
|||
<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 slides" id="slides_{{session.pk}}">
|
||||
<tbody>
|
||||
<tbody session="{{session.pk}}" addToSession="{% url 'ietf.meeting.views.ajax_add_slides_to_session' session_id=session.pk num=session.meeting.number %}" removeFromSession="{% url 'ietf.meeting.views.ajax_remove_slides_from_session' session_id=session.pk num=session.meeting.number %}" reorderInSession="{% url 'ietf.meeting.views.ajax_reorder_slides_in_session' session_id=session.pk num=session.meeting.number %}">
|
||||
{% 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 %}">
|
||||
<tr name="{{pres.document.name}}">
|
||||
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
|
||||
<td>
|
||||
<a href="{{pres.document.href}}">{{pres.document.title}} </a>
|
||||
|
|
Loading…
Reference in a new issue