From b733e1c615ed2c4b8f4f765496fd1de2560e48f8 Mon Sep 17 00:00:00 2001
From: Jim Fenton
Date: Sat, 20 Jul 2024 15:44:23 -0700
Subject: [PATCH 1/4] attempt at optional approval
---
ietf/meeting/forms.py | 1 +
ietf/meeting/views.py | 1 +
ietf/templates/meeting/propose_session_slides.html | 4 ++++
3 files changed, 6 insertions(+)
diff --git a/ietf/meeting/forms.py b/ietf/meeting/forms.py
index b31ffb6cd7..9f63c73462 100644
--- a/ietf/meeting/forms.py
+++ b/ietf/meeting/forms.py
@@ -489,6 +489,7 @@ class UploadAgendaForm(ApplyToAllFileUploadForm):
class UploadSlidesForm(ApplyToAllFileUploadForm):
doc_type = 'slides'
title = forms.CharField(max_length=255)
+ approved = forms.BooleanField(initial=True)
def __init__(self, session, *args, **kwargs):
super().__init__(*args, **kwargs)
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 2948a2e715..5218714c0f 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -3152,6 +3152,7 @@ def propose_session_slides(request, session_id, num):
{'session': session,
'session_number': session_number,
'form': form,
+ 'manage': session.can_manage_materials(request.user),
})
diff --git a/ietf/templates/meeting/propose_session_slides.html b/ietf/templates/meeting/propose_session_slides.html
index e5a0b451e6..a375827961 100644
--- a/ietf/templates/meeting/propose_session_slides.html
+++ b/ietf/templates/meeting/propose_session_slides.html
@@ -16,12 +16,16 @@
Session {{ session_number }} : {{ session.official_timeslotassignment.timeslot.time|timezone:session.meeting.time_zone|date:"D M-d-Y Hi" }}
{% endif %}
+ {% if not manage %}
This form will allow you to propose a slide deck to the session chairs. After you upload your proposal, mail will be sent to the session chairs asking for their approval.
+ {% endif %}
{% endblock %}
\ No newline at end of file
From 4b74a91abf9ae7b93bcbcb86debeca292e4d1f8a Mon Sep 17 00:00:00 2001
From: Jim Fenton
Date: Fri, 2 Aug 2024 19:48:51 -0700
Subject: [PATCH 2/4] Update of meeting slides propose/upload
---
ietf/meeting/forms.py | 8 +-
ietf/meeting/tests_views.py | 29 +++-
ietf/meeting/urls.py | 1 -
ietf/meeting/views.py | 130 ++++++------------
.../meeting/propose_session_slides.html | 31 -----
.../meeting/session_details_panel.html | 2 +-
ietf/templates/meeting/slides_approved.txt | 2 +-
.../meeting/upload_session_slides.html | 26 ++--
8 files changed, 87 insertions(+), 142 deletions(-)
delete mode 100644 ietf/templates/meeting/propose_session_slides.html
diff --git a/ietf/meeting/forms.py b/ietf/meeting/forms.py
index 9f63c73462..3b66d2cd29 100644
--- a/ietf/meeting/forms.py
+++ b/ietf/meeting/forms.py
@@ -489,10 +489,12 @@ class UploadAgendaForm(ApplyToAllFileUploadForm):
class UploadSlidesForm(ApplyToAllFileUploadForm):
doc_type = 'slides'
title = forms.CharField(max_length=255)
- approved = forms.BooleanField(initial=True)
+ approved = forms.BooleanField(label='Auto-approve', initial=True, required=False)
- def __init__(self, session, *args, **kwargs):
- super().__init__(*args, **kwargs)
+ def __init__(self, session, show_apply_to_all_checkbox, can_manage, *args, **kwargs):
+ super().__init__(show_apply_to_all_checkbox, *args, **kwargs)
+ if not can_manage:
+ self.fields.pop('approved')
self.session = session
def clean_title(self):
diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py
index d783ed9c75..eac61b530f 100644
--- a/ietf/meeting/tests_views.py
+++ b/ietf/meeting/tests_views.py
@@ -6591,7 +6591,7 @@ def test_propose_session_slides(self):
newperson = PersonFactory()
session_overview_url = urlreverse('ietf.meeting.views.session_details',kwargs={'num':session.meeting.number,'acronym':session.group.acronym})
- propose_url = urlreverse('ietf.meeting.views.propose_session_slides', kwargs={'session_id':session.pk, 'num': session.meeting.number})
+ propose_url = urlreverse('ietf.meeting.views.upload_session_slides', kwargs={'session_id':session.pk, 'num': session.meeting.number})
r = self.client.get(session_overview_url)
self.assertEqual(r.status_code,200)
@@ -6612,7 +6612,7 @@ def test_propose_session_slides(self):
test_file = BytesIO(b'this is not really a slide')
test_file.name = 'not_really.txt'
empty_outbox()
- r = self.client.post(propose_url,dict(file=test_file,title='a test slide file',apply_to_all=True))
+ r = self.client.post(propose_url,dict(file=test_file,title='a test slide file',apply_to_all=True,approved=False))
self.assertEqual(r.status_code, 302)
session = Session.objects.get(pk=session.pk)
self.assertEqual(session.slidesubmission_set.count(),1)
@@ -6633,6 +6633,25 @@ def test_propose_session_slides(self):
self.assertEqual(len(q('.proposedslidelist p')), 2)
self.client.logout()
+ login_testing_unauthorized(self,chair.user.username,propose_url)
+ r = self.client.get(propose_url)
+ self.assertEqual(r.status_code,200)
+ test_file = BytesIO(b'this is not really a slide either')
+ test_file.name = 'not_really.txt'
+ empty_outbox()
+ r = self.client.post(propose_url,dict(file=test_file,title='a selfapproved test slide file',apply_to_all=True,approved=True))
+ self.assertEqual(r.status_code, 302)
+ self.client.logout()
+
+ self.client.login(username=chair.user.username, password=chair.user.username+"+password")
+ r = self.client.get(session_overview_url)
+ self.assertEqual(r.status_code, 200)
+ q = PyQuery(r.content)
+ self.assertEqual(len(q('.uploadslidelist p')), 42)
+ self.client.logout()
+
+
+
def test_disapprove_proposed_slides(self):
submission = SlideSubmissionFactory()
submission.session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20))
@@ -6753,12 +6772,12 @@ def test_submit_and_approve_multiple_versions(self, mock_slides_manager_cls):
session.meeting.importantdate_set.create(name_id='revsub',date=date_today()+datetime.timedelta(days=20))
newperson = PersonFactory()
- propose_url = urlreverse('ietf.meeting.views.propose_session_slides', kwargs={'session_id':session.pk, 'num': session.meeting.number})
+ propose_url = urlreverse('ietf.meeting.views.upload_session_slides', kwargs={'session_id':session.pk, 'num': session.meeting.number})
login_testing_unauthorized(self,newperson.user.username,propose_url)
test_file = BytesIO(b'this is not really a slide')
test_file.name = 'not_really.txt'
- r = self.client.post(propose_url,dict(file=test_file,title='a test slide file',apply_to_all=True))
+ r = self.client.post(propose_url,dict(file=test_file,title='a test slide file',apply_to_all=True,approved=False))
self.assertEqual(r.status_code, 302)
self.client.logout()
@@ -6829,6 +6848,8 @@ def test_submit_and_approve_multiple_versions(self, mock_slides_manager_cls):
self.assertIn('third version', contents)
+
+
@override_settings(IETF_NOTES_URL='https://notes.ietf.org/')
class ImportNotesTests(TestCase):
settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ['AGENDA_PATH']
diff --git a/ietf/meeting/urls.py b/ietf/meeting/urls.py
index 26d3d93b20..f2e65578ec 100644
--- a/ietf/meeting/urls.py
+++ b/ietf/meeting/urls.py
@@ -22,7 +22,6 @@ def get_redirect_url(self, *args, **kwargs):
url(r'^session/(?P\d+)/narrativeminutes$', views.upload_session_narrativeminutes),
url(r'^session/(?P\d+)/agenda$', views.upload_session_agenda),
url(r'^session/(?P\d+)/import/minutes$', views.import_session_minutes),
- url(r'^session/(?P\d+)/propose_slides$', views.propose_session_slides),
url(r'^session/(?P\d+)/slides(?:/%(name)s)?$' % settings.URL_REGEXPS, views.upload_session_slides),
url(r'^session/(?P\d+)/add_to_session$', views.ajax_add_slides_to_session),
url(r'^session/(?P\d+)/remove_from_session$', views.ajax_remove_slides_from_session),
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 5218714c0f..e56df8ac0d 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -1702,7 +1702,7 @@ def api_get_session_materials(request, session_id=None):
minutes = session.minutes()
slides_actions = []
- if can_manage_session_materials(request.user, session.group, session):
+ if can_manage_session_materials(request.user, session.group, session) or not session.is_material_submission_cutoff():
slides_actions.append(
{
"label": "Upload slides",
@@ -1712,16 +1712,6 @@ def api_get_session_materials(request, session_id=None):
),
}
)
- elif not session.is_material_submission_cutoff():
- slides_actions.append(
- {
- "label": "Propose slides",
- "url": reverse(
- "ietf.meeting.views.propose_session_slides",
- kwargs={"num": session.meeting.number, "session_id": session.pk},
- ),
- }
- )
else:
pass # no action available if it's past cutoff
@@ -2926,10 +2916,7 @@ def upload_session_slides(request, session_id, num, name=None):
"""
# num is redundant, but we're dragging it along an artifact of where we are in the current URL structure
session = get_object_or_404(Session, pk=session_id)
- if not session.can_manage_materials(request.user):
- permission_denied(
- request, "You don't have permission to upload slides for this session."
- )
+ can_manage = session.can_manage_materials(request.user)
if session.is_material_submission_cutoff() and not has_role(
request.user, "Secretariat"
):
@@ -2954,7 +2941,7 @@ def upload_session_slides(request, session_id, num, name=None):
if request.method == "POST":
form = UploadSlidesForm(
- session, show_apply_to_all_checkbox, request.POST, request.FILES
+ session, show_apply_to_all_checkbox, can_manage, request.POST, request.FILES
)
if form.is_valid():
file = request.FILES["file"]
@@ -2962,6 +2949,46 @@ def upload_session_slides(request, session_id, num, name=None):
apply_to_all = session.type_id == "regular"
if show_apply_to_all_checkbox:
apply_to_all = form.cleaned_data["apply_to_all"]
+ if can_manage:
+ approved = form.cleaned_data["approved"]
+ else:
+ approved = False
+
+ # Propose slides if not auto-approved
+ if not approved:
+ title = form.cleaned_data['title']
+ submission = SlideSubmission.objects.create(session = session, title = title, filename = '', apply_to_all = apply_to_all, submitter=request.user.person)
+
+ if session.meeting.type_id=='ietf':
+ name = 'slides-%s-%s' % (session.meeting.number,
+ session.group.acronym)
+ if not apply_to_all:
+ name += '-%s' % (session.docname_token(),)
+ else:
+ name = 'slides-%s-%s' % (session.meeting.number, session.docname_token())
+ name = name + '-' + slugify(title).replace('_', '-')[:128]
+ filename = '%s-ss%d%s'% (name, submission.id, ext)
+ destination = io.open(os.path.join(settings.SLIDE_STAGING_PATH, filename),'wb+')
+ for chunk in file.chunks():
+ destination.write(chunk)
+ destination.close()
+
+ submission.filename = filename
+ submission.save()
+
+ (to, cc) = gather_address_lists('slides_proposed', group=session.group, proposer=request.user.person).as_strings()
+ msg_txt = render_to_string("meeting/slides_proposed.txt", {
+ "to": to,
+ "cc": cc,
+ "submission": submission,
+ "settings": settings,
+ })
+ msg = infer_message(msg_txt)
+ msg.by = request.user.person
+ msg.save()
+ send_mail_message(request, msg)
+ messages.success(request, 'Successfully submitted proposed slides.')
+ return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
# Handle creation / update of the Document (but do not save yet)
if doc is not None:
@@ -3075,7 +3102,7 @@ def upload_session_slides(request, session_id, num, name=None):
initial = {}
if doc is not None:
initial = {"title": doc.title}
- form = UploadSlidesForm(session, show_apply_to_all_checkbox, initial=initial)
+ form = UploadSlidesForm(session, show_apply_to_all_checkbox, can_manage, initial=initial)
return render(
request,
@@ -3083,79 +3110,12 @@ def upload_session_slides(request, session_id, num, name=None):
{
"session": session,
"session_number": session_number,
- "slides_sp": session.presentations.filter(document=doc).first() if doc else None,
+ "manage": session.can_manage_materials(request.user),
"form": form,
},
)
-@login_required
-def propose_session_slides(request, session_id, num):
- session = get_object_or_404(Session,pk=session_id)
- if session.is_material_submission_cutoff() and not has_role(request.user, "Secretariat"):
- permission_denied(request, "The materials cutoff for this session has passed. Contact the secretariat for further action.")
-
- session_number = None
- sessions = get_sessions(session.meeting.number,session.group.acronym)
- show_apply_to_all_checkbox = len(sessions) > 1 if session.type_id == 'regular' else False
- if len(sessions) > 1:
- session_number = 1 + sessions.index(session)
-
-
- if request.method == 'POST':
- form = UploadSlidesForm(session, show_apply_to_all_checkbox,request.POST,request.FILES)
- if form.is_valid():
- file = request.FILES['file']
- _, ext = os.path.splitext(file.name)
- apply_to_all = session.type_id == 'regular'
- if show_apply_to_all_checkbox:
- apply_to_all = form.cleaned_data['apply_to_all']
- title = form.cleaned_data['title']
-
- submission = SlideSubmission.objects.create(session = session, title = title, filename = '', apply_to_all = apply_to_all, submitter=request.user.person)
-
- if session.meeting.type_id=='ietf':
- name = 'slides-%s-%s' % (session.meeting.number,
- session.group.acronym)
- if not apply_to_all:
- name += '-%s' % (session.docname_token(),)
- else:
- name = 'slides-%s-%s' % (session.meeting.number, session.docname_token())
- name = name + '-' + slugify(title).replace('_', '-')[:128]
- filename = '%s-ss%d%s'% (name, submission.id, ext)
- destination = io.open(os.path.join(settings.SLIDE_STAGING_PATH, filename),'wb+')
- for chunk in file.chunks():
- destination.write(chunk)
- destination.close()
-
- submission.filename = filename
- submission.save()
-
- (to, cc) = gather_address_lists('slides_proposed', group=session.group, proposer=request.user.person).as_strings()
- msg_txt = render_to_string("meeting/slides_proposed.txt", {
- "to": to,
- "cc": cc,
- "submission": submission,
- "settings": settings,
- })
- msg = infer_message(msg_txt)
- msg.by = request.user.person
- msg.save()
- send_mail_message(request, msg)
- messages.success(request, 'Successfully submitted proposed slides.')
- return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
- else:
- initial = {}
- form = UploadSlidesForm(session, show_apply_to_all_checkbox, initial=initial)
-
- return render(request, "meeting/propose_session_slides.html",
- {'session': session,
- 'session_number': session_number,
- 'form': form,
- 'manage': session.can_manage_materials(request.user),
- })
-
-
def remove_sessionpresentation(request, session_id, num, name):
sp = get_object_or_404(
SessionPresentation, session_id=session_id, document__name=name
diff --git a/ietf/templates/meeting/propose_session_slides.html b/ietf/templates/meeting/propose_session_slides.html
deleted file mode 100644
index a375827961..0000000000
--- a/ietf/templates/meeting/propose_session_slides.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends "base.html" %}
-{# Copyright The IETF Trust 2015, All Rights Reserved #}
-{% load origin static django_bootstrap5 tz %}
-{% block title %}Propose Slides for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
-{% block content %}
- {% origin %}
-
- Propose Slides for {{ session.meeting }}
-
- {{ session.group.acronym }}
- {% if session.name %}: {{ session.name }}{% endif %}
-
-
- {% if session_number %}
-
- Session {{ session_number }} : {{ session.official_timeslotassignment.timeslot.time|timezone:session.meeting.time_zone|date:"D M-d-Y Hi" }}
-
- {% endif %}
- {% if not manage %}
-
- This form will allow you to propose a slide deck to the session chairs. After you upload your proposal, mail will be sent to the session chairs asking for their approval.
-
- {% endif %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/ietf/templates/meeting/session_details_panel.html b/ietf/templates/meeting/session_details_panel.html
index d053ba1c1c..1dcbded913 100644
--- a/ietf/templates/meeting/session_details_panel.html
+++ b/ietf/templates/meeting/session_details_panel.html
@@ -187,7 +187,7 @@ Slides
{% elif request.user.is_authenticated and not session.is_material_submission_cutoff %}
+ href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number %}">
Propose slides
{% endif %}
diff --git a/ietf/templates/meeting/slides_approved.txt b/ietf/templates/meeting/slides_approved.txt
index db288ad853..61ffafcd18 100644
--- a/ietf/templates/meeting/slides_approved.txt
+++ b/ietf/templates/meeting/slides_approved.txt
@@ -1,4 +1,4 @@
-{% load ietf_filters %}{% autoescape off %}Your proposed slides have been approved for {{ submission.session.meeting }} : {{ submission.session.group.acronym }}{% if submission.session.name %} : {{submission.session.name}}{% endif %}
+{% load ietf_filters %}{% autoescape off %}Your proposed slides have been approved for {{ submission.session.meeting }} : {{ submission.session.group.acronym }}{% if submission.session.name %} : {{submission.session.name}}{% endif %} by {{approver}}
Title: {{submission.title}}
diff --git a/ietf/templates/meeting/upload_session_slides.html b/ietf/templates/meeting/upload_session_slides.html
index 8e3e064df3..aa2737727a 100644
--- a/ietf/templates/meeting/upload_session_slides.html
+++ b/ietf/templates/meeting/upload_session_slides.html
@@ -1,23 +1,11 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin static django_bootstrap5 tz %}
-{% block title %}
- {% if slides_sp %}
- Revise
- {% else %}
- Upload new
- {% endif %}
- slides for {{ session.meeting }} : {{ session.group.acronym }}
-{% endblock %}
+{% block title %}Upload Slides for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
{% block content %}
{% origin %}
- {% if slides_sp %}
- Revise
- {% else %}
- Upload new
- {% endif %}
- slides for {{ session.meeting }}
+ Upload slides for {{ session.meeting }}
{{ session.group.acronym }}
@@ -25,9 +13,15 @@
{% if session_number %}
- Session {{ session_number }} : {{ session.official_timeslotassignment.timeslot.time|timezone:session.meeting.time_zone|date:"D M-d-Y Hi" }}
+
+ Session {{ session_number }} : {{ session.official_timeslotassignment.timeslot.time|timezone:session.meeting.time_zone|date:"D M-d-Y Hi" }}
+
+ {% endif %}
+ {% if not manage %}
+
+ This form will allow you to propose a slide deck to the session chairs. After you upload your proposal, mail will be sent to the session chairs asking for their approval.
+
{% endif %}
- {% if slides_sp %}{{ slides_sp.document.name }}
{% endif %}
{% endif %}
+ {% if slides_sp %}{{ slides_sp.document.name }}
{% endif %}