From f9d614528b9e375502deded3ece07c40b6af35cd Mon Sep 17 00:00:00 2001 From: Ryan Cross Date: Sun, 20 Jul 2014 20:31:08 +0000 Subject: [PATCH 1/3] fixes Ticket #1443. Do not allow editing or submitting new session requests when the tool is locked. Commit ready for merge. - Legacy-Id: 8156 --- ietf/secr/sreq/tests.py | 50 ++++++++++++++++++- ietf/secr/sreq/views.py | 26 ++++++++-- .../includes/sessions_request_form.html | 8 ++- ietf/secr/templates/sreq/view.html | 2 +- 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/ietf/secr/sreq/tests.py b/ietf/secr/sreq/tests.py index 38c9eec1b..c2eece938 100644 --- a/ietf/secr/sreq/tests.py +++ b/ietf/secr/sreq/tests.py @@ -1,11 +1,16 @@ +import os +import shutil + from django.core.urlresolvers import reverse +from django.conf import settings from ietf.utils.test_utils import TestCase from ietf.group.models import Group +#from ietf.meeting.models import Session #from ietf.utils.test_data import make_test_data from ietf.meeting.test_data import make_meeting_test_data as make_test_data -#from pyquery import PyQuery +from pyquery import PyQuery SECR_USER='secretary' @@ -59,6 +64,47 @@ class SubmitRequestCase(TestCase): r = self.client.get(url) assert False, r.content """ + +class LockAppTestCase(TestCase): + def setUp(self): + self.agenda_dir = os.path.abspath("tmp-agenda-dir") + os.mkdir(self.agenda_dir) + settings.AGENDA_PATH = self.agenda_dir + path = os.path.join(self.agenda_dir,'session_request.lock') + with open(path, 'w') as f: + f.write('App is locked') + + def tearDown(self): + shutil.rmtree(self.agenda_dir) + + def test_edit_request(self): + make_test_data() + group = Group.objects.get(acronym='mars') + url = reverse('sessions_edit',kwargs={'acronym':group.acronym}) + self.client.login(username="secretary", password="secretary+password") + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertEqual(len(q(':disabled[name="submit"]')), 1) + + def test_view_request(self): + make_test_data() + group = Group.objects.get(acronym='mars') + url = reverse('sessions_view',kwargs={'acronym':group.acronym}) + self.client.login(username="secretary", password="secretary+password") + r = self.client.get(url,follow=True) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertEqual(len(q(':disabled[name="edit"]')), 1) + + def test_new_request(self): + make_test_data() + group = Group.objects.get(acronym='mars') + url = reverse('sessions_new',kwargs={'acronym':group.acronym}) + self.client.login(username="secretary", password="secretary+password") + r = self.client.get(url) + self.assertEqual(r.status_code, 302) + class EditRequestCase(TestCase): pass @@ -73,4 +119,4 @@ class RetrievePreviousCase(TestCase): # test error if already scheduled # test get previous exists/doesn't exist # test that groups scheduled and unscheduled add up to total groups - # test locking function, access by unauthorized + # test access by unauthorized diff --git a/ietf/secr/sreq/views.py b/ietf/secr/sreq/views.py index 0a10fb94f..b6caa4b6b 100644 --- a/ietf/secr/sreq/views.py +++ b/ietf/secr/sreq/views.py @@ -24,7 +24,7 @@ from ietf.person.models import Email # Globals # ------------------------------------------------- SESSION_REQUEST_EMAIL = 'session-request@ietf.org' -LOCKFILE = os.path.join(settings.SECR_PROCEEDINGS_DIR,'session_request.lock') +LOCKFILE = os.path.join(settings.AGENDA_PATH,'session_request.lock') # ------------------------------------------------- # Helper Functions # ------------------------------------------------- @@ -355,6 +355,11 @@ def edit_mtg(request, num, acronym): if 'resources' in initial: initial['resources'] = [x.pk for x in initial['resources']] + # check if app is locked + is_locked = check_app_locked() + if is_locked: + messages.warning(request, "The Session Request Tool is closed") + session_conflicts = session_conflicts_as_string(group, meeting) login = request.user.person @@ -467,6 +472,7 @@ def edit_mtg(request, num, acronym): form = SessionForm(initial=initial) return render_to_response('sreq/edit.html', { + 'is_locked': is_locked, 'meeting': meeting, 'form': form, 'group': group, @@ -541,11 +547,16 @@ def new(request, acronym): This view gathers details for a new session request. The user proceeds to confirm() to create the request. ''' - group = get_object_or_404(Group, acronym=acronym) meeting = get_meeting() session_conflicts = session_conflicts_as_string(group, meeting) + # check if app is locked + is_locked = check_app_locked() + if is_locked: + messages.warning(request, "The Session Request Tool is closed") + return redirect('sessions') + if request.method == 'POST': button_text = request.POST.get('submit', '') if button_text == 'Cancel': @@ -689,9 +700,17 @@ def view(request, acronym, num = None): group = get_object_or_404(Group, acronym=acronym) sessions = Session.objects.filter(~Q(status__in=('canceled','notmeet','deleted')),meeting=meeting,group=group).order_by('id') + # check if app is locked + is_locked = check_app_locked() + if is_locked: + messages.warning(request, "The Session Request Tool is closed") + # if there are no session requests yet, redirect to new session request page if not sessions: - return redirect('sessions_new', acronym=acronym) + if is_locked: + return redirect('sessions') + else: + return redirect('sessions_new', acronym=acronym) # TODO simulate activity records activities = [{'act_date':sessions[0].requested.strftime('%b %d, %Y'), @@ -718,6 +737,7 @@ def view(request, acronym, num = None): session = get_initial_session(sessions) return render_to_response('sreq/view.html', { + 'is_locked': is_locked, 'session': session, 'activities': activities, 'meeting': meeting, diff --git a/ietf/secr/templates/includes/sessions_request_form.html b/ietf/secr/templates/includes/sessions_request_form.html index 7344f06de..9daedfae9 100755 --- a/ietf/secr/templates/includes/sessions_request_form.html +++ b/ietf/secr/templates/includes/sessions_request_form.html @@ -62,6 +62,12 @@ - {% include "includes/buttons_save_cancel.html" %} +
+ +
+ diff --git a/ietf/secr/templates/sreq/view.html b/ietf/secr/templates/sreq/view.html index eb623741a..e76d785f0 100644 --- a/ietf/secr/templates/sreq/view.html +++ b/ietf/secr/templates/sreq/view.html @@ -28,7 +28,7 @@
+

Use this to input session recording information.

+ \ No newline at end of file diff --git a/ietf/secr/templates/includes/slides.html b/ietf/secr/templates/includes/slides.html index 802460bee..71146bef6 100644 --- a/ietf/secr/templates/includes/slides.html +++ b/ietf/secr/templates/includes/slides.html @@ -11,7 +11,7 @@ - {% for slide in slides %} + {% for slide in materials.slides %} {{ slide.title }} {{ slide.external_url }}{% if slide.external_url|is_ppt %} *{% endif %} diff --git a/ietf/secr/templates/proceedings/proceedings.html b/ietf/secr/templates/proceedings/proceedings.html index 455b8b685..4f81613f0 100644 --- a/ietf/secr/templates/proceedings/proceedings.html +++ b/ietf/secr/templates/proceedings/proceedings.html @@ -22,16 +22,16 @@ and end with {% endif %}

-{% if minutes %} - Minutes +{% if materials.minutes %} + Minutes {% else %} Minutes {% endif %}  |   {% if meeting.type.slug == "ietf" %} - Audio Archives  |   + {% comment %}Audio Archives  |   {% endcomment %} {% else %} - {% if agenda %} - Agenda + {% if materials.agenda %} + Agenda {% else %} Agenda {% endif %}  |   @@ -84,10 +84,21 @@ and end with {% endif %}

-

Meeting Slides:

-{% if slides %} +

Recordings:

+{% if materials.record %} +{% else %} +

No Recordings Present

+{% endif %} + +

Meeting Slides:

+{% if materials.slides %} + diff --git a/ietf/secr/templates/proceedings/recording.html b/ietf/secr/templates/proceedings/recording.html new file mode 100755 index 000000000..613aa95ba --- /dev/null +++ b/ietf/secr/templates/proceedings/recording.html @@ -0,0 +1,80 @@ +{% extends "base_site.html" %} + +{% block title %}Proceedings{% endblock %} + +{% block extrastyle %}{{ block.super }} + +{% endblock %} + +{% block extrahead %}{{ block.super }} + + +{% endblock %} + +{% block breadcrumbs %}{{ block.super }} + {% if meeting.type_id == "interim" %} + » Proceedings + » Interim Select Group + » {{ group.acronym }} + » {{ meeting }} + {% else %} + » Proceedings + » {{ meeting.number }} + » Recording + {% endif %} +{% endblock %} + +{% block content %} + +
+ +

Recording Metadata

+
{% csrf_token %} + + {{ form.as_table }} +
+ + {% include "includes/buttons_submit_back.html" %} + +
+ +
+ +{% if docevents %} +
+
+ {% include "includes/docevents.html" %} +
+{% endif %} + +{% endblock %} + +{% block footer-extras %} + {% include "includes/upload_footer.html" %} +{% endblock %} diff --git a/ietf/secr/templates/proceedings/recording_edit.html b/ietf/secr/templates/proceedings/recording_edit.html new file mode 100755 index 000000000..cea5c2d97 --- /dev/null +++ b/ietf/secr/templates/proceedings/recording_edit.html @@ -0,0 +1,40 @@ +{% extends "base_site.html" %} + +{% block title %}Edit Recording{% endblock %} + +{% block extrahead %}{{ block.super }} + +{% endblock %} + +{% block breadcrumbs %}{{ block.super }} + {% if meeting.type_id == "interim" %} + » Proceedings + » Interim Select Group + » {{ group.acronym }} + » {{ meeting }} + » Recording + » {{ recording.name }} + {% else %} + » Proceedings + » {{ meeting.number }} + » Recording + » {{ recording.name }} + {% endif %} +{% endblock %} + +{% block content %} + +
+

Recording Metadata for Group: {{ form.instance.group.acronym }} | Session: {{ form.instance.session_set.first.official_scheduledsession.timeslot.time }}

+

Edit Recording Metadata:

+
{% csrf_token %} + + {{ form.as_table }} +
+ + {% include "includes/buttons_save_cancel.html" %} + +
+
+ +{% endblock %} diff --git a/ietf/secr/templates/proceedings/upload_unified.html b/ietf/secr/templates/proceedings/upload_unified.html index c8bedf627..0b2d64b7f 100755 --- a/ietf/secr/templates/proceedings/upload_unified.html +++ b/ietf/secr/templates/proceedings/upload_unified.html @@ -51,10 +51,10 @@ - {% if minutes %} - Minutes - {{ minutes.external_url }} - Delete + {% if materials.minutes %} + Minutes + {{ materials.minutes.external_url }} + Delete {% else %} Minutes (not uploaded) @@ -62,10 +62,10 @@ {% endif %} - {% if agenda %} - Agenda - {{ agenda.external_url }} - Delete + {% if materials.agenda %} + Agenda + {{ materials.agenda.external_url }} + Delete {% else %} Agenda (not uploaded) diff --git a/ietf/secr/utils/meeting.py b/ietf/secr/utils/meeting.py index c1afaea3a..d5b657c3f 100644 --- a/ietf/secr/utils/meeting.py +++ b/ietf/secr/utils/meeting.py @@ -1,27 +1,30 @@ import os +import re from django.conf import settings -from ietf.meeting.models import Meeting +from ietf.meeting.models import Meeting, Session def get_current_meeting(): '''Returns the most recent IETF meeting''' return Meeting.objects.filter(type='ietf').order_by('-number')[0] -def get_material(session): +def get_materials(group,meeting): ''' - This function takes a session object and returns a tuple of active materials: - agenda(Document), minutes(Document), slides(list of Documents) + Returns the materials as a dictionary with keys = doctype. + NOTE, if the group has multiple sessions all materials but recordings will be + attached to all sessions. ''' - active_materials = session.materials.exclude(states__slug='deleted') - slides = active_materials.filter(type='slides').order_by('order') - minutes = active_materials.filter(type='minutes') - minutes = minutes[0] if minutes else None - agenda = active_materials.filter(type='agenda') - agenda = agenda[0] if agenda else None - - return agenda,minutes,slides + materials = dict(slides=[],record=[]) + # TODO: status should only be sched, but there is a bug in the scheduler + for session in Session.objects.filter(group=group,meeting=meeting,status__in=('sched','schedw')): + for doc in session.materials.exclude(states__slug='deleted').order_by('order'): + if doc.type.slug in ('minutes','agenda'): + materials[doc.type.slug] = doc + elif doc not in materials[doc.type.slug]: + materials[doc.type.slug].append(doc) + return materials def get_proceedings_path(meeting, group): if meeting.type.slug == 'interim': diff --git a/ietf/settings.py b/ietf/settings.py index 3900e4b34..b98e1a5c8 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -273,6 +273,7 @@ IESG_ROLL_CALL_FILE = '/a/www/www6/iesg/internal/rollcall.txt' IESG_MINUTES_FILE = '/a/www/www6/iesg/internal/minutes.txt' IESG_WG_EVALUATION_DIR = "/a/www/www6/iesg/evaluation" INTERNET_DRAFT_ARCHIVE_DIR = '/a/www/www6s/draft-archive' +MEETING_RECORDINGS_DIR = '/a/www/audio' # Mailing list info URL for lists hosted on the IETF servers MAILING_LIST_INFO_URL = "https://www.ietf.org/mailman/listinfo/%(list_addr)s" @@ -295,6 +296,7 @@ MEETING_DOC_HREFS = { "agenda": "/meeting/{meeting}/agenda/{doc.group.acronym}/", "minutes": "http://www.ietf.org/proceedings/{meeting}/minutes/{doc.external_url}", "slides": "http://www.ietf.org/proceedings/{meeting}/slides/{doc.external_url}", + "record": "{doc.external_url}", } # Override this in settings_local.py if needed diff --git a/static/secretariat/css/custom.css b/static/secretariat/css/custom.css index 05b9a3819..76b284ae6 100644 --- a/static/secretariat/css/custom.css +++ b/static/secretariat/css/custom.css @@ -575,6 +575,10 @@ div.interim-scroll { border-left: 1px solid #CCCCCC; } +#recording-form #id_external_url { + width: 40em; +} + td.hidden { display: none; } diff --git a/static/secretariat/js/proceedings-recording.js b/static/secretariat/js/proceedings-recording.js new file mode 100644 index 000000000..e861a2ae6 --- /dev/null +++ b/static/secretariat/js/proceedings-recording.js @@ -0,0 +1,24 @@ +/* proceedings-recordings.js - utility functions */ + + +$(document).ready(function() { + // auto populate Session select list + $('#id_group').blur(function(){ + var loadUrl = "/secr/proceedings/ajax/get-sessions/"; + var url = window.location.pathname; + var parts = url.split("/"); + var acronym = $(this).val(); + loadUrl = loadUrl+parts[3]+"/"+acronym+"/"; + $('.errorlist').remove(); + $.getJSON(loadUrl,function(data) { + $('#id_session').find('option').remove(); + if (data.length == 0) { + $( '' ).insertBefore( "#id_group" ); + } else { + $.each(data,function(i,item) { + $('#id_session').append(''); + }); + } + }); + }); +});