Merge lp:~cjohnston/summit/cj-wrote-tests into lp:summit
- cj-wrote-tests
- Merge into trunk
Proposed by
Chris Johnston
Status: | Merged |
---|---|
Approved by: | Michael Hall |
Approved revision: | 496 |
Merged at revision: | 484 |
Proposed branch: | lp:~cjohnston/summit/cj-wrote-tests |
Merge into: | lp:summit |
Diff against target: |
1362 lines (+866/-111) 10 files modified
summit/schedule/models/meetingmodel.py (+175/-64) summit/schedule/models/participantmodel.py (+26/-14) summit/schedule/models/roommodel.py (+7/-2) summit/schedule/models/summitmodel.py (+1/-1) summit/schedule/models/trackmodel.py (+6/-1) summit/schedule/templates/schedule/virtual_meeting.html (+2/-0) summit/schedule/tests/__init__.py (+1/-0) summit/schedule/tests/test_virtual.py (+572/-0) summit/schedule/tests/tests.py (+8/-2) summit/schedule/views.py (+68/-27) |
To merge this branch: | bzr merge lp:~cjohnston/summit/cj-wrote-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Hall (community) | Approve | ||
Review via email: mp+150191@code.launchpad.net |
Commit message
Adds 22 tests for the new virtual meeting functionality.
Description of the change
To post a comment you must log in.
- 488. By Chris Johnston
-
More test stuff
- 489. By Chris Johnston
-
Reducing code
- 490. By Chris Johnston
-
more tests
- 491. By Chris Johnston
-
More tests
- 492. By Chris Johnston
-
more
- 493. By Chris Johnston
-
fixes from Michael
- 494. By Chris Johnston
-
save form
- 495. By Chris Johnston
-
Let us test forms
- 496. By Chris Johnston
-
Testing tests
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'summit/schedule/models/meetingmodel.py' |
2 | --- summit/schedule/models/meetingmodel.py 2013-02-20 13:57:06 +0000 |
3 | +++ summit/schedule/models/meetingmodel.py 2013-02-26 19:00:29 +0000 |
4 | @@ -1,5 +1,5 @@ |
5 | # The Summit Scheduler web application |
6 | -# Copyright (C) 2008 - 2012 Ubuntu Community, Canonical Ltd |
7 | +# Copyright (C) 2008 - 2013 Ubuntu Community, Canonical Ltd |
8 | # |
9 | # This program is free software: you can redistribute it and/or modify |
10 | # it under the terms of the GNU Affero General Public License as |
11 | @@ -21,7 +21,6 @@ |
12 | |
13 | from django.db import models |
14 | from django.core.exceptions import ObjectDoesNotExist |
15 | -from django.conf import settings |
16 | from django.core.urlresolvers import reverse |
17 | |
18 | import simplejson as json |
19 | @@ -91,15 +90,31 @@ |
20 | ) |
21 | |
22 | summit = models.ForeignKey(Summit) |
23 | - name = NameField(max_length=100, help_text="Lowercase alphanumeric characters and dashes only.") |
24 | - title = models.CharField(max_length=100, help_text="Alphanumeric characters and spaces are allowed") |
25 | + name = NameField( |
26 | + max_length=100, |
27 | + help_text="Lowercase alphanumeric characters and dashes only." |
28 | + ) |
29 | + title = models.CharField( |
30 | + max_length=100, |
31 | + help_text="Alphanumeric characters and spaces are allowed" |
32 | + ) |
33 | description = models.TextField(max_length=2047, blank=True) |
34 | - type = models.CharField(max_length=15, choices=TYPE_CHOICES, |
35 | - default=TYPE_CHOICES[0][0]) |
36 | - status = models.CharField(max_length=10, choices=STATUS_CHOICES, |
37 | - null=True, blank=True) |
38 | - priority = models.IntegerField(choices=PRIORITY_CHOICES, |
39 | - null=True, blank=True) |
40 | + type = models.CharField( |
41 | + max_length=15, |
42 | + choices=TYPE_CHOICES, |
43 | + default=TYPE_CHOICES[0][0] |
44 | + ) |
45 | + status = models.CharField( |
46 | + max_length=10, |
47 | + choices=STATUS_CHOICES, |
48 | + null=True, |
49 | + blank=True |
50 | + ) |
51 | + priority = models.IntegerField( |
52 | + choices=PRIORITY_CHOICES, |
53 | + null=True, |
54 | + blank=True |
55 | + ) |
56 | hangout_url = models.URLField( |
57 | blank=True, |
58 | null=True, |
59 | @@ -113,20 +128,37 @@ |
60 | # FIXME tracks must be for the same summit |
61 | # (will require js magic in admin to refresh the boxes) |
62 | tracks = models.ManyToManyField(Track, blank=True) |
63 | - spec_url = models.URLField(blank=True, |
64 | - verbose_name="Spec URL") |
65 | - wiki_url = models.URLField(blank=True, verify_exists=False, |
66 | - verbose_name="Wiki URL") |
67 | - pad_url = models.URLField(verify_exists=False, |
68 | - verbose_name="Pad URL", null=True, blank=True) |
69 | + spec_url = models.URLField( |
70 | + blank=True, |
71 | + verbose_name="Spec URL" |
72 | + ) |
73 | + wiki_url = models.URLField( |
74 | + blank=True, |
75 | + verify_exists=False, |
76 | + verbose_name="Wiki URL" |
77 | + ) |
78 | + pad_url = models.URLField( |
79 | + verify_exists=False, |
80 | + verbose_name="Pad URL", |
81 | + null=True, |
82 | + blank=True |
83 | + ) |
84 | slots = models.IntegerField(default=1) |
85 | - override_break = models.BooleanField(default=False, verbose_name="Override Break", |
86 | - help_text="If this is a multi-slot meeting, should it be allowed to take place during a break") |
87 | + override_break = models.BooleanField( |
88 | + default=False, |
89 | + verbose_name="Override Break", |
90 | + help_text="If this is a multi-slot meeting, should it be" |
91 | + "allowed to take place during a break" |
92 | + ) |
93 | virtual_meeting = models.BooleanField( |
94 | help_text="If virtual summit is true, this will not override it" |
95 | ) |
96 | - approved = models.CharField(max_length=10, choices=REVIEW_CHOICES, |
97 | - null=True, default='PENDING') |
98 | + approved = models.CharField( |
99 | + max_length=10, |
100 | + choices=REVIEW_CHOICES, |
101 | + null=True, |
102 | + default='PENDING' |
103 | + ) |
104 | private = models.BooleanField(default=False) |
105 | private_key = models.CharField(max_length=32, null=True, blank=True) |
106 | |
107 | @@ -142,16 +174,35 @@ |
108 | |
109 | # FIXME attendees must be for the same summit |
110 | # (will require js magic in admin to refresh the boxes) |
111 | - drafter = models.ForeignKey(Attendee, null=True, blank=True, |
112 | - related_name='drafter_set') |
113 | - assignee = models.ForeignKey(Attendee, null=True, blank=True, |
114 | - related_name='assignee_set') |
115 | - approver = models.ForeignKey(Attendee, null=True, blank=True, |
116 | - related_name='approver_set') |
117 | - scribe = models.ForeignKey(Attendee, null=True, blank=True, |
118 | - related_name='scribe_set') |
119 | - participants = models.ManyToManyField(Attendee, blank=True, |
120 | - through='Participant') |
121 | + drafter = models.ForeignKey( |
122 | + Attendee, |
123 | + null=True, |
124 | + blank=True, |
125 | + related_name='drafter_set' |
126 | + ) |
127 | + assignee = models.ForeignKey( |
128 | + Attendee, |
129 | + null=True, |
130 | + blank=True, |
131 | + related_name='assignee_set' |
132 | + ) |
133 | + approver = models.ForeignKey( |
134 | + Attendee, |
135 | + null=True, |
136 | + blank=True, |
137 | + related_name='approver_set' |
138 | + ) |
139 | + scribe = models.ForeignKey( |
140 | + Attendee, |
141 | + null=True, |
142 | + blank=True, |
143 | + related_name='scribe_set' |
144 | + ) |
145 | + participants = models.ManyToManyField( |
146 | + Attendee, |
147 | + blank=True, |
148 | + through='Participant' |
149 | + ) |
150 | launchpad_blueprint_id = models.IntegerField(blank=True, null=True) |
151 | |
152 | class Meta: |
153 | @@ -169,7 +220,8 @@ |
154 | return |
155 | |
156 | if not self.private_key: |
157 | - import hashlib, random |
158 | + import hashlib |
159 | + import random |
160 | meeting_hash = hashlib.md5() |
161 | meeting_hash.update(str(self.pk)) |
162 | meeting_hash.update(self.name) |
163 | @@ -185,7 +237,8 @@ |
164 | if self.pad_url is not None and self.pad_url != '': |
165 | return self.pad_url |
166 | elif self.private: |
167 | - import hashlib, random |
168 | + import hashlib |
169 | + import random |
170 | meeting_hash = hashlib.md5() |
171 | meeting_hash.update(str(self.pk)) |
172 | meeting_hash.update(self.name) |
173 | @@ -362,7 +415,10 @@ |
174 | # fetch to update the title |
175 | # Now, LP has an API, we're stopping the sceen scrape :) |
176 | try: |
177 | - apiurl = spec_url.replace('blueprints.launchpad.net', 'api.launchpad.net/devel') + '?ws.accept=application/json' |
178 | + apiurl = spec_url.replace( |
179 | + 'blueprints.launchpad.net', |
180 | + 'api.launchpad.net/devel' |
181 | + ) + '?ws.accept=application/json' |
182 | lpdata = urllib2.urlopen(apiurl) |
183 | data = json.load(lpdata) |
184 | if 'title' in data: |
185 | @@ -397,7 +453,8 @@ |
186 | if assignee: |
187 | try: |
188 | self.assignee = self.summit.attendee_set.get( |
189 | - user__username__exact=assignee) |
190 | + user__username__exact=assignee |
191 | + ) |
192 | except ObjectDoesNotExist: |
193 | pass |
194 | |
195 | @@ -406,7 +463,8 @@ |
196 | if approver: |
197 | try: |
198 | self.approver = self.summit.attendee_set.get( |
199 | - user__username__exact=approver) |
200 | + user__username__exact=approver |
201 | + ) |
202 | except ObjectDoesNotExist: |
203 | pass |
204 | |
205 | @@ -422,18 +480,21 @@ |
206 | |
207 | try: |
208 | attendee = self.summit.attendee_set.get( |
209 | - user__username__exact=username) |
210 | + user__username__exact=username |
211 | + ) |
212 | |
213 | try: |
214 | participant = self.participant_set.get( |
215 | - attendee=attendee) |
216 | + attendee=attendee |
217 | + ) |
218 | except ObjectDoesNotExist: |
219 | participant = self.participant_set.create( |
220 | - attendee=attendee) |
221 | + attendee=attendee |
222 | + ) |
223 | except: |
224 | participant = self.participant_set.filter( |
225 | - attendee=attendee)[0] |
226 | - |
227 | + attendee=attendee |
228 | + )[0] |
229 | |
230 | participant.from_launchpad = True |
231 | if required: |
232 | @@ -444,11 +505,15 @@ |
233 | except ObjectDoesNotExist: |
234 | pass |
235 | |
236 | - self.participant_set.filter(from_launchpad=True).filter(~models.Q(attendee__user__username__in=from_lp)).delete() |
237 | + self.participant_set.filter( |
238 | + from_launchpad=True |
239 | + ).filter( |
240 | + ~models.Q(attendee__user__username__in=from_lp) |
241 | + ).delete() |
242 | |
243 | self.save() |
244 | |
245 | - def check_schedule(self, slot, room, with_interested = False): |
246 | + def check_schedule(self, slot, room, with_interested=False): |
247 | """Check whether we can schedule this meeting in the given slot |
248 | and room.""" |
249 | missing = set() |
250 | @@ -456,7 +521,8 @@ |
251 | slots = [slot] |
252 | if self.slots > 1: |
253 | slots.extend(s for s |
254 | - in self.summit.slot_set.filter(start_utc__gte=slot.end_utc).order_by('start_utc') |
255 | + in self.summit.slot_set.filter( |
256 | + start_utc__gte=slot.end_utc).order_by('start_utc') |
257 | if s.start.date() == slot.start.date()) |
258 | if len(slots) < self.slots: |
259 | raise Meeting.SchedulingError("Insufficient slots available") |
260 | @@ -470,16 +536,23 @@ |
261 | continue |
262 | if this_slot.type not in ('open', 'plenary'): |
263 | raise Meeting.SchedulingError("Slot not available") |
264 | - if this_slot.type == 'plenary' and self.type not in ('plenary', 'talk', 'special'): |
265 | + if this_slot.type == 'plenary' and self.type not in ( |
266 | + 'plenary', |
267 | + 'talk', |
268 | + 'special' |
269 | + ): |
270 | raise Meeting.SchedulingError( |
271 | - "Not a plenary event, talk or special event") |
272 | + "Not a plenary event, talk or special event" |
273 | + ) |
274 | |
275 | # Check that the room is not already in use |
276 | try: |
277 | existing = room.agenda_set.get(slot=this_slot) |
278 | if existing.meeting != self: |
279 | - raise Meeting.SchedulingError("Room is in use by %s" |
280 | - % existing.meeting) |
281 | + raise Meeting.SchedulingError( |
282 | + "Room is in use by %s" |
283 | + % existing.meeting |
284 | + ) |
285 | except ObjectDoesNotExist: |
286 | pass |
287 | |
288 | @@ -496,8 +569,10 @@ |
289 | for agenda in prev_slot.agenda_set.filter(room=room): |
290 | if agenda.meeting != self \ |
291 | and agenda.meeting.slots >= (distance - breaks): |
292 | - raise Meeting.SchedulingError("Room is in use by %s" |
293 | - % agenda.meeting) |
294 | + raise Meeting.SchedulingError( |
295 | + "Room is in use by %s" |
296 | + % agenda.meeting |
297 | + ) |
298 | |
299 | # Check that the room is available |
300 | if not room.available(this_slot): |
301 | @@ -505,15 +580,21 @@ |
302 | |
303 | if self.requires_dial_in: |
304 | if not room.has_dial_in: |
305 | - raise Meeting.SchedulingError("Room has no dial-in capability") |
306 | + raise Meeting.SchedulingError( |
307 | + "Room has no dial-in capability" |
308 | + ) |
309 | |
310 | # Work out who is busy in this slot |
311 | busy = set() |
312 | for agenda in this_slot.agenda_set.all(): |
313 | if agenda.meeting != self: |
314 | - busy.update([a.pk for a in agenda.meeting.required_attendees]) |
315 | + busy.update( |
316 | + [a.pk for a in agenda.meeting.required_attendees] |
317 | + ) |
318 | if with_interested: |
319 | - busy.update([a.pk for a in agenda.meeting.get_participants_by_level('INTERESTED')]) |
320 | + busy.update( |
321 | + [a.pk for a in agenda.meeting.get_participants_by_level('INTERESTED')] |
322 | + ) |
323 | slot_num = all_slots.index(this_slot) |
324 | for i in range(slot_num, 0, -1): |
325 | distance = 2 + slot_num - i |
326 | @@ -524,9 +605,13 @@ |
327 | for agenda in prev_slot.agenda_set.all(): |
328 | if agenda.meeting != self \ |
329 | and agenda.meeting.slots >= distance: |
330 | - busy.update([a.pk for a in agenda.meeting.required_attendees]) |
331 | + busy.update( |
332 | + [a.pk for a in agenda.meeting.required_attendees] |
333 | + ) |
334 | if with_interested: |
335 | - busy.update([a.pk for a in agenda.meeting.get_participants_by_level('INTERESTED')]) |
336 | + busy.update( |
337 | + [a.pk for a in agenda.meeting.get_participants_by_level('INTERESTED')] |
338 | + ) |
339 | # Check that all required attendees are free in this slot |
340 | for attendee in self.required_attendees: |
341 | if not attendee.available(this_slot): |
342 | @@ -544,12 +629,21 @@ |
343 | def check_not_same_track(other_slot, relative_position): |
344 | type_exceptions = ('presentation', 'plenary', 'talk') |
345 | if other_slot is not None and self.type not in type_exceptions: |
346 | - for agenda in other_slot.agenda_set.filter(room__exact=room).exclude( |
347 | - meeting__exact=self).filter(meeting__tracks__in=self.tracks.all()): |
348 | + for agenda in other_slot.agenda_set.filter( |
349 | + room__exact=room |
350 | + ).exclude( |
351 | + meeting__exact=self |
352 | + ).filter( |
353 | + meeting__tracks__in=self.tracks.all() |
354 | + ): |
355 | if agenda.meeting.tracks.filter( |
356 | - pk__in=self.tracks.all()).exclude(allow_adjacent_sessions=True).count() > 0: |
357 | + pk__in=self.tracks.all() |
358 | + ).exclude( |
359 | + allow_adjacent_sessions=True |
360 | + ).count() > 0: |
361 | raise Meeting.SchedulingError( |
362 | - "Same track in the %s slot" % relative_position) |
363 | + "Same track in the %s slot" % relative_position |
364 | + ) |
365 | |
366 | check_not_same_track(this_slot.previous(), "previous") |
367 | check_not_same_track(this_slot.next(), "next") |
368 | @@ -583,21 +677,38 @@ |
369 | """Try to schedule this meeting in one of the given rooms.""" |
370 | today = datetime.now() |
371 | for room in rooms: |
372 | - for slot in self.summit.slot_set.filter(type__exact='open',start_utc__gt=today): |
373 | + for slot in self.summit.slot_set.filter( |
374 | + type__exact='open', |
375 | + start_utc__gt=today |
376 | + ): |
377 | try: |
378 | room.agenda_set.get(slot=slot) |
379 | except room.agenda_set.model.DoesNotExist: |
380 | try: |
381 | - missing = self.check_schedule(slot, room, with_interested) |
382 | + missing = self.check_schedule( |
383 | + slot, |
384 | + room, |
385 | + with_interested |
386 | + ) |
387 | if len(missing): |
388 | - raise Meeting.SchedulingError("Required people not available: %s" |
389 | - % ', '.join(m.user.username for m in missing)) |
390 | + raise Meeting.SchedulingError( |
391 | + "Required people not available: %s" |
392 | + % ', '.join(m.user.username for m in missing) |
393 | + ) |
394 | |
395 | print "Schedule %s in %s at %s" % (self, room, slot) |
396 | room.agenda_set.create( |
397 | - slot=slot, meeting=self, auto=True) |
398 | + slot=slot, |
399 | + meeting=self, |
400 | + auto=True |
401 | + ) |
402 | return True |
403 | except Meeting.SchedulingError, e: |
404 | - print "-- could not schedule %s in %s at %s (%s)" % (self, room, slot, e) |
405 | + print "-- could not schedule %s in %s at %s (%s)" % ( |
406 | + self, |
407 | + room, |
408 | + slot, |
409 | + e |
410 | + ) |
411 | |
412 | return False |
413 | |
414 | === modified file 'summit/schedule/models/participantmodel.py' |
415 | --- summit/schedule/models/participantmodel.py 2012-07-12 18:36:38 +0000 |
416 | +++ summit/schedule/models/participantmodel.py 2013-02-26 19:00:29 +0000 |
417 | @@ -1,5 +1,5 @@ |
418 | # The Summit Scheduler web application |
419 | -# Copyright (C) 2008 - 2012 Ubuntu Community, Canonical Ltd |
420 | +# Copyright (C) 2008 - 2013 Ubuntu Community, Canonical Ltd |
421 | # |
422 | # This program is free software: you can redistribute it and/or modify |
423 | # it under the terms of the GNU Affero General Public License as |
424 | @@ -25,24 +25,30 @@ |
425 | |
426 | |
427 | HELP_TEXT = { |
428 | - "attendee": ("Be sure to choose the attendee from the correct " |
429 | + "attendee": ( |
430 | + "Be sure to choose the attendee from the correct " |
431 | "event. If the person is not listed for the event in question " |
432 | "then they are not known to be attending yet, and have to " |
433 | - "sign up to attend."), |
434 | - "required": ("The person is required to attend the session. " |
435 | + "sign up to attend." |
436 | + ), |
437 | + "required": ( |
438 | + "The person is required to attend the session. " |
439 | "If this is set the scheduler will attempt to ensure that " |
440 | "the person is able to attend. If it is not checked then " |
441 | "the scheduler won't consider the person when deciding " |
442 | - "where the meeting can go on the schedule."), |
443 | - "from_launchpad": ("Set to indicate the participant comes from " |
444 | + "where the meeting can go on the schedule." |
445 | + ), |
446 | + "from_launchpad": ( |
447 | + "Set to indicate the participant comes from " |
448 | "a subscription to the Launchpad blueprint. Don't set this " |
449 | "if you are adding the participant, as they may end up " |
450 | - "getting deleted if you do."), |
451 | + "getting deleted if you do." |
452 | + ), |
453 | } |
454 | |
455 | |
456 | class Participant(models.Model): |
457 | - |
458 | + |
459 | PARTICIPATION_CHOICES = ( |
460 | (u'ATTENDING', u'Attending'), |
461 | (u'INTERESTED', u'Very interested in attending'), |
462 | @@ -50,12 +56,18 @@ |
463 | ) |
464 | |
465 | meeting = models.ForeignKey(Meeting) |
466 | - attendee = models.ForeignKey(Attendee, |
467 | - help_text=HELP_TEXT["attendee"]) |
468 | - participation = models.CharField(max_length=32, choices=PARTICIPATION_CHOICES, |
469 | - null=True, blank=False, default='ATTENDING') |
470 | - from_launchpad = models.BooleanField(default=False, |
471 | - help_text=HELP_TEXT["from_launchpad"]) |
472 | + attendee = models.ForeignKey(Attendee, help_text=HELP_TEXT["attendee"]) |
473 | + participation = models.CharField( |
474 | + max_length=32, |
475 | + choices=PARTICIPATION_CHOICES, |
476 | + null=True, |
477 | + blank=False, |
478 | + default='ATTENDING' |
479 | + ) |
480 | + from_launchpad = models.BooleanField( |
481 | + default=False, |
482 | + help_text=HELP_TEXT["from_launchpad"] |
483 | + ) |
484 | |
485 | class Meta: |
486 | app_label = 'schedule' |
487 | |
488 | === modified file 'summit/schedule/models/roommodel.py' |
489 | --- summit/schedule/models/roommodel.py 2012-02-06 18:25:01 +0000 |
490 | +++ summit/schedule/models/roommodel.py 2013-02-26 19:00:29 +0000 |
491 | @@ -51,8 +51,13 @@ |
492 | verbose_name="End (UTC)") |
493 | icecast_url = models.URLField(blank=True, verify_exists=False, |
494 | verbose_name="Icecast URL") |
495 | - irc_channel = models.CharField(max_length=50, verbose_name="IRC Channel", blank=True, help_text="Please enter the IRC channel without the #") |
496 | - |
497 | + irc_channel = models.CharField( |
498 | + max_length=50, |
499 | + verbose_name="IRC Channel", |
500 | + blank=True, |
501 | + help_text="Please enter the IRC channel without the #" |
502 | + ) |
503 | + |
504 | # Whether the room has dial-in capability |
505 | has_dial_in = models.BooleanField(default=False) |
506 | |
507 | |
508 | === modified file 'summit/schedule/models/summitmodel.py' |
509 | --- summit/schedule/models/summitmodel.py 2013-02-21 23:10:17 +0000 |
510 | +++ summit/schedule/models/summitmodel.py 2013-02-26 19:00:29 +0000 |
511 | @@ -1,5 +1,5 @@ |
512 | # The Summit Scheduler web application |
513 | -# Copyright (C) 2008 - 2012 Ubuntu Community, Canonical Ltd |
514 | +# Copyright (C) 2008 - 2013 Ubuntu Community, Canonical Ltd |
515 | # |
516 | # This program is free software: you can redistribute it and/or modify |
517 | # it under the terms of the GNU Affero General Public License as |
518 | |
519 | === modified file 'summit/schedule/models/trackmodel.py' |
520 | --- summit/schedule/models/trackmodel.py 2012-12-06 22:24:06 +0000 |
521 | +++ summit/schedule/models/trackmodel.py 2013-02-26 19:00:29 +0000 |
522 | @@ -28,7 +28,12 @@ |
523 | summit = models.ForeignKey(Summit) |
524 | title = models.CharField(max_length=100) |
525 | slug = models.CharField(max_length=100, null=True, blank=False) |
526 | - color = models.CharField(max_length=6, null=False, blank=False, default='FFFFFF') |
527 | + color = models.CharField( |
528 | + max_length=6, |
529 | + null=False, |
530 | + blank=False, |
531 | + default='FFFFFF' |
532 | + ) |
533 | description = models.TextField(max_length=1000, blank=False, null=True) |
534 | allow_adjacent_sessions = models.BooleanField(default=False) |
535 | |
536 | |
537 | === modified file 'summit/schedule/templates/schedule/virtual_meeting.html' |
538 | --- summit/schedule/templates/schedule/virtual_meeting.html 2013-02-21 23:10:17 +0000 |
539 | +++ summit/schedule/templates/schedule/virtual_meeting.html 2013-02-26 19:00:29 +0000 |
540 | @@ -72,7 +72,9 @@ |
541 | <h2>{{ meeting.title }}</h2> |
542 | <div id="description"> |
543 | {{ meeting.description|markdown:'safe' }} |
544 | + {% if required %} |
545 | <h3><a href="{{ meeting.hangout_url }}">Join the Hangout on Air</a></h3> |
546 | + {% endif %} |
547 | </div> |
548 | |
549 | </section> |
550 | |
551 | === modified file 'summit/schedule/tests/__init__.py' |
552 | --- summit/schedule/tests/__init__.py 2013-02-22 01:22:19 +0000 |
553 | +++ summit/schedule/tests/__init__.py 2013-02-26 19:00:29 +0000 |
554 | @@ -15,3 +15,4 @@ |
555 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
556 | |
557 | from tests import * |
558 | +from test_virtual import * |
559 | |
560 | === added file 'summit/schedule/tests/test_virtual.py' |
561 | --- summit/schedule/tests/test_virtual.py 1970-01-01 00:00:00 +0000 |
562 | +++ summit/schedule/tests/test_virtual.py 2013-02-26 19:00:29 +0000 |
563 | @@ -0,0 +1,572 @@ |
564 | +# The Summit Scheduler web application |
565 | +# Copyright (C) 2008 - 2013 Ubuntu Community, Canonical Ltd |
566 | +# |
567 | +# This program is free software: you can redistribute it and/or modify |
568 | +# it under the terms of the GNU Affero General Public License as |
569 | +# published by the Free Software Foundation, either version 3 of the |
570 | +# License, or (at your option) any later version. |
571 | +# |
572 | +# This program is distributed in the hope that it will be useful, |
573 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
574 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
575 | +# GNU Affero General Public License for more details. |
576 | +# |
577 | +# You should have received a copy of the GNU Affero General Public License |
578 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
579 | + |
580 | +import datetime |
581 | + |
582 | +from django import test as djangotest |
583 | +from django.core.urlresolvers import reverse |
584 | +from django.contrib.auth.models import User |
585 | +from django.test.client import Client |
586 | + |
587 | +from model_mommy import mommy as factory |
588 | + |
589 | +from summit.schedule.models import ( |
590 | + Summit, |
591 | + Slot, |
592 | + Attendee, |
593 | + Meeting, |
594 | + Track, |
595 | + Room, |
596 | + Lead, |
597 | + Participant, |
598 | + Agenda, |
599 | +) |
600 | + |
601 | + |
602 | +class VirtualSummitTestCase(djangotest.TestCase): |
603 | + """ |
604 | + Tests for the virtual meeting display |
605 | + """ |
606 | + |
607 | + c = Client() |
608 | + |
609 | + def setUp(self): |
610 | + now = datetime.datetime.utcnow() |
611 | + one_hour = datetime.timedelta(0, 3600) |
612 | + week = datetime.timedelta(days=5) |
613 | + self.summit = factory.make_one( |
614 | + Summit, |
615 | + name='uds-virt', |
616 | + virtual_summit=True, |
617 | + date_start=now, |
618 | + date_end=now + week, |
619 | + ) |
620 | + |
621 | + self.slot = factory.make_one( |
622 | + Slot, |
623 | + start_utc=now+one_hour, |
624 | + end_utc=now+(2*one_hour), |
625 | + type='open', |
626 | + summit=self.summit |
627 | + ) |
628 | + self.track = factory.make_one(Track, summit=self.summit) |
629 | + self.room = factory.make_one( |
630 | + Room, |
631 | + summit=self.summit, |
632 | + type='open', |
633 | + irc_channel='test-channel', |
634 | + ) |
635 | + |
636 | + self.meeting1 = factory.make_one( |
637 | + Meeting, |
638 | + summit=self.summit, |
639 | + name='meeting-non-virt', |
640 | + private=False, |
641 | + requires_dial_in=False, |
642 | + spec_url='', |
643 | + pad_url='http://pad.com/1' |
644 | + ) |
645 | + self.meeting1.tracks = [self.track] |
646 | + |
647 | + self.user1 = factory.make_one( |
648 | + User, |
649 | + username='testuser', |
650 | + first_name='Test', |
651 | + last_name='User', |
652 | + is_active=True, |
653 | + is_superuser=False, |
654 | + ) |
655 | + self.user1.set_password('password') |
656 | + self.user1.save() |
657 | + self.attendee1 = factory.make_one( |
658 | + Attendee, |
659 | + summit=self.summit, |
660 | + user=self.user1, |
661 | + start_utc=now, |
662 | + end_utc=now+week |
663 | + ) |
664 | + |
665 | + self.agenda1 = factory.make_one( |
666 | + Agenda, |
667 | + slot=self.slot, |
668 | + meeting=self.meeting1, |
669 | + room=self.room |
670 | + ) |
671 | + |
672 | + def tearDown(self): |
673 | + self.client.logout() |
674 | + |
675 | + def login(self): |
676 | + logged_in = self.c.login( |
677 | + username='testuser', |
678 | + password='password') |
679 | + self.assertTrue(logged_in) |
680 | + |
681 | + def view_and_save_edit_meeting_hangout_form(self): |
682 | + """ |
683 | + Tests that a user with proper permissions can save the |
684 | + edit_meeting_hangout form |
685 | + """ |
686 | + # View the edit meeting hangout form |
687 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
688 | + response = self.c.get( |
689 | + reverse( |
690 | + 'summit.schedule.views.edit_meeting_hangout', |
691 | + args=rev_args |
692 | + ) |
693 | + ) |
694 | + self.assertEqual(response.status_code, 200) |
695 | + self.assertTemplateUsed(response, 'schedule/edit_hangout.html') |
696 | + |
697 | + # Define data to fill our the form |
698 | + hangout_url = 'http://hangouturl.com' |
699 | + broadcast_url = 'http://broadcasturl.com' |
700 | + |
701 | + # Post the form |
702 | + post = self.c.post( |
703 | + reverse( |
704 | + 'summit.schedule.views.edit_meeting_hangout', |
705 | + args=rev_args |
706 | + ), |
707 | + data={ |
708 | + 'broadcast_url': broadcast_url, |
709 | + 'hangout_url': hangout_url, |
710 | + } |
711 | + ) |
712 | + |
713 | + # A successful post should redirect to the meeting page |
714 | + response = self.view_virtual_meeting_page() |
715 | + redirect_url = reverse( |
716 | + 'summit.schedule.views.meeting', |
717 | + args=rev_args |
718 | + ) |
719 | + self.assertEqual(post.status_code, 302) |
720 | + self.assertRedirects( |
721 | + post, |
722 | + redirect_url, |
723 | + ) |
724 | + redirect_responseonse = self.c.get(redirect_url) |
725 | + |
726 | + # Verify that the new data appears on the meeting page |
727 | + self.assertEqual(redirect_responseonse.status_code, 200) |
728 | + self.assertIn(broadcast_url, redirect_responseonse.content) |
729 | + self.assertIn(hangout_url, redirect_responseonse.content) |
730 | + self.assertIn('Join the Hangout on Air', redirect_responseonse.content) |
731 | + |
732 | + def view_virtual_meeting_page(self): |
733 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
734 | + response = self.c.get( |
735 | + reverse( |
736 | + 'summit.schedule.views.meeting', |
737 | + args=rev_args |
738 | + ) |
739 | + ) |
740 | + self.assertEqual(response.status_code, 200) |
741 | + self.assertTemplateUsed(response, 'schedule/virtual_meeting.html') |
742 | + self.assertTemplateNotUsed(response, 'schedule/meeting.html') |
743 | + |
744 | + return response |
745 | + |
746 | + def test_virtual_mtg_true_display_virtual_page(self): |
747 | + """ |
748 | + Tests that a meeting with virtual_summit=True and virtual_meeting=True |
749 | + displays the virtual meeting page. |
750 | + """ |
751 | + |
752 | + self.meeting1.virtual_meeting = True |
753 | + self.meeting1.save() |
754 | + |
755 | + response = self.view_virtual_meeting_page() |
756 | + |
757 | + def test_virtual_mtg_false_display_virtual_page(self): |
758 | + """ |
759 | + Tests that a meeting with virtual_summit=True and virtual_meeting=False |
760 | + displays the virtual meeting page. |
761 | + """ |
762 | + |
763 | + self.meeting1.virtual_meeting = False |
764 | + self.meeting1.save() |
765 | + response = self.view_virtual_meeting_page() |
766 | + |
767 | + def test_lead_has_edit_meeting_hangout_link(self): |
768 | + """ |
769 | + Tests that the track lead for the meeting has the link to add the |
770 | + hangout URLs |
771 | + """ |
772 | + |
773 | + self.lead = factory.make_one( |
774 | + Lead, |
775 | + summit=self.summit, |
776 | + track=self.track, |
777 | + lead=self.attendee1, |
778 | + ) |
779 | + |
780 | + self.login() |
781 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
782 | + response = self.view_virtual_meeting_page() |
783 | + self.assertIn( |
784 | + reverse( |
785 | + 'summit.schedule.views.edit_meeting_hangout', |
786 | + args=rev_args |
787 | + ), |
788 | + response.content |
789 | + ) |
790 | + self.assertIn('Edit Hangout Details', response.content) |
791 | + |
792 | + def test_drafter_has_edit_meeting_hangout_link(self): |
793 | + """ |
794 | + Tests that the meeting drafter has the link to add hangout URLs |
795 | + """ |
796 | + |
797 | + self.meeting1.drafter = self.attendee1 |
798 | + self.meeting1.save() |
799 | + |
800 | + self.login() |
801 | + |
802 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
803 | + response = self.view_virtual_meeting_page() |
804 | + self.assertContains( |
805 | + response, |
806 | + reverse( |
807 | + 'summit.schedule.views.edit_meeting_hangout', |
808 | + args=rev_args |
809 | + ), |
810 | + 1 |
811 | + ) |
812 | + self.assertContains(response, 'Edit Hangout Details', 1) |
813 | + |
814 | + def test_manager_has_edit_meeting_hangout_link(self): |
815 | + """ |
816 | + Tests that a Summit Manager has the link to add hangout URLs |
817 | + """ |
818 | + |
819 | + self.summit.managers.add(self.user1) |
820 | + |
821 | + self.login() |
822 | + |
823 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
824 | + response = self.view_virtual_meeting_page() |
825 | + self.assertIn( |
826 | + reverse( |
827 | + 'summit.schedule.views.edit_meeting_hangout', |
828 | + args=rev_args |
829 | + ), |
830 | + response.content |
831 | + ) |
832 | + self.assertIn('Edit Hangout Details', response.content) |
833 | + |
834 | + def test_scheduler_has_edit_meeting_hangout_link(self): |
835 | + """ |
836 | + Tests that a Summit Scheduler has the link to add hangout URLs |
837 | + """ |
838 | + |
839 | + self.summit.schedulers.add(self.user1) |
840 | + |
841 | + self.login() |
842 | + |
843 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
844 | + response = self.view_virtual_meeting_page() |
845 | + self.assertIn( |
846 | + reverse( |
847 | + 'summit.schedule.views.edit_meeting_hangout', |
848 | + args=rev_args |
849 | + ), |
850 | + response.content |
851 | + ) |
852 | + self.assertIn('Edit Hangout Details', response.content) |
853 | + |
854 | + def test_regular_user_does_not__have_edit_meeting_hangout_link(self): |
855 | + """ |
856 | + Tests that a regular Summit user is not able to see the edit the |
857 | + hangout link |
858 | + """ |
859 | + |
860 | + self.login() |
861 | + |
862 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
863 | + response = self.view_virtual_meeting_page() |
864 | + self.assertContains( |
865 | + response, |
866 | + reverse( |
867 | + 'summit.schedule.views.edit_meeting_hangout', |
868 | + args=rev_args |
869 | + ), |
870 | + 0 |
871 | + ) |
872 | + self.assertContains(response, 'Edit Hangout Details', 0) |
873 | + |
874 | + def test_non_logged_in_user_does_not_have_edit_meeting_hangout_link(self): |
875 | + """ |
876 | + Tests that a non-logged in user is not able to see the edit the hangout |
877 | + link |
878 | + """ |
879 | + |
880 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
881 | + response = self.view_virtual_meeting_page() |
882 | + self.assertContains( |
883 | + response, |
884 | + reverse( |
885 | + 'summit.schedule.views.edit_meeting_hangout', |
886 | + args=rev_args |
887 | + ), |
888 | + 0 |
889 | + ) |
890 | + self.assertContains(response, 'Edit Hangout Details', 0) |
891 | + |
892 | + def test_lead_can_edit_meeting_hangout(self): |
893 | + """ |
894 | + Tests that the track lead for the meeting can add the hangout URLs |
895 | + """ |
896 | + |
897 | + self.lead = factory.make_one( |
898 | + Lead, |
899 | + summit=self.summit, |
900 | + track=self.track, |
901 | + lead=self.attendee1, |
902 | + ) |
903 | + |
904 | + self.participant1 = Participant.objects.create( |
905 | + meeting=self.meeting1, |
906 | + attendee=self.attendee1, |
907 | + participation='REQUIRED' |
908 | + ) |
909 | + |
910 | + self.login() |
911 | + |
912 | + self.view_and_save_edit_meeting_hangout_form() |
913 | + |
914 | + def test_drafter_can_edit_meeting_hangout(self): |
915 | + """ |
916 | + Tests that the meeting drafter can add hangout URLs |
917 | + """ |
918 | + |
919 | + self.meeting1.drafter = self.attendee1 |
920 | + self.meeting1.save() |
921 | + |
922 | + self.participant1 = Participant.objects.create( |
923 | + meeting=self.meeting1, |
924 | + attendee=self.attendee1, |
925 | + participation='REQUIRED' |
926 | + ) |
927 | + self.login() |
928 | + |
929 | + self.view_and_save_edit_meeting_hangout_form() |
930 | + |
931 | + def test_manager_can_edit_meeting_hangout(self): |
932 | + """ |
933 | + Tests that a Summit Manager can add hangout URLs |
934 | + """ |
935 | + |
936 | + self.summit.managers.add(self.user1) |
937 | + |
938 | + self.participant1 = Participant.objects.create( |
939 | + meeting=self.meeting1, |
940 | + attendee=self.attendee1, |
941 | + participation='REQUIRED' |
942 | + ) |
943 | + self.login() |
944 | + |
945 | + self.view_and_save_edit_meeting_hangout_form() |
946 | + |
947 | + def test_scheduler_can_edit_meeting_hangout(self): |
948 | + """ |
949 | + Tests that a Summit Scheduler can add hangout URLs |
950 | + """ |
951 | + |
952 | + self.summit.schedulers.add(self.user1) |
953 | + |
954 | + self.participant1 = Participant.objects.create( |
955 | + meeting=self.meeting1, |
956 | + attendee=self.attendee1, |
957 | + participation='REQUIRED' |
958 | + ) |
959 | + self.login() |
960 | + |
961 | + self.view_and_save_edit_meeting_hangout_form() |
962 | + |
963 | + def test_regular_user_can_not_edit_meeting_hangout(self): |
964 | + """ |
965 | + Tests that a regular Summit user is not able to edit the hangout |
966 | + links |
967 | + """ |
968 | + |
969 | + self.login() |
970 | + |
971 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
972 | + response = self.c.get( |
973 | + reverse( |
974 | + 'summit.schedule.views.edit_meeting_hangout', |
975 | + args=rev_args |
976 | + ), |
977 | + ) |
978 | + self.assertEqual(response.status_code, 302) |
979 | + redirect_args = [self.summit.name, ] |
980 | + redirect_url = reverse( |
981 | + 'summit.schedule.views.summit', |
982 | + args=redirect_args |
983 | + ) |
984 | + self.assertEqual( |
985 | + response['Location'], |
986 | + 'http://testserver' + redirect_url, |
987 | + ) |
988 | + |
989 | + def test_non_logged_in_user_can_not_edit_meeting_hangout(self): |
990 | + """ |
991 | + Tests that a non-logged in user is not able to edit the hangout |
992 | + links |
993 | + """ |
994 | + |
995 | + rev_args = [self.summit.name, self.meeting1.id, self.meeting1.name] |
996 | + response = self.c.get( |
997 | + reverse( |
998 | + 'summit.schedule.views.edit_meeting_hangout', |
999 | + args=rev_args |
1000 | + ), |
1001 | + ) |
1002 | + self.assertEqual(response.status_code, 302) |
1003 | + redirect_url = reverse( |
1004 | + 'summit.schedule.views.edit_meeting_hangout', |
1005 | + args=rev_args |
1006 | + ) |
1007 | + self.assertEqual( |
1008 | + response['Location'], |
1009 | + 'http://testserver/openid/login?next=' + redirect_url, |
1010 | + ) |
1011 | + |
1012 | + def test_webchat(self): |
1013 | + """ |
1014 | + Tests that the webchat client is displayed on the virtual meeting page |
1015 | + with the proper room |
1016 | + """ |
1017 | + |
1018 | + response = self.view_virtual_meeting_page() |
1019 | + self.assertIn( |
1020 | + 'http://webchat.freenode.net?channels=' + |
1021 | + self.room.irc_channel + |
1022 | + '&uio=Mj10cnVlJjQ9dHJ1ZSY5PXRydWUmMTA9' + |
1023 | + 'dHJ1ZSYxMz1mYWxzZSYxND1mYWxzZQbf', |
1024 | + response.content |
1025 | + ) |
1026 | + |
1027 | + def test_hangout_broadcast_url(self): |
1028 | + """ |
1029 | + Tests that the hangout broadcast is displayed on the page |
1030 | + """ |
1031 | + |
1032 | + self.meeting1.broadcast_url = 'http://broadcasturl.com' |
1033 | + self.meeting1.save() |
1034 | + |
1035 | + response = self.view_virtual_meeting_page() |
1036 | + self.assertIn(self.meeting1.broadcast_url, response.content) |
1037 | + |
1038 | + def test_participant_essential_join_url(self): |
1039 | + """ |
1040 | + Tests that a participant who is essential is shown the link to join |
1041 | + the hangout |
1042 | + """ |
1043 | + |
1044 | + self.meeting1.hangout_url = 'http://hangouturl.com' |
1045 | + self.meeting1.save() |
1046 | + |
1047 | + self.participant1 = Participant.objects.create( |
1048 | + meeting=self.meeting1, |
1049 | + attendee=self.attendee1, |
1050 | + participation='REQUIRED' |
1051 | + ) |
1052 | + |
1053 | + self.login() |
1054 | + |
1055 | + response = self.view_virtual_meeting_page() |
1056 | + self.assertIn(self.meeting1.hangout_url, response.content) |
1057 | + self.assertIn('Join the Hangout on Air', response.content) |
1058 | + |
1059 | + def test_interested_participant_no_join_url(self): |
1060 | + """ |
1061 | + Tests that a non-essential participant is not shown the link to join |
1062 | + the hangout |
1063 | + """ |
1064 | + |
1065 | + self.meeting1.hangout_url = 'http://hangouturl.com' |
1066 | + self.meeting1.save() |
1067 | + |
1068 | + self.participant1 = Participant.objects.create( |
1069 | + meeting=self.meeting1, |
1070 | + attendee=self.attendee1, |
1071 | + participation='INTERESTED' |
1072 | + ) |
1073 | + |
1074 | + self.login() |
1075 | + |
1076 | + response = self.view_virtual_meeting_page() |
1077 | + self.assertNotIn(self.meeting1.hangout_url, response.content) |
1078 | + self.assertNotIn('Join the Hangout on Air', response.content) |
1079 | + |
1080 | + def test_attending_participant_no_join_url(self): |
1081 | + """ |
1082 | + Tests that a non-essential (attending) participant is not shown |
1083 | + the link to join the hangout |
1084 | + """ |
1085 | + |
1086 | + self.meeting1.hangout_url = 'http://hangouturl.com' |
1087 | + self.meeting1.save() |
1088 | + |
1089 | + self.participant1 = Participant.objects.create( |
1090 | + meeting=self.meeting1, |
1091 | + attendee=self.attendee1, |
1092 | + participation='ATTENDING' |
1093 | + ) |
1094 | + |
1095 | + self.login() |
1096 | + |
1097 | + response = self.view_virtual_meeting_page() |
1098 | + self.assertNotIn(self.meeting1.hangout_url, response.content) |
1099 | + self.assertNotIn('Join the Hangout on Air', response.content) |
1100 | + |
1101 | + def test_non_participant_no_join_url(self): |
1102 | + """ |
1103 | + Tests that a participant not attending the meeting is not shown the |
1104 | + link to join the hangout |
1105 | + """ |
1106 | + |
1107 | + self.meeting1.hangout_url = 'http://hangouturl.com' |
1108 | + self.meeting1.save() |
1109 | + |
1110 | + self.login() |
1111 | + |
1112 | + response = self.view_virtual_meeting_page() |
1113 | + self.assertNotIn(self.meeting1.hangout_url, response.content) |
1114 | + self.assertNotIn('Join the Hangout on Air', response.content) |
1115 | + |
1116 | + def test_not_logged_in_no_join_url(self): |
1117 | + """ |
1118 | + Tests that a non-essential participant is not shown the link to join |
1119 | + the hangout |
1120 | + """ |
1121 | + |
1122 | + self.meeting1.hangout_url = 'http://hangouturl.com' |
1123 | + self.meeting1.save() |
1124 | + |
1125 | + response = self.view_virtual_meeting_page() |
1126 | + self.assertNotIn(self.meeting1.hangout_url, response.content) |
1127 | + self.assertNotIn('Join the Hangout on Air', response.content) |
1128 | + |
1129 | + def test_etherpad(self): |
1130 | + """ |
1131 | + Tests that the etherpad client is displayed on the virtual meeting page |
1132 | + """ |
1133 | + |
1134 | + response = self.view_virtual_meeting_page() |
1135 | + self.assertIn(self.meeting1.pad_url, response.content) |
1136 | |
1137 | === modified file 'summit/schedule/tests/tests.py' |
1138 | --- summit/schedule/tests/tests.py 2013-02-22 01:22:19 +0000 |
1139 | +++ summit/schedule/tests/tests.py 2013-02-26 19:00:29 +0000 |
1140 | @@ -1728,7 +1728,12 @@ |
1141 | self.assertEquals(0, self.private_meeting.agenda_set.count()) |
1142 | |
1143 | # Private rooms should not ever be autoscheduled |
1144 | - self.assertEquals(0, Agenda.objects.filter(room__type='private').count()) |
1145 | + self.assertEquals( |
1146 | + 0, |
1147 | + Agenda.objects.filter( |
1148 | + room__type='private' |
1149 | + ).count() |
1150 | + ) |
1151 | |
1152 | def test_no_available_private_room(self): |
1153 | ''' |
1154 | @@ -1989,7 +1994,8 @@ |
1155 | ) |
1156 | |
1157 | def tearDown(self): |
1158 | - # Cached requests cause render.py to return old data, so clear the cache |
1159 | + # Cached requests cause render.py to return old data. |
1160 | + # Let's clear the cache |
1161 | if hasattr(cache, 'clear'): |
1162 | cache.clear() |
1163 | # Older django didn't have .clear, but locmem cache did have ._cull |
1164 | |
1165 | === modified file 'summit/schedule/views.py' |
1166 | --- summit/schedule/views.py 2013-02-21 23:10:17 +0000 |
1167 | +++ summit/schedule/views.py 2013-02-26 19:00:29 +0000 |
1168 | @@ -1,5 +1,5 @@ |
1169 | # The Summit Scheduler web application |
1170 | -# Copyright (C) 2008 - 2012 Ubuntu Community, Canonical Ltd |
1171 | +# Copyright (C) 2008 - 2013 Ubuntu Community, Canonical Ltd |
1172 | # |
1173 | # This program is free software: you can redistribute it and/or modify |
1174 | # it under the terms of the GNU Affero General Public License as |
1175 | @@ -464,8 +464,12 @@ |
1176 | tracks = meeting.tracks.all() |
1177 | user_is_attending = attendee is not None and attendee in meeting.attendees |
1178 | user_is_participating = attendee is not None and attendee in [p.attendee for p in participants if not p.from_launchpad] |
1179 | - |
1180 | - if attendee == meeting.drafter: |
1181 | + required = False |
1182 | + |
1183 | + if attendee is not None and attendee in meeting.required_attendees: |
1184 | + required = True |
1185 | + |
1186 | + if attendee is not None and attendee == meeting.drafter: |
1187 | drafter = True |
1188 | else: |
1189 | drafter = False |
1190 | @@ -478,6 +482,7 @@ |
1191 | 'attendees': attendees, |
1192 | 'user_is_attending': user_is_attending, |
1193 | 'user_is_participating': user_is_participating, |
1194 | + 'required': required, |
1195 | 'tracks': tracks, |
1196 | 'ETHERPAD_HOST': summit.etherpad, |
1197 | 'summit_organizer': summit.is_organizer(attendee), |
1198 | @@ -661,8 +666,11 @@ |
1199 | context = { |
1200 | 'past_summit': pastsummit, |
1201 | } |
1202 | - return render_to_response("schedule/past_summit.html", context, |
1203 | - context_instance=RequestContext(request)) |
1204 | + return render_to_response( |
1205 | + "schedule/past_summit.html", |
1206 | + context, |
1207 | + context_instance=RequestContext(request) |
1208 | + ) |
1209 | |
1210 | |
1211 | @summit_attendee_required |
1212 | @@ -695,8 +703,11 @@ |
1213 | 'summit': summit, |
1214 | 'form': form, |
1215 | } |
1216 | - return render_to_response('schedule/create_meeting.html', |
1217 | - context, RequestContext(request)) |
1218 | + return render_to_response( |
1219 | + 'schedule/create_meeting.html', |
1220 | + context, |
1221 | + RequestContext(request) |
1222 | + ) |
1223 | |
1224 | |
1225 | @summit_attendee_required |
1226 | @@ -721,8 +732,11 @@ |
1227 | 'summit': summit, |
1228 | 'form': form, |
1229 | } |
1230 | - return render_to_response('schedule/propose_meeting.html', |
1231 | - context, RequestContext(request)) |
1232 | + return render_to_response( |
1233 | + 'schedule/propose_meeting.html', |
1234 | + context, |
1235 | + RequestContext(request) |
1236 | + ) |
1237 | |
1238 | |
1239 | @summit_attendee_required |
1240 | @@ -755,8 +769,11 @@ |
1241 | 'summit': summit, |
1242 | 'form': form, |
1243 | } |
1244 | - return render_to_response('schedule/org_edit_meeting.html', |
1245 | - context, RequestContext(request)) |
1246 | + return render_to_response( |
1247 | + 'schedule/org_edit_meeting.html', |
1248 | + context, |
1249 | + RequestContext(request) |
1250 | + ) |
1251 | |
1252 | |
1253 | @summit_attendee_required |
1254 | @@ -783,8 +800,11 @@ |
1255 | 'summit': summit, |
1256 | 'form': form, |
1257 | } |
1258 | - return render_to_response('schedule/edit_meeting.html', |
1259 | - context, RequestContext(request)) |
1260 | + return render_to_response( |
1261 | + 'schedule/edit_meeting.html', |
1262 | + context, |
1263 | + RequestContext(request) |
1264 | + ) |
1265 | |
1266 | |
1267 | @summit_attendee_required |
1268 | @@ -818,8 +838,11 @@ |
1269 | 'summit': summit, |
1270 | 'form': form, |
1271 | } |
1272 | - return render_to_response('schedule/edit_hangout.html', |
1273 | - context, RequestContext(request)) |
1274 | + return render_to_response( |
1275 | + 'schedule/edit_hangout.html', |
1276 | + context, |
1277 | + RequestContext(request) |
1278 | + ) |
1279 | |
1280 | |
1281 | @summit_required |
1282 | @@ -877,8 +900,11 @@ |
1283 | 'summit': summit, |
1284 | 'form': form, |
1285 | } |
1286 | - return render_to_response('schedule/meeting_review.html', |
1287 | - context, RequestContext(request)) |
1288 | + return render_to_response( |
1289 | + 'schedule/meeting_review.html', |
1290 | + context, |
1291 | + RequestContext(request) |
1292 | + ) |
1293 | |
1294 | |
1295 | @summit_required |
1296 | @@ -902,8 +928,11 @@ |
1297 | 'drafter': drafter, |
1298 | 'attendee': attendee, |
1299 | } |
1300 | - return render_to_response("schedule/mine.html", context, |
1301 | - context_instance=RequestContext(request)) |
1302 | + return render_to_response( |
1303 | + "schedule/mine.html", |
1304 | + context, |
1305 | + context_instance=RequestContext(request) |
1306 | + ) |
1307 | |
1308 | |
1309 | @summit_required |
1310 | @@ -968,8 +997,11 @@ |
1311 | 'meeting.title': meeting.title, |
1312 | 'meeting': meeting, |
1313 | } |
1314 | - return render_to_response('schedule/attend.html', |
1315 | - context, RequestContext(request)) |
1316 | + return render_to_response( |
1317 | + 'schedule/attend.html', |
1318 | + context, |
1319 | + RequestContext(request) |
1320 | + ) |
1321 | |
1322 | |
1323 | @summit_required |
1324 | @@ -1054,8 +1086,11 @@ |
1325 | 'meeting': meeting, |
1326 | 'attendee': attendee, |
1327 | } |
1328 | - return render_to_response('schedule/org_attend.html', |
1329 | - context, RequestContext(request)) |
1330 | + return render_to_response( |
1331 | + 'schedule/org_attend.html', |
1332 | + context, |
1333 | + RequestContext(request) |
1334 | + ) |
1335 | |
1336 | |
1337 | @summit_attendee_required |
1338 | @@ -1081,8 +1116,11 @@ |
1339 | 'meeting.title': meeting.title, |
1340 | 'meeting': meeting, |
1341 | } |
1342 | - return render_to_response('schedule/delete_confirm.html', |
1343 | - context, RequestContext(request)) |
1344 | + return render_to_response( |
1345 | + 'schedule/delete_confirm.html', |
1346 | + context, |
1347 | + RequestContext(request) |
1348 | + ) |
1349 | |
1350 | |
1351 | @summit_attendee_required |
1352 | @@ -1114,5 +1152,8 @@ |
1353 | 'summit': summit |
1354 | } |
1355 | |
1356 | - return render_to_response('schedule/confirm_deletion.html', |
1357 | - context, RequestContext(request)) |
1358 | + return render_to_response( |
1359 | + 'schedule/confirm_deletion.html', |
1360 | + context, |
1361 | + RequestContext(request) |
1362 | + ) |
162 tests, all pass, great job