Merged in [18371] from mark@painless-security.com:
Track slide submissions even after acceptance or rejection. Fixes #2835.
- Legacy-Id: 18421
Note: SVN reference [18371] has been migrated to Git commit 21ba67fb79
This commit is contained in:
commit
2603bf4a23
22
ietf/meeting/migrations/0031_auto_20200803_1153.py
Normal file
22
ietf/meeting/migrations/0031_auto_20200803_1153.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 2.2.14 on 2020-08-03 11:53
|
||||
|
||||
from django.db import migrations
|
||||
import django.db.models.deletion
|
||||
import ietf.utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('name', '0018_slidesubmissionstatusname'),
|
||||
('doc', '0035_populate_docextresources'),
|
||||
('meeting', '0030_allow_empty_joint_with_sessions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='slidesubmission',
|
||||
name='doc',
|
||||
field=ietf.utils.models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='doc.Document'),
|
||||
),
|
||||
]
|
20
ietf/meeting/migrations/0032_auto_20200824_1642.py
Normal file
20
ietf/meeting/migrations/0032_auto_20200824_1642.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.2.14 on 2020-08-03 11:53
|
||||
|
||||
from django.db import migrations
|
||||
import django.db.models.deletion
|
||||
import ietf.utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('meeting', '0031_auto_20200803_1153'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='slidesubmission',
|
||||
name='status',
|
||||
field=ietf.utils.models.ForeignKey(null=True, default='pending', on_delete=django.db.models.deletion.SET_NULL, to='name.SlideSubmissionStatusName'),
|
||||
),
|
||||
]
|
|
@ -29,7 +29,7 @@ from ietf.dbtemplate.models import DBTemplate
|
|||
from ietf.doc.models import Document
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_materials
|
||||
from ietf.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName, RoomResourceName, ImportantDateName, TimerangeName
|
||||
from ietf.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName, RoomResourceName, ImportantDateName, TimerangeName, SlideSubmissionStatusName
|
||||
from ietf.person.models import Person
|
||||
from ietf.utils.decorators import memoize
|
||||
from ietf.utils.storage import NoLocationMigrationFileSystemStorage
|
||||
|
@ -1277,6 +1277,8 @@ class SlideSubmission(models.Model):
|
|||
filename = models.CharField(max_length=255)
|
||||
apply_to_all = models.BooleanField(default=False)
|
||||
submitter = ForeignKey(Person)
|
||||
status = ForeignKey(SlideSubmissionStatusName, null=True, default='pending', on_delete=models.SET_NULL)
|
||||
doc = ForeignKey(Document, null=True, on_delete=models.SET_NULL)
|
||||
|
||||
def staged_filepath(self):
|
||||
return os.path.join(settings.SLIDE_STAGING_PATH , self.filename)
|
||||
|
|
|
@ -2788,6 +2788,7 @@ class MaterialsTests(TestCase):
|
|||
def test_disapprove_proposed_slides(self):
|
||||
submission = SlideSubmissionFactory()
|
||||
submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
|
||||
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 1)
|
||||
chair = RoleFactory(group=submission.session.group,name_id='chair').person
|
||||
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
|
||||
login_testing_unauthorized(self, chair.user.username, url)
|
||||
|
@ -2795,7 +2796,11 @@ class MaterialsTests(TestCase):
|
|||
self.assertEqual(r.status_code,200)
|
||||
r = self.client.post(url,dict(title='some title',disapprove="disapprove"))
|
||||
self.assertEqual(r.status_code,302)
|
||||
self.assertEqual(SlideSubmission.objects.count(), 0)
|
||||
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'rejected').count(), 1)
|
||||
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 0)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, "These slides have already been rejected")
|
||||
|
||||
def test_approve_proposed_slides(self):
|
||||
submission = SlideSubmissionFactory()
|
||||
|
@ -2804,13 +2809,22 @@ class MaterialsTests(TestCase):
|
|||
chair = RoleFactory(group=submission.session.group,name_id='chair').person
|
||||
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
|
||||
login_testing_unauthorized(self, chair.user.username, url)
|
||||
self.assertEqual(submission.status_id, 'pending')
|
||||
self.assertIsNone(submission.doc)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,200)
|
||||
r = self.client.post(url,dict(title='different title',approve='approve'))
|
||||
self.assertEqual(r.status_code,302)
|
||||
self.assertEqual(SlideSubmission.objects.count(), 0)
|
||||
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 0)
|
||||
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'approved').count(), 1)
|
||||
submission = SlideSubmission.objects.get(id = submission.id)
|
||||
self.assertEqual(submission.status_id, 'approved')
|
||||
self.assertIsNotNone(submission.doc)
|
||||
self.assertEqual(session.sessionpresentation_set.count(),1)
|
||||
self.assertEqual(session.sessionpresentation_set.first().document.title,'different title')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, "These slides have already been approved")
|
||||
|
||||
def test_approve_proposed_slides_multisession_apply_one(self):
|
||||
submission = SlideSubmissionFactory(session__meeting__type_id='ietf')
|
||||
|
@ -2881,7 +2895,7 @@ class MaterialsTests(TestCase):
|
|||
self.assertEqual(r.status_code, 302)
|
||||
self.client.logout()
|
||||
|
||||
(first_submission, second_submission) = SlideSubmission.objects.filter(session=session).order_by('id')
|
||||
(first_submission, second_submission) = SlideSubmission.objects.filter(session=session, status__slug = 'pending').order_by('id')
|
||||
|
||||
approve_url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':second_submission.pk,'num':second_submission.session.meeting.number})
|
||||
login_testing_unauthorized(self, chair.user.username, approve_url)
|
||||
|
@ -2893,7 +2907,8 @@ class MaterialsTests(TestCase):
|
|||
self.assertEqual(r.status_code,302)
|
||||
self.client.logout()
|
||||
|
||||
self.assertEqual(SlideSubmission.objects.count(),0)
|
||||
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(),0)
|
||||
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'rejected').count(),1)
|
||||
self.assertEqual(session.sessionpresentation_set.first().document.rev,'01')
|
||||
path = os.path.join(submission.session.meeting.get_materials_path(),'slides')
|
||||
filename = os.path.join(path,session.sessionpresentation_set.first().document.name+'-01.txt')
|
||||
|
|
|
@ -25,7 +25,7 @@ from wsgiref.handlers import format_date_time
|
|||
|
||||
from django import forms
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound, Http404
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
@ -79,6 +79,7 @@ from ietf.meeting.utils import current_session_status
|
|||
from ietf.meeting.utils import data_for_meetings_overview
|
||||
from ietf.meeting.utils import preprocess_constraints_for_meeting_schedule_editor
|
||||
from ietf.message.utils import infer_message
|
||||
from ietf.name.models import SlideSubmissionStatusName
|
||||
from ietf.secr.proceedings.utils import handle_upload_file
|
||||
from ietf.secr.proceedings.proc_utils import (get_progress_stats, post_process, import_audio_files,
|
||||
create_recording)
|
||||
|
@ -1541,9 +1542,9 @@ def session_details(request, num, acronym):
|
|||
pending_suggestions = None
|
||||
if request.user.is_authenticated:
|
||||
if can_manage:
|
||||
pending_suggestions = session.slidesubmission_set.all()
|
||||
pending_suggestions = session.slidesubmission_set.filter(status__slug='pending')
|
||||
else:
|
||||
pending_suggestions = session.slidesubmission_set.filter(submitter=request.user.person)
|
||||
pending_suggestions = session.slidesubmission_set.filter(status__slug='pending', submitter=request.user.person)
|
||||
|
||||
return render(request, "meeting/session_details.html",
|
||||
{ 'scheduled_sessions':scheduled_sessions ,
|
||||
|
@ -3146,13 +3147,16 @@ def approve_proposed_slides(request, slidesubmission_id, num):
|
|||
name, _ = os.path.splitext(submission.filename)
|
||||
name = name[:name.rfind('-ss')]
|
||||
existing_doc = Document.objects.filter(name=name).first()
|
||||
if request.method == 'POST':
|
||||
if request.method == 'POST' and submission.status.slug == 'pending':
|
||||
form = ApproveSlidesForm(show_apply_to_all_checkbox, request.POST)
|
||||
if form.is_valid():
|
||||
apply_to_all = submission.session.type_id == 'regular'
|
||||
if show_apply_to_all_checkbox:
|
||||
apply_to_all = form.cleaned_data['apply_to_all']
|
||||
if request.POST.get('approve'):
|
||||
# Ensure that we have a file to approve. The system gets cranky otherwise.
|
||||
if submission.filename is None or submission.filename == '' or not os.path.isfile(submission.staged_filepath()):
|
||||
return HttpResponseNotFound("The slides you attempted to approve could not be found. Please disapprove and delete them instead.")
|
||||
title = form.cleaned_data['title']
|
||||
if existing_doc:
|
||||
doc = Document.objects.get(name=name)
|
||||
|
@ -3192,15 +3196,29 @@ def approve_proposed_slides(request, slidesubmission_id, num):
|
|||
os.rename(submission.staged_filepath(), os.path.join(path, target_filename))
|
||||
post_process(doc)
|
||||
acronym = submission.session.group.acronym
|
||||
submission.delete()
|
||||
submission.status = SlideSubmissionStatusName.objects.get(slug='approved')
|
||||
submission.doc = doc
|
||||
submission.save()
|
||||
return redirect('ietf.meeting.views.session_details',num=num,acronym=acronym)
|
||||
elif request.POST.get('disapprove'):
|
||||
os.unlink(submission.staged_filepath())
|
||||
# Errors in processing a submit request sometimes result
|
||||
# in a SlideSubmission object without a file. Handle
|
||||
# this case and keep processing the 'disapprove' even if
|
||||
# the filename doesn't exist.
|
||||
try:
|
||||
if submission.filename != None and submission.filename != '':
|
||||
os.unlink(submission.staged_filepath())
|
||||
except (FileNotFoundError, IsADirectoryError):
|
||||
pass
|
||||
acronym = submission.session.group.acronym
|
||||
submission.delete()
|
||||
submission.status = SlideSubmissionStatusName.objects.get(slug='rejected')
|
||||
submission.save()
|
||||
return redirect('ietf.meeting.views.session_details',num=num,acronym=acronym)
|
||||
else:
|
||||
pass
|
||||
elif not submission.status.slug == 'pending':
|
||||
return render(request, "meeting/previously_approved_slides.html",
|
||||
{'submission': submission })
|
||||
else:
|
||||
initial = {
|
||||
'title': submission.title,
|
||||
|
|
|
@ -11,7 +11,7 @@ from ietf.name.models import (
|
|||
ReviewRequestStateName, ReviewResultName, ReviewTypeName, RoleName, RoomResourceName,
|
||||
SessionStatusName, StdLevelName, StreamName, TimeSlotTypeName, TopicAudienceName,
|
||||
DocUrlTagName, ReviewAssignmentStateName, ReviewerQueuePolicyName, TimerangeName,
|
||||
ExtResourceName, ExtResourceTypeName, )
|
||||
ExtResourceName, ExtResourceTypeName, SlideSubmissionStatusName)
|
||||
|
||||
|
||||
from ietf.stats.models import CountryAlias
|
||||
|
@ -89,3 +89,4 @@ admin.site.register(TimerangeName, NameAdmin)
|
|||
admin.site.register(TopicAudienceName, NameAdmin)
|
||||
admin.site.register(DocUrlTagName, NameAdmin)
|
||||
admin.site.register(ExtResourceTypeName, NameAdmin)
|
||||
admin.site.register(SlideSubmissionStatusName, NameAdmin)
|
||||
|
|
|
@ -12077,6 +12077,36 @@
|
|||
"model": "name.sessionstatusname",
|
||||
"pk": "schedw"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "Approved",
|
||||
"name": "approved",
|
||||
"order": 1,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.slidesubmissionstatusname",
|
||||
"pk": "approved"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "Pending",
|
||||
"name": "pending",
|
||||
"order": 0,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.slidesubmissionstatusname",
|
||||
"pk": "pending"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "Rejected",
|
||||
"name": "rejected",
|
||||
"order": 2,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.slidesubmissionstatusname",
|
||||
"pk": "rejected"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
|
@ -14905,7 +14935,7 @@
|
|||
"fields": {
|
||||
"command": "xym",
|
||||
"switch": "--version",
|
||||
"time": "2020-08-12T00:12:54.984",
|
||||
"time": "2020-07-23T00:12:27.508",
|
||||
"used": true,
|
||||
"version": "xym 0.4.8"
|
||||
},
|
||||
|
@ -14916,7 +14946,7 @@
|
|||
"fields": {
|
||||
"command": "pyang",
|
||||
"switch": "--version",
|
||||
"time": "2020-08-12T00:12:56.359",
|
||||
"time": "2020-07-23T00:12:28.886",
|
||||
"used": true,
|
||||
"version": "pyang 2.3.2"
|
||||
},
|
||||
|
@ -14927,7 +14957,7 @@
|
|||
"fields": {
|
||||
"command": "yanglint",
|
||||
"switch": "--version",
|
||||
"time": "2020-08-12T00:12:56.632",
|
||||
"time": "2020-07-23T00:12:29.140",
|
||||
"used": true,
|
||||
"version": "yanglint SO 1.6.7"
|
||||
},
|
||||
|
@ -14938,7 +14968,7 @@
|
|||
"fields": {
|
||||
"command": "xml2rfc",
|
||||
"switch": "--version",
|
||||
"time": "2020-08-12T00:12:58.366",
|
||||
"time": "2020-07-23T00:12:30.892",
|
||||
"used": true,
|
||||
"version": "xml2rfc 2.47.0"
|
||||
},
|
||||
|
|
42
ietf/name/migrations/0018_slidesubmissionstatusname.py
Normal file
42
ietf/name/migrations/0018_slidesubmissionstatusname.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Generated by Django 2.2.14 on 2020-08-03 11:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('name', '0017_update_constraintname_order_and_label'),
|
||||
]
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
SlideSubmissionStatusName = apps.get_model('name', 'SlideSubmissionStatusName')
|
||||
slide_submission_status_names = [
|
||||
('pending', 'Pending'),
|
||||
('approved', 'Approved'),
|
||||
('rejected', 'Rejected'),
|
||||
]
|
||||
for order, (slug, desc) in enumerate(slide_submission_status_names):
|
||||
SlideSubmissionStatusName.objects.create(slug=slug, name=slug, desc=desc, used=True, order=order)
|
||||
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
pass
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SlideSubmissionStatusName',
|
||||
fields=[
|
||||
('slug', models.CharField(max_length=32, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('desc', models.TextField(blank=True)),
|
||||
('used', models.BooleanField(default=True)),
|
||||
('order', models.IntegerField(default=0)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['order', 'name'],
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
|
@ -130,3 +130,5 @@ class ExtResourceTypeName(NameModel):
|
|||
class ExtResourceName(NameModel):
|
||||
"""GitHub Repository URL, GitHub Username, ..."""
|
||||
type = ForeignKey(ExtResourceTypeName)
|
||||
class SlideSubmissionStatusName(NameModel):
|
||||
"Pending, Accepted, Rejected"
|
||||
|
|
|
@ -17,7 +17,8 @@ from ietf.name.models import ( AgendaTypeName, BallotPositionName, ConstraintNam
|
|||
LiaisonStatementState, LiaisonStatementTagName, MeetingTypeName, NomineePositionStateName,
|
||||
ReviewAssignmentStateName, ReviewRequestStateName, ReviewResultName, ReviewTypeName,
|
||||
RoleName, RoomResourceName, SessionStatusName, StdLevelName, StreamName, TimeSlotTypeName,
|
||||
TopicAudienceName, ReviewerQueuePolicyName, TimerangeName, ExtResourceTypeName, ExtResourceName)
|
||||
TopicAudienceName, ReviewerQueuePolicyName, TimerangeName, ExtResourceTypeName, ExtResourceName,
|
||||
SlideSubmissionStatusName)
|
||||
|
||||
class TimeSlotTypeNameResource(ModelResource):
|
||||
class Meta:
|
||||
|
@ -650,3 +651,20 @@ class ExtResourceNameResource(ModelResource):
|
|||
"type": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.name.register(ExtResourceNameResource())
|
||||
|
||||
class SlideSubmissionStatusNameResource(ModelResource):
|
||||
class Meta:
|
||||
queryset = SlideSubmissionStatusName.objects.all()
|
||||
serializer = api.Serializer()
|
||||
cache = SimpleCache()
|
||||
resource_name = 'slidesubmissionstatusname'
|
||||
ordering = ['slug', ]
|
||||
filtering = {
|
||||
"slug": ALL,
|
||||
"name": ALL,
|
||||
"desc": ALL,
|
||||
"used": ALL,
|
||||
"order": ALL,
|
||||
}
|
||||
api.name.register(SlideSubmissionStatusNameResource())
|
||||
|
||||
|
|
20
ietf/templates/meeting/previously_approved_slides.html
Normal file
20
ietf/templates/meeting/previously_approved_slides.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2020, All Rights Reserved #}
|
||||
{% load origin staticfiles bootstrap3 %}
|
||||
|
||||
{% block title %}Approved Slides for {{ submission.session.meeting }} : {{ submission.session.group.acronym }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
|
||||
<h1>These slides have already been {% if submission.status.slug == 'approved' %} approved {% else %} rejected {% endif %}</h1>
|
||||
|
||||
<p>The slides from {{ submission.submitter }} have already been {% if submission.status.slug == 'approved' %} approved {% else %} rejected {% endif %}. No further action is needed.</p>
|
||||
|
||||
<p>You may wish to
|
||||
{% if submission.status.slug == 'approved' and submission.doc %}
|
||||
<a href="{% url 'ietf.doc.views_doc.document_main' name=submission.doc.name %}">view the slides</a> or
|
||||
{% endif %}
|
||||
<a href="{% url "ietf.meeting.views.session_details" num=submission.session.meeting.number acronym=submission.session.group.acronym %}">return to this meeting session</a>.</p>
|
||||
|
||||
{% endblock %}
|
Loading…
Reference in a new issue