checkpoint. Refactor to put session oriented utilites back in the meeting app. Minimize the use of the /materials url. Provide better access control to the remaining materials url functions.

- Legacy-Id: 10850
This commit is contained in:
Robert Sparks 2016-02-22 17:03:46 +00:00
parent fe17f6d87b
commit 1a2b885864
13 changed files with 75 additions and 67 deletions

View file

@ -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)

View file

@ -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")

View file

@ -118,6 +118,7 @@ urlpatterns = patterns('',
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.doc.urls_charter')),
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/meetings$', 'ietf.doc.views_doc.all_presentations', name="all_presentations"),
(r'^(?P<name>[A-Za-z0-9._+-]+)/material/', include('ietf.doc.urls_material')),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/session/', include(session_patterns)),
)

View file

@ -2,6 +2,5 @@ from django.conf.urls import patterns, url
urlpatterns = patterns('ietf.doc.views_material',
url(r'^(?P<action>state|title|abstract|revise)/$', "edit_material", name="material_edit"),
url(r'^meetings/$', "all_presentations", name="all_presentations"),
)

View file

@ -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,
})

View file

@ -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,
})

View file

@ -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

View file

@ -18,7 +18,7 @@
{% buttons %}
<button class="btn btn-primary" type="submit" name="save">Save</button>
<a class="btn btn-default" href="{% url 'ietf.doc.views_material.all_presentations' name=doc.name %}">Cancel</a>
<a class="btn btn-default" href="{% url 'ietf.doc.views_doc.all_presentations' name=doc.name %}">Cancel</a>
{% endbuttons %}
</form>

View file

@ -250,7 +250,7 @@
<th>On Agenda</th>
<td class="edit">
{% 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 %}
</td>

View file

@ -93,7 +93,7 @@
<th>On agenda</th>
<td class="edit">
{% if not snapshot and can_manage_material %}
{% doc_edit_button "material_presentations" name=doc.name %}
{% doc_edit_button "all_presentations" name=doc.name %}
{% endif %}
</td>

View file

@ -21,7 +21,7 @@
{% buttons %}
<button class="btn btn-primary" type="submit" name="save">Save</button>
<a class="btn btn-default" href="{% url 'ietf.doc.views_material.all_presentations' name=sp.document.name %}">Cancel</a>
<a class="btn btn-default" href="{% url 'ietf.doc.views_doc.all_presentations' name=sp.document.name %}">Cancel</a>
{% endbuttons %}
</form>

View file

@ -6,7 +6,7 @@
{% block content %}
{% origin %}
<h1>Sessions linked to {{doc.name}}{% if doc.title %}<br><small>{{doc.title}}</small>{% endif %}</h1>
<h1>Sessions linked to <a href="{% url 'doc_view' name=doc.name %}">{{doc.name}}</a>{% if doc.title %}<br><small>{{doc.title}}</small>{% endif %}</h1>
<div class="buttonlist" >
{% if user|has_role:"Secretariat,Area Director,WG Chair,WG Secretary,RG Chair,RG Secretary,IRTF Chair,Team Chair" %}

View file

@ -24,7 +24,7 @@
{% 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.doc.views_material.all_presentations' name=sp.document.name %}">Cancel</a>
<a class="btn btn-default href="{% url 'ietf.doc.views_doc.all_presentations' name=sp.document.name %}">Cancel</a>
{% endbuttons %}
</form>