Merge lp:~summit-hackers/summit/rm-rf into lp:summit

Proposed by Chris Johnston on 2012-10-04
Status: Merged
Approved by: Michael Hall on 2012-10-09
Approved revision: 457
Merged at revision: 452
Proposed branch: lp:~summit-hackers/summit/rm-rf
Merge into: lp:summit
Diff against target: 265 lines (+161/-4)
9 files modified
summit/common/templatetags/menubuilder.py (+2/-0)
summit/schedule/admin/meetingadmin.py (+1/-1)
summit/schedule/models/meetingmodel.py (+2/-1)
summit/schedule/templates/schedule/admin.html (+3/-0)
summit/schedule/templates/schedule/confirm_deletion.html (+16/-0)
summit/schedule/templates/schedule/delete_confirm.html (+20/-0)
summit/schedule/tests.py (+75/-2)
summit/schedule/views.py (+39/-0)
summit/urls.py (+3/-0)
To merge this branch: bzr merge lp:~summit-hackers/summit/rm-rf
Reviewer Review Type Date Requested Status
Michael Hall (community) 2012-10-04 Approve on 2012-10-09
Review via email: mp+128078@code.launchpad.net

Commit Message

Adds ability for summit.schedulers and is_staff to delete meetings from the front end

To post a comment you must log in.
lp:~summit-hackers/summit/rm-rf updated on 2012-10-09
452. By Michael Hall on 2012-10-09

work from chris

453. By Michael Hall on 2012-10-09

Fixes to delete meeting tests

454. By Chris Johnston on 2012-10-09

Fixes one broken view

455. By Chris Johnston on 2012-10-09

Adds missing test

456. By Michael Hall on 2012-10-09

Remove debug prints, mark a meeting as REMOVED instead of actually deleting the record

457. By Michael Hall on 2012-10-09

Allow admin to filter by approved state, don't mark removed meetings as approved when importing again from launchpad

Michael Hall (mhall119) wrote :

Working well, tests pass

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'summit/common/templatetags/menubuilder.py'
2--- summit/common/templatetags/menubuilder.py 2012-10-03 21:01:17 +0000
3+++ summit/common/templatetags/menubuilder.py 2012-10-09 19:03:21 +0000
4@@ -19,6 +19,8 @@
5 self.menu_name = menu_name
6
7 def render(self, context):
8+ if 'request' not in context:
9+ return ''
10 real_menu_name = context.get(self.menu_name, self.menu_name)
11 current_path = context['request'].path
12 user = context['request'].user
13
14=== modified file 'summit/schedule/admin/meetingadmin.py'
15--- summit/schedule/admin/meetingadmin.py 2012-10-02 02:23:02 +0000
16+++ summit/schedule/admin/meetingadmin.py 2012-10-09 19:03:21 +0000
17@@ -134,7 +134,7 @@
18 class MeetingAdmin(admin.ModelAdmin):
19 list_display = ('summit', 'name', 'title', 'slots', 'override_break', 'private', 'requires_dial_in', 'video', 'type', 'approved')
20 list_display_links = ('name', 'title')
21- list_filter = ('summit', 'type', 'tracks', 'slots', 'private',
22+ list_filter = ('summit', 'type', 'approved', 'tracks', 'slots', 'private',
23 'status', 'priority')
24 search_fields = ('name', 'title')
25
26
27=== modified file 'summit/schedule/models/meetingmodel.py'
28--- summit/schedule/models/meetingmodel.py 2012-10-02 02:23:02 +0000
29+++ summit/schedule/models/meetingmodel.py 2012-10-09 19:03:21 +0000
30@@ -296,7 +296,8 @@
31 def update_from_launchpad(self, elem):
32 """Update from Launchpad data."""
33
34- self.approved = 'APPROVED'
35+ if not self.approved == 'REMOVED':
36+ self.approved = 'APPROVED'
37
38 name = elem.get("name")
39 if name:
40
41=== modified file 'summit/schedule/templates/schedule/admin.html'
42--- summit/schedule/templates/schedule/admin.html 2012-06-10 20:34:50 +0000
43+++ summit/schedule/templates/schedule/admin.html 2012-10-09 19:03:21 +0000
44@@ -4,5 +4,8 @@
45 <li><strong>Created by:</strong> {{ meeting.drafter.name }}</li>
46 <li><strong>Approved by:</strong> {{ meeting.approver.name }}</li>
47 <li><strong>Scheduled:</strong> {% for ai in agenda_items %}{% if ai.auto %}Auto{% else %}Manual{% endif %}{% endfor %}</li>
48+ {% if is_scheduler %}
49+ <li><strong><a href="{% url summit.schedule.views.delete_meeting_confirm summit.name, meeting.id, meeting.name|default:'-' %}">Delete Meeting</a></strong></li>
50+ {% endif %}
51 </ul>
52 </div>
53
54=== added file 'summit/schedule/templates/schedule/confirm_deletion.html'
55--- summit/schedule/templates/schedule/confirm_deletion.html 1970-01-01 00:00:00 +0000
56+++ summit/schedule/templates/schedule/confirm_deletion.html 2012-10-09 19:03:21 +0000
57@@ -0,0 +1,16 @@
58+{% extends "base.html" %}
59+
60+{% block page_name %}Meeting Successfully Deleted - {{ summit.title }}{%endblock %}
61+{% block sub_nav %}{% endblock %}
62+
63+{% block extrahead %}{{ block.super }}
64+{% endblock %}
65+
66+{% block content %}
67+<div class="row">
68+ <article id="form" class="span-8">
69+ <h3>Meeting Deleted</h3>
70+ <p>You have successfully deleted the meeting</p>
71+ </article>
72+</div>
73+{% endblock %}
74
75=== added file 'summit/schedule/templates/schedule/delete_confirm.html'
76--- summit/schedule/templates/schedule/delete_confirm.html 1970-01-01 00:00:00 +0000
77+++ summit/schedule/templates/schedule/delete_confirm.html 2012-10-09 19:03:21 +0000
78@@ -0,0 +1,20 @@
79+{% extends "base.html" %}
80+
81+{% block page_name %}Delete {{ meeting.title }} - {{ summit.title }}{%endblock %}
82+{% block sub_nav %}{% endblock %}
83+
84+{% block extrahead %}{{ block.super }}
85+{% endblock %}
86+
87+{% block content %}
88+<div class="row">
89+ <article id="form" class="span-8">
90+ <h3>Delete {{ meeting.title }}</h3>
91+ <p>You are about to delete "{{ meeting.title }}". Are you absolutely sure that you wish to do this?</p>
92+ {% if meeting.spec_url %}
93+ <p>NOTE: This meeting was created by a <a href="{{ meeting.spec_url }}">blueprint</a>. The blueprint needs to be marked declined prior to deleting this meeting, or the meeting will reappear.</p>
94+ {% endif %}
95+ <p><a href="{% url summit.schedule.views.delete_meeting summit.name, meeting.id, meeting.name|default:'-' %}" class="submit-button">Delete Meeting</a></p>
96+ </article>
97+</div>
98+{% endblock %}
99
100=== modified file 'summit/schedule/tests.py'
101--- summit/schedule/tests.py 2012-10-02 02:23:02 +0000
102+++ summit/schedule/tests.py 2012-10-09 19:03:21 +0000
103@@ -24,7 +24,7 @@
104 from django.core.handlers.wsgi import WSGIRequest
105 from django.core.urlresolvers import reverse
106 from django.conf import settings
107-from django.contrib.auth.models import User
108+from django.contrib.auth.models import User, Permission
109 from django.contrib.contenttypes.models import ContentType
110 from django.db import models
111 from django.core.cache import cache
112@@ -42,7 +42,8 @@
113 Room,
114 Agenda,
115 Participant,
116- SummitSprint)
117+ SummitSprint,
118+ Lead)
119
120 from summit.schedule.render import Schedule
121 from summit.common import launchpad
122@@ -1894,3 +1895,75 @@
123
124 self.assertEqual(1, summit.attendee_set.filter(user__username__exact="testuser").count())
125 self.assertTrue(mock_set_openid.called)
126+
127+class DeleteMeetingTestCase(djangotest.TestCase):
128+ """
129+ This will test different options for deleting a meeting from
130+ the front end UI.
131+ """
132+
133+ def setUp(self):
134+ now = datetime.datetime.utcnow()
135+ one_hour = datetime.timedelta(0, 3600)
136+ self.summit = factory.make_one(Summit, name='uds-test', date_start=now, date_end=now+one_hour)
137+ self.summit.save()
138+ slot = factory.make_one(
139+ Slot,
140+ summit=self.summit,
141+ start_utc=now,
142+ end_utc=now+one_hour)
143+ room = factory.make_one(Room)
144+
145+ self.meeting = factory.make_one(Meeting, summit=self.summit, requires_dial_in=False, private=False)
146+
147+ attendee1 = factory.make_one(Attendee)
148+ factory.make_one(Participant, meeting=self.meeting, attendee=attendee1)
149+
150+ factory.make_one(Agenda, meeting=self.meeting, slot=slot, room=room)
151+
152+ self.user = factory.make_one(User, username='testuser', is_active=True, is_superuser=False)
153+ self.user.set_password('password')
154+ self.user.save()
155+
156+ self.attendee = factory.make_one(Attendee, user=self.user, summit=self.summit)
157+
158+ def tearDown(self):
159+ self.client.logout()
160+ self.user.user_permissions.all().delete()
161+
162+ def login(self):
163+ logged_in = self.client.login(username='testuser', password='password')
164+ self.assertTrue(logged_in)
165+
166+ def test_track_lead_cant_delete_meeting(self):
167+ self.lead = factory.make_one(Lead, lead=self.attendee, summit=self.summit)
168+ self.login()
169+ response = self.client.get(reverse('summit.schedule.views.delete_meeting', args=(self.summit, self.meeting.id, self.meeting.name)))
170+ self.assertRedirects(response, reverse('summit.schedule.views.summit', args=(self.summit.name,)), status_code=302, target_status_code=200)
171+
172+ def test_user_cant_delete_meeting(self):
173+ self.login()
174+ response = self.client.get(reverse('summit.schedule.views.delete_meeting', args=(self.summit, self.meeting.id, self.meeting.name)))
175+ self.assertRedirects(response, reverse('summit.schedule.views.summit', args=(self.summit.name,)), status_code=302, target_status_code=200)
176+
177+ def test_managers_cant_delete_meeting(self):
178+ self.summit.managers.add(self.user)
179+ self.login()
180+ response = self.client.get(reverse('summit.schedule.views.delete_meeting', args=(self.summit, self.meeting.id, self.meeting.name)))
181+ self.assertRedirects(response, reverse('summit.schedule.views.summit', args=(self.summit.name,)), status_code=302, target_status_code=200)
182+
183+ def test_schedulers_can_delete_meeting(self):
184+ self.summit.schedulers.add(self.user)
185+ self.login()
186+ response = self.client.get(reverse('summit.schedule.views.delete_meeting', args=(self.summit, self.meeting.id, self.meeting.name)))
187+ self.assertRedirects(response, reverse('summit.schedule.views.delete_confirmed', args=(self.summit.name,)), status_code=302, target_status_code=200)
188+
189+ def test_change_agenda_can_delete_meeting(self):
190+ """
191+ Testing if a user who is assigned can_change_agenda in django admin can delete a meeting
192+ """
193+ change_agenda = Permission.objects.get(codename='change_agenda')
194+ self.user.user_permissions.add(change_agenda)
195+ self.login()
196+ response = self.client.get(reverse('summit.schedule.views.delete_meeting', args=(self.summit, self.meeting.id, self.meeting.name)))
197+ self.assertRedirects(response, reverse('summit.schedule.views.delete_confirmed', args=(self.summit.name,)), status_code=302, target_status_code=200)
198
199=== modified file 'summit/schedule/views.py'
200--- summit/schedule/views.py 2012-09-14 14:57:02 +0000
201+++ summit/schedule/views.py 2012-10-09 19:03:21 +0000
202@@ -366,6 +366,7 @@
203 'ETHERPAD_HOST': summit.etherpad,
204 'summit_organizer': summit.is_organizer(attendee),
205 'scheduler': summit.can_change_agenda(attendee),
206+ 'is_scheduler': summit.is_scheduler(attendee),
207 'drafter': drafter,
208 }
209 return render_to_response("schedule/meeting.html", context,
210@@ -750,3 +751,41 @@
211 }
212 return render_to_response('schedule/org_attend.html',
213 context, RequestContext(request))
214+
215+
216+@summit_attendee_required
217+def delete_meeting_confirm(request, summit, attendee, meeting_id, meeting_slug):
218+ meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
219+
220+ if not attendee.user in summit.schedulers.all() and not attendee.user.has_perm('schedule.change_agenda'):
221+ return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
222+
223+ context = {
224+ 'summit': summit,
225+ 'meeting.title': meeting.title,
226+ 'meeting': meeting,
227+ }
228+ return render_to_response('schedule/delete_confirm.html',
229+ context, RequestContext(request))
230+
231+
232+@summit_attendee_required
233+def delete_meeting(request, summit, attendee, meeting_id, meeting_slug):
234+ meeting = get_object_or_404(summit.meeting_set, pk = meeting_id)
235+ if not attendee.user in summit.schedulers.all() and not attendee.user.has_perm('schedule.change_agenda'):
236+ return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
237+ else:
238+ meeting.approved = 'REMOVED'
239+ meeting.save()
240+ meeting.agenda_set.all().delete()
241+ return HttpResponseRedirect(reverse('summit.schedule.views.delete_confirmed', args=(summit.name,)))
242+
243+def delete_confirmed(request, summit_name):
244+ summit = get_object_or_404(Summit, name=summit_name)
245+
246+ context = {
247+ 'summit': summit
248+ }
249+
250+ return render_to_response('schedule/confirm_deletion.html',
251+ context, RequestContext(request))
252
253=== modified file 'summit/urls.py'
254--- summit/urls.py 2012-08-05 16:31:15 +0000
255+++ summit/urls.py 2012-10-09 19:03:21 +0000
256@@ -75,6 +75,9 @@
257 (r'^(?P<summit_name>[\w-]+)/edit_attendee/(?P<meeting_id>\d+)/(?P<username>[%+\.\w-]+)/$', 'organizer_edit_attendees'),
258 (r'^(?P<summit_name>[\w-]+)/create_meeting/$', 'create_meeting'),
259 (r'^(?P<summit_name>[\w-]+)/edit_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'organizer_edit_meeting'),
260+ (r'^(?P<summit_name>[\w-]+)/confirm_del_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'delete_meeting_confirm'),
261+ (r'^(?P<summit_name>[\w-]+)/del_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'delete_meeting'),
262+ (r'^(?P<summit_name>[\w-]+)/deleted/$', 'delete_confirmed'),
263 (r'^(?P<summit_name>[\w-]+)/attendee_review/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'attendee_review'),
264 (r'^(?P<summit_name>[\w-]+)/tracks$', 'tracks'),
265 (r'^(?P<summit_name>[\w-]+)/next$', 'next_session'),

Subscribers

People subscribed via source and target branches