diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 362163ecd..4fb350e4c 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -933,7 +933,7 @@ class DocumentMeetingTests(TestCase): doc.sessionpresentation_set.create(session=self.inprog,rev=None) doc.sessionpresentation_set.create(session=self.interim,rev=None) - url = urlreverse('ietf.doc.views_material.all_presentations', kwargs=dict(name=doc.name)) + url = urlreverse('ietf.doc.views_doc.all_presentations', kwargs=dict(name=doc.name)) response = self.client.get(url) self.assertEqual(response.status_code, 200) q = PyQuery(response.content) diff --git a/ietf/doc/tests_material.py b/ietf/doc/tests_material.py index fee6560c4..f16858cb4 100644 --- a/ietf/doc/tests_material.py +++ b/ietf/doc/tests_material.py @@ -6,6 +6,8 @@ import datetime from StringIO import StringIO from pyquery import PyQuery +import debug # pyflakes:ignore + from django.conf import settings from django.core.urlresolvers import reverse as urlreverse @@ -18,6 +20,7 @@ from ietf.person.models import Person from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent from ietf.utils.test_data import make_test_data + class GroupMaterialTests(TestCase): def setUp(self): self.materials_dir = os.path.abspath("tmp-document-dir") diff --git a/ietf/doc/urls.py b/ietf/doc/urls.py index e4ffd7ccd..235a95c17 100644 --- a/ietf/doc/urls.py +++ b/ietf/doc/urls.py @@ -118,6 +118,7 @@ urlpatterns = patterns('', (r'^(?Pcharter-[A-Za-z0-9._+-]+)/', include('ietf.doc.urls_charter')), (r'^(?P[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')), (r'^(?P[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')), + url(r'^(?P[A-Za-z0-9._+-]+)/meetings$', 'ietf.doc.views_doc.all_presentations', name="all_presentations"), (r'^(?P[A-Za-z0-9._+-]+)/material/', include('ietf.doc.urls_material')), url(r'^(?P[A-Za-z0-9._+-]+)/session/', include(session_patterns)), ) diff --git a/ietf/doc/urls_material.py b/ietf/doc/urls_material.py index 5b6eac4fc..1f104336d 100644 --- a/ietf/doc/urls_material.py +++ b/ietf/doc/urls_material.py @@ -2,6 +2,5 @@ from django.conf.urls import patterns, url urlpatterns = patterns('ietf.doc.views_material', url(r'^(?Pstate|title|abstract|revise)/$', "edit_material", name="material_edit"), - url(r'^meetings/$', "all_presentations", name="all_presentations"), ) diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index 270007a70..f21693fce 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -61,6 +61,7 @@ from ietf.doc.forms import TelechatForm, NotifyForm from ietf.doc.mails import email_comment from ietf.mailtrigger.utils import gather_relevant_expansions from ietf.meeting.models import Session +from ietf.meeting.utils import group_sessions, get_upcoming_manageable_sessions, sort_sessions def render_document_top(request, doc, tab, name): tabs = [] @@ -1094,7 +1095,6 @@ def email_aliases(request,name=''): class VersionForm(forms.Form): - # TODO is required=False correct here? version = forms.ChoiceField(required=True, label='Which version of this document will be discussed at this session?') @@ -1126,7 +1126,7 @@ def edit_sessionpresentation(request,name,session_id): c = DocEvent(type="added_comment", doc=doc, by=request.user.person) c.desc = "Revision for session %s changed to %s" % (sp.session,new_selection) c.save() - return redirect('ietf.doc.views_material.all_presentations', name=name) + return redirect('ietf.doc.views_doc.all_presentations', name=name) else: form = VersionForm(choices=choices,initial=initial) @@ -1147,47 +1147,10 @@ def remove_sessionpresentation(request,name,session_id): c = DocEvent(type="added_comment", doc=doc, by=request.user.person) c.desc = "Removed from session: %s" % (sp.session) c.save() - return redirect('ietf.doc.views_material.all_presentations', name=name) + return redirect('ietf.doc.views_doc.all_presentations', name=name) return render(request,'doc/remove_sessionpresentation.html', {'sp': sp }) - -def get_upcoming_manageable_sessions(user): - - # TODO: Move this into meeting.models or utils, or maybe person.models or utils - it doesn't depend on doc - # Find all the sessions for meetings that haven't ended that the user could affect - # This motif is also in Document.future_presentations - it would be nice to consolodate it somehow - - # Consider adding an argument that has some Qs to append to the queryset - - candidate_sessions = Session.objects.exclude(status__in=['canceled','disappr','notmeet','deleted']).filter(meeting__date__gte=datetime.date.today()-datetime.timedelta(days=15)) - refined_candidates = [ sess for sess in candidate_sessions if sess.meeting.end_date()>=datetime.date.today()] - - # Consider keeping this (put acronym=None back in argument list - #if acronym: - # refined_candidates = [ sess for sess in refined_candidates if sess.group.acronym==acronym] - - return [ sess for sess in refined_candidates if can_manage_materials(user, sess.group) ] - -def sort_sessions(sessions): - - # Python sorts are stable since version 2,2, so this series results in a list sorted first - # by the meeting 'number', then by session's group acronym, then by scheduled time - # (or the time of the session request if the session isn't scheduled). - - def time_sort_key(session): - official_sessions = session.timeslotassignments.filter(schedule=session.meeting.agenda) - if official_sessions: - return official_sessions.first().timeslot.time - else: - return session.requested - - time_sorted = sorted(sessions,key=time_sort_key) - acronym_sorted = sorted(time_sorted,key=lambda x: x.group.acronym) - meeting_sorted = sorted(acronym_sorted,key=lambda x: x.meeting.number) - - return meeting_sorted - class SessionChooserForm(forms.Form): session = forms.ChoiceField(label="Which session should this document be added to?",required=True) @@ -1221,10 +1184,27 @@ def add_sessionpresentation(request,name): c = DocEvent(type="added_comment", doc=doc, by=request.user.person) c.desc = "%s to session: %s" % ('Added -%s'%rev if rev else 'Added', Session.objects.get(pk=session_id)) c.save() - return redirect('ietf.doc.views_material.all_presentations', name=name) + return redirect('ietf.doc.views_doc.all_presentations', name=name) else: version_form = VersionForm(choices=version_choices,initial={'version':'current'}) session_form = SessionChooserForm(choices=session_choices) return render(request,'doc/add_sessionpresentation.html',{'doc':doc,'version_form':version_form,'session_form':session_form}) + +def all_presentations(request, name): + doc = get_object_or_404(Document, name=name) + + + sessions = doc.session_set.filter(status__in=['sched','schedw','appr','canceled'], + type__in=['session','plenary','other']) + + future, in_progress, past = group_sessions(sessions) + + return render(request, 'doc/material/all_presentations.html', { + 'user': request.user, + 'doc': doc, + 'future': future, + 'in_progress': in_progress, + 'past' : past, + }) diff --git a/ietf/doc/views_material.py b/ietf/doc/views_material.py index 281b62651..ea258d98c 100644 --- a/ietf/doc/views_material.py +++ b/ietf/doc/views_material.py @@ -17,7 +17,6 @@ from ietf.doc.models import NewRevisionDocEvent, save_document_in_history from ietf.doc.utils import add_state_change_event, check_common_doc_name_rules from ietf.group.models import Group from ietf.group.utils import can_manage_materials -from ietf.meeting.utils import group_sessions @login_required def choose_material_type(request, acronym): @@ -92,10 +91,15 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None): doc = None document_type = get_object_or_404(DocTypeName, slug=doc_type) + if document_type not in DocTypeName.objects.filter(slug__in=group.features.material_types): + raise Http404 else: doc = get_object_or_404(Document, name=name) group = doc.group document_type = doc.type + if document_type not in DocTypeName.objects.filter(slug__in=group.features.material_types): + raise Http404 + if not can_manage_materials(request.user, group): return HttpResponseForbidden("You don't have permission to access this view") @@ -172,20 +176,3 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None): 'document_type': document_type, 'doc_name': doc.name if doc else "", }) - -def all_presentations(request, name): - doc = get_object_or_404(Document, name=name) - - - sessions = doc.session_set.filter(status__in=['sched','schedw','appr','canceled'], - type__in=['session','plenary','other']) - - future, in_progress, past = group_sessions(sessions) - - return render(request, 'doc/material/all_presentations.html', { - 'user': request.user, - 'doc': doc, - 'future': future, - 'in_progress': in_progress, - 'past' : past, - }) diff --git a/ietf/meeting/utils.py b/ietf/meeting/utils.py index 1308ecbb6..4a48ca746 100644 --- a/ietf/meeting/utils.py +++ b/ietf/meeting/utils.py @@ -1,5 +1,8 @@ import datetime +from ietf.meeting.models import Session +from ietf.group.utils import can_manage_materials + def group_sessions(sessions): def sort_key(session): @@ -33,3 +36,38 @@ def group_sessions(sessions): past.append(s) return future, in_progress, past + +def get_upcoming_manageable_sessions(user): + """ Find all the sessions for meetings that haven't ended that the user could affect """ + + # Consider adding an argument that has some Qs to append to the queryset + # to allow filtering to a particular group, etc. if we start seeing a lot of code + # that calls this function and then immediately starts whittling down the returned list + + # Note the days=15 - this allows this function to find meetings in progress that last up to two weeks. + # This notion of searching by end-of-meeting is also present in Document.future_presentations. + # It would be nice to make it easier to use querysets to talk about meeting endings wthout a heuristic like this one + + candidate_sessions = Session.objects.exclude(status__in=['canceled','disappr','notmeet','deleted']).filter(meeting__date__gte=datetime.date.today()-datetime.timedelta(days=15)) + refined_candidates = [ sess for sess in candidate_sessions if sess.meeting.end_date()>=datetime.date.today()] + + return [ sess for sess in refined_candidates if can_manage_materials(user, sess.group) ] + +def sort_sessions(sessions): + + # Python sorts are stable since version 2,2, so this series results in a list sorted first + # by the meeting 'number', then by session's group acronym, then by scheduled time + # (or the time of the session request if the session isn't scheduled). + + def time_sort_key(session): + official_sessions = session.timeslotassignments.filter(schedule=session.meeting.agenda) + if official_sessions: + return official_sessions.first().timeslot.time + else: + return session.requested + + time_sorted = sorted(sessions,key=time_sort_key) + acronym_sorted = sorted(time_sorted,key=lambda x: x.group.acronym) + meeting_sorted = sorted(acronym_sorted,key=lambda x: x.meeting.number) + + return meeting_sorted diff --git a/ietf/templates/doc/add_sessionpresentation.html b/ietf/templates/doc/add_sessionpresentation.html index cb7aea5ce..72d9f0195 100644 --- a/ietf/templates/doc/add_sessionpresentation.html +++ b/ietf/templates/doc/add_sessionpresentation.html @@ -18,7 +18,7 @@ {% buttons %} - Cancel + Cancel {% endbuttons %} diff --git a/ietf/templates/doc/document_draft.html b/ietf/templates/doc/document_draft.html index e73b19682..cc53f7929 100644 --- a/ietf/templates/doc/document_draft.html +++ b/ietf/templates/doc/document_draft.html @@ -250,7 +250,7 @@ On Agenda {% if not snapshot and can_edit_stream_info %} - {% doc_edit_button "ietf.doc.views_material.all_presentations" name=doc.name %} + {% doc_edit_button "ietf.doc.views_doc.all_presentations" name=doc.name %} {% endif %} diff --git a/ietf/templates/doc/document_material.html b/ietf/templates/doc/document_material.html index b1f733409..2d2d56636 100644 --- a/ietf/templates/doc/document_material.html +++ b/ietf/templates/doc/document_material.html @@ -93,7 +93,7 @@ On agenda {% if not snapshot and can_manage_material %} - {% doc_edit_button "material_presentations" name=doc.name %} + {% doc_edit_button "all_presentations" name=doc.name %} {% endif %} diff --git a/ietf/templates/doc/edit_sessionpresentation.html b/ietf/templates/doc/edit_sessionpresentation.html index 379c7a93f..549078960 100644 --- a/ietf/templates/doc/edit_sessionpresentation.html +++ b/ietf/templates/doc/edit_sessionpresentation.html @@ -21,7 +21,7 @@ {% buttons %} - Cancel + Cancel {% endbuttons %} diff --git a/ietf/templates/doc/material/all_presentations.html b/ietf/templates/doc/material/all_presentations.html index f81d883ee..80577dade 100644 --- a/ietf/templates/doc/material/all_presentations.html +++ b/ietf/templates/doc/material/all_presentations.html @@ -6,7 +6,7 @@ {% block content %} {% origin %} -

Sessions linked to {{doc.name}}{% if doc.title %}
{{doc.title}}{% endif %}

+

Sessions linked to {{doc.name}}{% if doc.title %}
{{doc.title}}{% endif %}

{% if user|has_role:"Secretariat,Area Director,WG Chair,WG Secretary,RG Chair,RG Secretary,IRTF Chair,Team Chair" %} diff --git a/ietf/templates/doc/remove_sessionpresentation.html b/ietf/templates/doc/remove_sessionpresentation.html index d63a40a52..919fcc224 100644 --- a/ietf/templates/doc/remove_sessionpresentation.html +++ b/ietf/templates/doc/remove_sessionpresentation.html @@ -24,7 +24,7 @@ {% csrf_token %} {% buttons %} - Cancel + Cancel {% endbuttons %}