Merged in [13615] and [13627]from rcross@amsl.com:

Changed views that use GET requests to delete objects to use POST.
Fixes #1796.
 - Legacy-Id: 13654
Note: SVN reference [13615] has been migrated to Git commit 3ccb550888

Note: SVN reference [13627] has been migrated to Git commit b908caf95c
This commit is contained in:
Henrik Levkowetz 2017-06-16 14:20:01 +00:00
commit 7ecf7dfa44
11 changed files with 143 additions and 41 deletions

View file

@ -1,5 +1,6 @@
# -*- conf-mode -*-
/personal/rcross/6.54.2.dev0@13632 # resolved differently in [13653]
/personal/lars/6.48.2.dev0@13124 # fails drag-and-drop test
/branch/proceedings/6.29.1.dev0@11850 # Merged into /branch/proceedings/6.30.1.dev0, will be merged from there
/branch/proceedings/6.29.1.dev0@11856 # Merged into /branch/proceedings/6.30.1.dev0, will be merged from there

View file

@ -154,3 +154,16 @@ class SecrDraftsTestCase(TestCase):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_author_delete(self):
draft = make_test_data()
author = draft.documentauthor_set.first()
id = author.id
url = urlreverse('ietf.secr.drafts.views.author_delete', kwargs={'id':draft.name, 'oid':id})
self.client.login(username="secretary", password="secretary+password")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
redirect_url = urlreverse('ietf.secr.drafts.views.authors', kwargs={'id':draft.name})
response = self.client.post(url, {'post':'yes'})
self.assertRedirects(response, redirect_url)
self.assertFalse(draft.documentauthor_set.filter(id=id))

View file

@ -542,9 +542,14 @@ def author_delete(request, id, oid):
'''
This view deletes the specified author from the draft
'''
DocumentAuthor.objects.get(id=oid).delete()
messages.success(request, 'The author was deleted successfully')
return redirect('ietf.secr.drafts.views.authors', id=id)
author = DocumentAuthor.objects.get(id=oid)
if request.method == 'POST' and request.POST['post'] == 'yes':
author.delete()
messages.success(request, 'The author was deleted successfully')
return redirect('ietf.secr.drafts.views.authors', id=id)
return render(request, 'confirm_delete.html', {'object': author})
@role_required('Secretariat')
def authors(request, id):

View file

@ -140,12 +140,15 @@ class GroupsTest(TestCase):
make_test_data()
group = Group.objects.filter(acronym='mars')[0]
role = group.role_set.all()[0]
id = role.id
url = reverse('ietf.secr.groups.views.delete_role', kwargs={'acronym':group.acronym,'id':role.id})
target = reverse('ietf.secr.groups.views.people', kwargs={'acronym':group.acronym})
self.client.login(username="secretary", password="secretary+password")
response = self.client.get(url,follow=True)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = self.client.post(url, {'post':'yes'})
self.assertRedirects(response, target)
self.assertTrue('deleted successfully' in response.content)
self.assertFalse(group.role_set.filter(id=id))
def test_people_add(self):
make_test_data()

View file

@ -190,14 +190,17 @@ def delete_role(request, acronym, id):
"""
group = get_object_or_404(Group, acronym=acronym)
role = get_object_or_404(Role, id=id)
if request.method == 'POST' and request.POST['post'] == 'yes':
# save group
save_group_in_history(group)
# save group
save_group_in_history(group)
role.delete()
messages.success(request, 'The entry was deleted successfully')
return redirect('ietf.secr.groups.views.people', acronym=acronym)
role.delete()
return render(request, 'confirm_delete.html', {'object': role})
messages.success(request, 'The entry was deleted successfully')
return redirect('ietf.secr.groups.views.people', acronym=acronym)
@role_required('Secretariat')
def edit(request, acronym):

View file

@ -236,13 +236,19 @@ class SecrMeetingTestCase(TestCase):
before = qs.count()
expected_deletion_count = qs.filter(time=qs.first().time).count()
url = reverse('ietf.secr.meetings.views.times_delete',kwargs={
'meeting_id':42,
'schedule_name':'test-agenda',
'meeting_id':meeting.number,
'schedule_name':meeting.agenda.name,
'time':qs.first().time.strftime("%Y:%m:%d:%H:%M")
})
redirect_url = reverse('ietf.secr.meetings.views.times',kwargs={
'meeting_id':meeting.number,
'schedule_name':meeting.agenda.name
})
self.client.login(username="secretary", password="secretary+password")
response = self.client.get(url)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.status_code, 200)
response = self.client.post(url, {'post':'yes'})
self.assertRedirects(response, redirect_url)
after = TimeSlot.objects.filter(meeting=meeting,type='session').count()
self.assertEqual(after,before - expected_deletion_count)
@ -312,6 +318,18 @@ class SecrMeetingTestCase(TestCase):
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,new_time)
def test_meetings_non_session_delete(self):
meeting = make_meeting_test_data()
slot = meeting.agenda.assignments.filter(timeslot__type='reg').first().timeslot
url = reverse('ietf.secr.meetings.views.non_session_delete', kwargs={'meeting_id':meeting.number,'schedule_name':meeting.agenda.name,'slot_id':slot.id})
target = reverse('ietf.secr.meetings.views.non_session', kwargs={'meeting_id':meeting.number,'schedule_name':meeting.agenda.name})
self.client.login(username="secretary", password="secretary+password")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = self.client.post(url, {'post':'yes'})
self.assertRedirects(response, target)
self.assertFalse(meeting.agenda.assignments.filter(timeslot=slot))
def test_meetings_select_group(self):
make_meeting_test_data()
url = reverse('ietf.secr.meetings.views.select_group',kwargs={'meeting_id':42,'schedule_name':'test-agenda'})
@ -321,6 +339,17 @@ class SecrMeetingTestCase(TestCase):
q = PyQuery(response.content)
self.assertEqual(len(q("#id_scheduled_sessions")),1)
def test_meetings_schedule(self):
meeting = make_meeting_test_data()
url = reverse('ietf.secr.meetings.views.schedule',kwargs={
'meeting_id':meeting.number,
'schedule_name':meeting.agenda.name,
'acronym':'mars'
})
self.client.login(username="secretary", password="secretary+password")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
# ----------------------
# Unit Tests
# -----------------------

View file

@ -18,6 +18,7 @@ from ietf.utils.mail import send_mail
from ietf.meeting.forms import duration_string
from ietf.meeting.helpers import get_meeting, make_materials_directories
from ietf.meeting.models import Meeting, Session, Room, TimeSlot, SchedTimeSessAssignment, Schedule
from ietf.name.models import SessionStatusName
from ietf.group.models import Group, GroupEvent
from ietf.person.models import Person
from ietf.secr.meetings.blue_sheets import create_blue_sheets
@ -517,26 +518,30 @@ def non_session(request, meeting_id, schedule_name):
@role_required('Secretariat')
def non_session_delete(request, meeting_id, schedule_name, slot_id):
'''
This function deletes the non-session TimeSlot. For "other" and "plenary" timeslot
types we need to delete the corresponding Session object as well. Check for uploaded
This function deletes the non-session TimeSlot. Check for uploaded
material first. SchedTimeSessAssignment objects get deleted as well.
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
# schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
slot = get_object_or_404(TimeSlot, id=slot_id)
if slot.type_id in ('other','plenary','lead'):
assignments = slot.sessionassignments.filter(schedule__meeting=meeting)
assert slot.type_id in ('other','plenary','lead', 'reg')
if request.method == 'POST' and request.POST['post'] == 'yes':
assignments = slot.sessionassignments.all()
session_objects = [ x.session for x in assignments ]
for session in session_objects:
if session.materials.exclude(states__slug='deleted'):
messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name)
return redirect('ietf.secr.meetings.views.non_session', meeting_id=meeting_id, schedule_name=schedule_name)
else:
Session.objects.filter(pk__in=[ x.pk for x in session_objects ]).delete()
slot.delete()
# delete high order assignments, then sessions and slots
assignments.delete()
Session.objects.filter(pk__in=[ x.pk for x in session_objects ]).delete()
slot.delete()
messages.success(request, 'Non-Session timeslot deleted successfully')
return redirect('ietf.secr.meetings.views.non_session', meeting_id=meeting_id, schedule_name=schedule_name)
messages.success(request, 'The entry was deleted successfully')
return redirect('ietf.secr.meetings.views.non_session', meeting_id=meeting_id, schedule_name=schedule_name)
return render(request, 'confirm_delete.html', {'object': slot})
@role_required('Secretariat')
def non_session_edit(request, meeting_id, schedule_name, slot_id):
@ -1004,11 +1009,24 @@ def times_delete(request, meeting_id, schedule_name, time):
parts = [ int(x) for x in time.split(':') ]
dtime = datetime.datetime(*parts)
status = SessionStatusName.objects.get(slug='schedw')
TimeSlot.objects.filter(meeting=meeting,time=dtime).delete()
if request.method == 'POST' and request.POST['post'] == 'yes':
for slot in TimeSlot.objects.filter(meeting=meeting,time=dtime):
for assignment in slot.sessionassignments.all():
if assignment.session:
session = assignment.session
session.status = status
session.save()
assignment.delete()
slot.delete()
messages.success(request, 'The entry was deleted successfully')
return redirect('ietf.secr.meetings.views.times', meeting_id=meeting_id,schedule_name=schedule_name)
messages.success(request, 'Timeslot deleted')
return redirect('ietf.secr.meetings.views.times', meeting_id=meeting_id,schedule_name=schedule_name)
return render(request, 'confirm_delete.html', {
'object': '%s timeslots' % dtime.strftime("%A %H:%M"),
'extra': 'Any sessions assigned to this timeslot will be unscheduled'
})
@role_required('Secretariat')
def unschedule(request, meeting_id, schedule_name, session_id):

View file

@ -28,13 +28,16 @@ class SecrRolesMainTestCase(TestCase):
augment_data()
group = Group.objects.filter(acronym='mars')[0]
role = group.role_set.all()[0]
id = role.id
url = reverse('ietf.secr.roles.views.delete_role', kwargs={'acronym':group.acronym,'id':role.id})
target = reverse('ietf.secr.roles.views.main') + '?group=%s' % group.acronym
target = reverse('ietf.secr.roles.views.main')
self.client.login(username="secretary", password="secretary+password")
response = self.client.get(url,follow=True)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = self.client.post(url, {'post':'yes'})
self.assertRedirects(response, target)
self.assertTrue('deleted successfully' in response.content)
self.assertFalse(group.role_set.filter(id=id))
def test_roles_add(self):
make_test_data()
augment_data()

View file

@ -1,7 +1,7 @@
from django.contrib import messages
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.shortcuts import render, get_object_or_404, redirect
from ietf.group.models import Group, Role
from ietf.group.utils import save_group_in_history
@ -53,14 +53,15 @@ def delete_role(request, acronym, id):
role = get_object_or_404(Role, id=id)
group = get_object_or_404(Group, acronym=acronym)
# save group
save_group_in_history(role.group)
role.delete()
messages.success(request, 'The entry was deleted successfully')
url = reverse('ietf.secr.roles.views.main') + '?group=%s' % group.acronym
return HttpResponseRedirect(url)
if request.method == 'POST' and request.POST['post'] == 'yes':
# save group
save_group_in_history(group)
role.delete()
messages.success(request, 'The entry was deleted successfully')
return redirect('ietf.secr.roles.views.main')
return render(request, 'confirm_delete.html', {'object': role})
@role_required('Secretariat')
def main(request):

View file

@ -0,0 +1,26 @@
{% extends "base_site.html" %}
{% load staticfiles %}
{% block title %}Confirm Delete{% endblock %}
{% block content %}
<div class="module draft-container">
<h2>Confirm Delete</h2>
<h3>Are you sure?</h3>
<p>You are about to delete: {{ object }}</p>
{% if extra %}<p>{{ extra }}</p>{% endif %}
<form action="" method="post">{% csrf_token %}
<div>
<p>
<input type="hidden" name="post" value="yes">
<input type="submit" value="Yes, I'm sure">
<a href="#" onclick="history.go(-1);return false;" class="button cancel-link">Take me back</a>
</p>
</div>
</form>
</div> <!-- module -->
{% endblock %}

View file

@ -23,7 +23,7 @@
<td>{{ item.time|date:"H:i" }} - {{ item.end_time|date:"H:i" }}</td>
<td>{{ item.name }}</td>
<td><a href="{% url "ietf.secr.meetings.views.times_edit" meeting_id=meeting.number schedule_name=schedule.name time=item.time|date:"Y:m:d:H:i" %}">Edit</a></td>
<td><a href="{% url "ietf.secr.meetings.views.times_delete" meeting_id=meeting.number schedule_name=schedule.name time=item.time|date:"Y:m:d:H:i" %}" onclick="return window.confirm('Are you sure you want to delete this timeslot? Any sessions assigned to this timeslot will be unscheduled.');">Delete</a></td>
<td><a href="{% url "ietf.secr.meetings.views.times_delete" meeting_id=meeting.number schedule_name=schedule.name time=item.time|date:"Y:m:d:H:i" %}">Delete</a></td>
</tr>
{% endfor %}
</tbody>