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:
parent
fe17f6d87b
commit
1a2b885864
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)),
|
||||
)
|
||||
|
|
|
@ -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"),
|
||||
)
|
||||
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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" %}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
Loading…
Reference in a new issue