Skip to content

Commit 2603bf4

Browse files
committed
Merged in [18371] from mark@painless-security.com:
Track slide submissions even after acceptance or rejection. Fixes ietf-tools#2835. - Legacy-Id: 18421 Note: SVN reference [18371] has been migrated to Git commit 21ba67f
2 parents da7c22f + 8bde162 commit 2603bf4

File tree

11 files changed

+208
-18
lines changed

11 files changed

+208
-18
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 2.2.14 on 2020-08-03 11:53
2+
3+
from django.db import migrations
4+
import django.db.models.deletion
5+
import ietf.utils.models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('name', '0018_slidesubmissionstatusname'),
12+
('doc', '0035_populate_docextresources'),
13+
('meeting', '0030_allow_empty_joint_with_sessions'),
14+
]
15+
16+
operations = [
17+
migrations.AddField(
18+
model_name='slidesubmission',
19+
name='doc',
20+
field=ietf.utils.models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='doc.Document'),
21+
),
22+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 2.2.14 on 2020-08-03 11:53
2+
3+
from django.db import migrations
4+
import django.db.models.deletion
5+
import ietf.utils.models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('meeting', '0031_auto_20200803_1153'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='slidesubmission',
17+
name='status',
18+
field=ietf.utils.models.ForeignKey(null=True, default='pending', on_delete=django.db.models.deletion.SET_NULL, to='name.SlideSubmissionStatusName'),
19+
),
20+
]

ietf/meeting/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from ietf.doc.models import Document
3030
from ietf.group.models import Group
3131
from ietf.group.utils import can_manage_materials
32-
from ietf.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName, RoomResourceName, ImportantDateName, TimerangeName
32+
from ietf.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName, RoomResourceName, ImportantDateName, TimerangeName, SlideSubmissionStatusName
3333
from ietf.person.models import Person
3434
from ietf.utils.decorators import memoize
3535
from ietf.utils.storage import NoLocationMigrationFileSystemStorage
@@ -1277,6 +1277,8 @@ class SlideSubmission(models.Model):
12771277
filename = models.CharField(max_length=255)
12781278
apply_to_all = models.BooleanField(default=False)
12791279
submitter = ForeignKey(Person)
1280+
status = ForeignKey(SlideSubmissionStatusName, null=True, default='pending', on_delete=models.SET_NULL)
1281+
doc = ForeignKey(Document, null=True, on_delete=models.SET_NULL)
12801282

12811283
def staged_filepath(self):
12821284
return os.path.join(settings.SLIDE_STAGING_PATH , self.filename)

ietf/meeting/tests_views.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2788,14 +2788,19 @@ def test_propose_session_slides(self):
27882788
def test_disapprove_proposed_slides(self):
27892789
submission = SlideSubmissionFactory()
27902790
submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
2791+
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 1)
27912792
chair = RoleFactory(group=submission.session.group,name_id='chair').person
27922793
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
27932794
login_testing_unauthorized(self, chair.user.username, url)
27942795
r = self.client.get(url)
27952796
self.assertEqual(r.status_code,200)
27962797
r = self.client.post(url,dict(title='some title',disapprove="disapprove"))
27972798
self.assertEqual(r.status_code,302)
2798-
self.assertEqual(SlideSubmission.objects.count(), 0)
2799+
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'rejected').count(), 1)
2800+
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 0)
2801+
r = self.client.get(url)
2802+
self.assertEqual(r.status_code, 200)
2803+
self.assertContains(r, "These slides have already been rejected")
27992804

28002805
def test_approve_proposed_slides(self):
28012806
submission = SlideSubmissionFactory()
@@ -2804,13 +2809,22 @@ def test_approve_proposed_slides(self):
28042809
chair = RoleFactory(group=submission.session.group,name_id='chair').person
28052810
url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
28062811
login_testing_unauthorized(self, chair.user.username, url)
2812+
self.assertEqual(submission.status_id, 'pending')
2813+
self.assertIsNone(submission.doc)
28072814
r = self.client.get(url)
28082815
self.assertEqual(r.status_code,200)
28092816
r = self.client.post(url,dict(title='different title',approve='approve'))
28102817
self.assertEqual(r.status_code,302)
2811-
self.assertEqual(SlideSubmission.objects.count(), 0)
2818+
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 0)
2819+
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'approved').count(), 1)
2820+
submission = SlideSubmission.objects.get(id = submission.id)
2821+
self.assertEqual(submission.status_id, 'approved')
2822+
self.assertIsNotNone(submission.doc)
28122823
self.assertEqual(session.sessionpresentation_set.count(),1)
28132824
self.assertEqual(session.sessionpresentation_set.first().document.title,'different title')
2825+
r = self.client.get(url)
2826+
self.assertEqual(r.status_code, 200)
2827+
self.assertContains(r, "These slides have already been approved")
28142828

28152829
def test_approve_proposed_slides_multisession_apply_one(self):
28162830
submission = SlideSubmissionFactory(session__meeting__type_id='ietf')
@@ -2881,7 +2895,7 @@ def test_submit_and_approve_multiple_versions(self):
28812895
self.assertEqual(r.status_code, 302)
28822896
self.client.logout()
28832897

2884-
(first_submission, second_submission) = SlideSubmission.objects.filter(session=session).order_by('id')
2898+
(first_submission, second_submission) = SlideSubmission.objects.filter(session=session, status__slug = 'pending').order_by('id')
28852899

28862900
approve_url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':second_submission.pk,'num':second_submission.session.meeting.number})
28872901
login_testing_unauthorized(self, chair.user.username, approve_url)
@@ -2893,7 +2907,8 @@ def test_submit_and_approve_multiple_versions(self):
28932907
self.assertEqual(r.status_code,302)
28942908
self.client.logout()
28952909

2896-
self.assertEqual(SlideSubmission.objects.count(),0)
2910+
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(),0)
2911+
self.assertEqual(SlideSubmission.objects.filter(status__slug = 'rejected').count(),1)
28972912
self.assertEqual(session.sessionpresentation_set.first().document.rev,'01')
28982913
path = os.path.join(submission.session.meeting.get_materials_path(),'slides')
28992914
filename = os.path.join(path,session.sessionpresentation_set.first().document.name+'-01.txt')

ietf/meeting/views.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from django import forms
2727
from django.shortcuts import render, redirect, get_object_or_404
28-
from django.http import HttpResponse, HttpResponseRedirect, Http404
28+
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound, Http404
2929
from django.conf import settings
3030
from django.contrib import messages
3131
from django.contrib.auth.decorators import login_required
@@ -79,6 +79,7 @@
7979
from ietf.meeting.utils import data_for_meetings_overview
8080
from ietf.meeting.utils import preprocess_constraints_for_meeting_schedule_editor
8181
from ietf.message.utils import infer_message
82+
from ietf.name.models import SlideSubmissionStatusName
8283
from ietf.secr.proceedings.utils import handle_upload_file
8384
from ietf.secr.proceedings.proc_utils import (get_progress_stats, post_process, import_audio_files,
8485
create_recording)
@@ -1541,9 +1542,9 @@ def session_details(request, num, acronym):
15411542
pending_suggestions = None
15421543
if request.user.is_authenticated:
15431544
if can_manage:
1544-
pending_suggestions = session.slidesubmission_set.all()
1545+
pending_suggestions = session.slidesubmission_set.filter(status__slug='pending')
15451546
else:
1546-
pending_suggestions = session.slidesubmission_set.filter(submitter=request.user.person)
1547+
pending_suggestions = session.slidesubmission_set.filter(status__slug='pending', submitter=request.user.person)
15471548

15481549
return render(request, "meeting/session_details.html",
15491550
{ 'scheduled_sessions':scheduled_sessions ,
@@ -3146,13 +3147,16 @@ def approve_proposed_slides(request, slidesubmission_id, num):
31463147
name, _ = os.path.splitext(submission.filename)
31473148
name = name[:name.rfind('-ss')]
31483149
existing_doc = Document.objects.filter(name=name).first()
3149-
if request.method == 'POST':
3150+
if request.method == 'POST' and submission.status.slug == 'pending':
31503151
form = ApproveSlidesForm(show_apply_to_all_checkbox, request.POST)
31513152
if form.is_valid():
31523153
apply_to_all = submission.session.type_id == 'regular'
31533154
if show_apply_to_all_checkbox:
31543155
apply_to_all = form.cleaned_data['apply_to_all']
31553156
if request.POST.get('approve'):
3157+
# Ensure that we have a file to approve. The system gets cranky otherwise.
3158+
if submission.filename is None or submission.filename == '' or not os.path.isfile(submission.staged_filepath()):
3159+
return HttpResponseNotFound("The slides you attempted to approve could not be found. Please disapprove and delete them instead.")
31563160
title = form.cleaned_data['title']
31573161
if existing_doc:
31583162
doc = Document.objects.get(name=name)
@@ -3192,15 +3196,29 @@ def approve_proposed_slides(request, slidesubmission_id, num):
31923196
os.rename(submission.staged_filepath(), os.path.join(path, target_filename))
31933197
post_process(doc)
31943198
acronym = submission.session.group.acronym
3195-
submission.delete()
3199+
submission.status = SlideSubmissionStatusName.objects.get(slug='approved')
3200+
submission.doc = doc
3201+
submission.save()
31963202
return redirect('ietf.meeting.views.session_details',num=num,acronym=acronym)
31973203
elif request.POST.get('disapprove'):
3198-
os.unlink(submission.staged_filepath())
3204+
# Errors in processing a submit request sometimes result
3205+
# in a SlideSubmission object without a file. Handle
3206+
# this case and keep processing the 'disapprove' even if
3207+
# the filename doesn't exist.
3208+
try:
3209+
if submission.filename != None and submission.filename != '':
3210+
os.unlink(submission.staged_filepath())
3211+
except (FileNotFoundError, IsADirectoryError):
3212+
pass
31993213
acronym = submission.session.group.acronym
3200-
submission.delete()
3214+
submission.status = SlideSubmissionStatusName.objects.get(slug='rejected')
3215+
submission.save()
32013216
return redirect('ietf.meeting.views.session_details',num=num,acronym=acronym)
32023217
else:
32033218
pass
3219+
elif not submission.status.slug == 'pending':
3220+
return render(request, "meeting/previously_approved_slides.html",
3221+
{'submission': submission })
32043222
else:
32053223
initial = {
32063224
'title': submission.title,

ietf/name/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
ReviewRequestStateName, ReviewResultName, ReviewTypeName, RoleName, RoomResourceName,
1212
SessionStatusName, StdLevelName, StreamName, TimeSlotTypeName, TopicAudienceName,
1313
DocUrlTagName, ReviewAssignmentStateName, ReviewerQueuePolicyName, TimerangeName,
14-
ExtResourceName, ExtResourceTypeName, )
14+
ExtResourceName, ExtResourceTypeName, SlideSubmissionStatusName)
1515

1616

1717
from ietf.stats.models import CountryAlias
@@ -89,3 +89,4 @@ class ExtResourceNameAdmin(NameAdmin):
8989
admin.site.register(TopicAudienceName, NameAdmin)
9090
admin.site.register(DocUrlTagName, NameAdmin)
9191
admin.site.register(ExtResourceTypeName, NameAdmin)
92+
admin.site.register(SlideSubmissionStatusName, NameAdmin)

ietf/name/fixtures/names.json

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12077,6 +12077,36 @@
1207712077
"model": "name.sessionstatusname",
1207812078
"pk": "schedw"
1207912079
},
12080+
{
12081+
"fields": {
12082+
"desc": "Approved",
12083+
"name": "approved",
12084+
"order": 1,
12085+
"used": true
12086+
},
12087+
"model": "name.slidesubmissionstatusname",
12088+
"pk": "approved"
12089+
},
12090+
{
12091+
"fields": {
12092+
"desc": "Pending",
12093+
"name": "pending",
12094+
"order": 0,
12095+
"used": true
12096+
},
12097+
"model": "name.slidesubmissionstatusname",
12098+
"pk": "pending"
12099+
},
12100+
{
12101+
"fields": {
12102+
"desc": "Rejected",
12103+
"name": "rejected",
12104+
"order": 2,
12105+
"used": true
12106+
},
12107+
"model": "name.slidesubmissionstatusname",
12108+
"pk": "rejected"
12109+
},
1208012110
{
1208112111
"fields": {
1208212112
"desc": "",
@@ -14905,7 +14935,7 @@
1490514935
"fields": {
1490614936
"command": "xym",
1490714937
"switch": "--version",
14908-
"time": "2020-08-12T00:12:54.984",
14938+
"time": "2020-07-23T00:12:27.508",
1490914939
"used": true,
1491014940
"version": "xym 0.4.8"
1491114941
},
@@ -14916,7 +14946,7 @@
1491614946
"fields": {
1491714947
"command": "pyang",
1491814948
"switch": "--version",
14919-
"time": "2020-08-12T00:12:56.359",
14949+
"time": "2020-07-23T00:12:28.886",
1492014950
"used": true,
1492114951
"version": "pyang 2.3.2"
1492214952
},
@@ -14927,7 +14957,7 @@
1492714957
"fields": {
1492814958
"command": "yanglint",
1492914959
"switch": "--version",
14930-
"time": "2020-08-12T00:12:56.632",
14960+
"time": "2020-07-23T00:12:29.140",
1493114961
"used": true,
1493214962
"version": "yanglint SO 1.6.7"
1493314963
},
@@ -14938,7 +14968,7 @@
1493814968
"fields": {
1493914969
"command": "xml2rfc",
1494014970
"switch": "--version",
14941-
"time": "2020-08-12T00:12:58.366",
14971+
"time": "2020-07-23T00:12:30.892",
1494214972
"used": true,
1494314973
"version": "xml2rfc 2.47.0"
1494414974
},
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Generated by Django 2.2.14 on 2020-08-03 11:53
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('name', '0017_update_constraintname_order_and_label'),
10+
]
11+
12+
def forward(apps, schema_editor):
13+
SlideSubmissionStatusName = apps.get_model('name', 'SlideSubmissionStatusName')
14+
slide_submission_status_names = [
15+
('pending', 'Pending'),
16+
('approved', 'Approved'),
17+
('rejected', 'Rejected'),
18+
]
19+
for order, (slug, desc) in enumerate(slide_submission_status_names):
20+
SlideSubmissionStatusName.objects.create(slug=slug, name=slug, desc=desc, used=True, order=order)
21+
22+
23+
def reverse(apps, schema_editor):
24+
pass
25+
26+
operations = [
27+
migrations.CreateModel(
28+
name='SlideSubmissionStatusName',
29+
fields=[
30+
('slug', models.CharField(max_length=32, primary_key=True, serialize=False)),
31+
('name', models.CharField(max_length=255)),
32+
('desc', models.TextField(blank=True)),
33+
('used', models.BooleanField(default=True)),
34+
('order', models.IntegerField(default=0)),
35+
],
36+
options={
37+
'ordering': ['order', 'name'],
38+
'abstract': False,
39+
},
40+
),
41+
migrations.RunPython(forward, reverse),
42+
]

ietf/name/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,5 @@ class ExtResourceTypeName(NameModel):
130130
class ExtResourceName(NameModel):
131131
"""GitHub Repository URL, GitHub Username, ..."""
132132
type = ForeignKey(ExtResourceTypeName)
133+
class SlideSubmissionStatusName(NameModel):
134+
"Pending, Accepted, Rejected"

ietf/name/resources.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
LiaisonStatementState, LiaisonStatementTagName, MeetingTypeName, NomineePositionStateName,
1818
ReviewAssignmentStateName, ReviewRequestStateName, ReviewResultName, ReviewTypeName,
1919
RoleName, RoomResourceName, SessionStatusName, StdLevelName, StreamName, TimeSlotTypeName,
20-
TopicAudienceName, ReviewerQueuePolicyName, TimerangeName, ExtResourceTypeName, ExtResourceName)
20+
TopicAudienceName, ReviewerQueuePolicyName, TimerangeName, ExtResourceTypeName, ExtResourceName,
21+
SlideSubmissionStatusName)
2122

2223
class TimeSlotTypeNameResource(ModelResource):
2324
class Meta:
@@ -650,3 +651,20 @@ class Meta:
650651
"type": ALL_WITH_RELATIONS,
651652
}
652653
api.name.register(ExtResourceNameResource())
654+
655+
class SlideSubmissionStatusNameResource(ModelResource):
656+
class Meta:
657+
queryset = SlideSubmissionStatusName.objects.all()
658+
serializer = api.Serializer()
659+
cache = SimpleCache()
660+
resource_name = 'slidesubmissionstatusname'
661+
ordering = ['slug', ]
662+
filtering = {
663+
"slug": ALL,
664+
"name": ALL,
665+
"desc": ALL,
666+
"used": ALL,
667+
"order": ALL,
668+
}
669+
api.name.register(SlideSubmissionStatusNameResource())
670+

0 commit comments

Comments
 (0)