Merge lp:~cjohnston/summit/moves-tests into lp:summit

Proposed by Chris Johnston
Status: Superseded
Proposed branch: lp:~cjohnston/summit/moves-tests
Merge into: lp:summit
Diff against target: 1840 lines (+867/-186)
8 files modified
summit/schedule/forms.py (+71/-14)
summit/schedule/models/attendeemodel.py (+9/-2)
summit/schedule/models/summitmodel.py (+125/-37)
summit/schedule/templates/schedule/edit_hangout.html (+45/-0)
summit/schedule/templates/schedule/virtual_meeting.html (+146/-0)
summit/schedule/tests/__init__.py (+17/-0)
summit/schedule/views.py (+400/-103)
summit/urls.py (+54/-30)
To merge this branch: bzr merge lp:~cjohnston/summit/moves-tests
Reviewer Review Type Date Requested Status
Summit Hackers Pending
Review via email: mp+149961@code.launchpad.net

This proposal has been superseded by a proposal from 2013-02-22.

To post a comment you must log in.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'summit/schedule/forms.py'
2--- summit/schedule/forms.py 2012-08-12 22:32:46 +0000
3+++ summit/schedule/forms.py 2013-02-22 01:25:24 +0000
4@@ -22,6 +22,7 @@
5
6 from common.forms import RenderableMixin
7
8+
9 class MultipleAttendeeField(forms.ModelMultipleChoiceField):
10 def label_from_instance(self, obj):
11 return u"%s %s (%s)" % (
12@@ -36,12 +37,8 @@
13 required=False)
14
15 class Media:
16- css = {'all': (
17- '/media/css/colortip-1.0-jquery.css',
18- )}
19- js = (
20- '/media/js/colortip-1.0-jquery.js',
21- )
22+ css = {'all': ('/media/css/colortip-1.0-jquery.css',)}
23+ js = ('/media/js/colortip-1.0-jquery.js',)
24
25 def __init__(self, *args, **kwargs):
26 if 'instance' in kwargs:
27@@ -72,6 +69,7 @@
28 old_save_m2m = self.save_m2m
29 else:
30 old_save_m2m = None
31+
32 def save_m2m():
33 if old_save_m2m is not None:
34 old_save_m2m()
35@@ -94,43 +92,102 @@
36 class CreateMeeting(MeetingFormBase, RenderableMixin):
37 class Meta:
38 model = Meeting
39- fields = ('title', 'description', 'tracks', 'type', 'private', 'spec_url', 'wiki_url',
40- 'pad_url', 'requires_dial_in', 'slots', 'approved', 'video', 'override_break')
41+ fields = (
42+ 'title',
43+ 'description',
44+ 'tracks',
45+ 'type',
46+ 'private',
47+ 'spec_url',
48+ 'wiki_url',
49+ 'pad_url',
50+ 'requires_dial_in',
51+ 'slots',
52+ 'approved',
53+ 'video',
54+ 'override_break'
55+ )
56+
57
58 class OrganizerEditMeeting(MeetingFormBase, RenderableMixin):
59 class Meta:
60 model = Meeting
61- fields = ('title', 'description', 'tracks', 'type', 'private', 'spec_url', 'wiki_url',
62- 'pad_url', 'requires_dial_in', 'slots', 'approved', 'video', 'override_break')
63+ fields = (
64+ 'title',
65+ 'description',
66+ 'tracks',
67+ 'type',
68+ 'private',
69+ 'spec_url',
70+ 'wiki_url',
71+ 'pad_url',
72+ 'requires_dial_in',
73+ 'slots',
74+ 'approved',
75+ 'video',
76+ 'override_break'
77+ )
78+
79
80 class ProposeMeeting(MeetingFormBase, RenderableMixin):
81 class Meta:
82 model = Meeting
83- fields = ('title', 'description', 'tracks', 'spec_url', 'wiki_url', 'pad_url')
84+ fields = (
85+ 'title',
86+ 'description',
87+ 'tracks',
88+ 'spec_url',
89+ 'wiki_url',
90+ 'pad_url'
91+ )
92
93
94 class EditMeeting(MeetingFormBase, RenderableMixin):
95 class Meta:
96 model = Meeting
97- fields = ('title', 'description', 'tracks', 'spec_url', 'wiki_url', 'pad_url')
98+ fields = (
99+ 'title',
100+ 'description',
101+ 'tracks',
102+ 'spec_url',
103+ 'wiki_url',
104+ 'pad_url'
105+ )
106+
107
108 class MeetingReview(forms.ModelForm, RenderableMixin):
109 class Meta:
110 model = Meeting
111 fields = ('approved',)
112
113+
114 class AttendMeeting(forms.ModelForm, RenderableMixin):
115 class Meta:
116 model = Participant
117 fields = ('participation',)
118+
119 def __init__(self, *args, **kwargs):
120 super(AttendMeeting, self).__init__(*args, **kwargs)
121- self.fields['participation'].choices = ((u'ATTENDING', u'Attending'), (u'INTERESTED', u'Very interested in attending'))
122+ self.fields['participation'].choices = (
123+ (u'ATTENDING', u'Attending'),
124+ (u'INTERESTED', u'Very interested in attending')
125+ )
126+
127
128 class OrganizerChangeAttend(forms.ModelForm, RenderableMixin):
129 class Meta:
130 model = Participant
131 fields = ('participation',)
132+
133 def __init__(self, *args, **kwargs):
134 super(OrganizerChangeAttend, self).__init__(*args, **kwargs)
135- self.fields['participation'].choices = ((u'INTERESTED', u'Should Attend'), (u'REQUIRED', u'Required to Attend'))
136+ self.fields['participation'].choices = (
137+ (u'INTERESTED', u'Should Attend'),
138+ (u'REQUIRED', u'Required to Attend')
139+ )
140+
141+
142+class EditMeetingHangout(forms.ModelForm, RenderableMixin):
143+ class Meta:
144+ model = Meeting
145+ fields = ('hangout_url', 'broadcast_url')
146
147=== modified file 'summit/schedule/models/attendeemodel.py'
148--- summit/schedule/models/attendeemodel.py 2012-04-30 16:48:43 +0000
149+++ summit/schedule/models/attendeemodel.py 2013-02-22 01:25:24 +0000
150@@ -45,7 +45,7 @@
151 verbose_name='Willing to be Crew',
152 default=False)
153 secret_key_id = models.CharField(max_length=32, blank=True, null=True)
154-
155+
156 class Meta:
157 app_label = 'schedule'
158 ordering = ('user__username', 'summit')
159@@ -86,7 +86,14 @@
160 secret_key = property(get_secret_key, set_secret_key)
161
162 def ical_url(self):
163- return getattr(settings, 'SITE_ROOT', 'http://summit.ubuntu.com') + reverse('summit.schedule.views.user_private_ical', args=(self.summit.name,self.secret_key))
164+ return getattr(
165+ settings,
166+ 'SITE_ROOT',
167+ 'http://summit.ubuntu.com'
168+ ) + reverse(
169+ 'summit.schedule.views.user_private_ical',
170+ args=(self.summit.name, self.secret_key)
171+ )
172
173 def update_from_launchpad(self, elem):
174 """Update from Launchpad data."""
175
176=== modified file 'summit/schedule/models/summitmodel.py'
177--- summit/schedule/models/summitmodel.py 2013-02-20 17:33:14 +0000
178+++ summit/schedule/models/summitmodel.py 2013-02-22 01:25:24 +0000
179@@ -47,6 +47,8 @@
180
181 #Monkey patch for better use in the admin
182 User._meta.ordering = ['username']
183+
184+
185 def unicode_user(user):
186 display = []
187 if user.first_name:
188@@ -56,9 +58,10 @@
189 if len(display) == 0:
190 return user.username
191 else:
192- return user.username + ' (' +' '.join(display) + ')'
193+ return user.username + ' (' + ' '.join(display) + ')'
194 User.__unicode__ = unicode_user
195
196+
197 class SummitManager(CurrentSiteManager):
198
199 def next(self):
200@@ -68,6 +71,7 @@
201 # No summits have been defined in the database yet
202 return Summit(name="no_summits", title="No Summits Defined")
203
204+
205 class Summit(models.Model):
206 STATE_CHOICES = (
207 (u'sponsor', u'Sponsorship Requests'),
208@@ -81,22 +85,51 @@
209 sites = models.ManyToManyField(Site)
210 location = models.CharField(max_length=100, blank=True)
211 description = models.TextField(max_length=2047, blank=True)
212- etherpad = models.URLField(verify_exists=False, max_length=75, blank=False, default='http://pad.ubuntu.com/', help_text="Enter the URL of the etherpad server you would like to use")
213- qr = models.URLField(verify_exists=False, max_length=100, blank=True, default='', help_text="Enter the URL of the QR code for mobile device application")
214+ etherpad = models.URLField(
215+ verify_exists=False,
216+ max_length=75,
217+ blank=False,
218+ default='http://pad.ubuntu.com/',
219+ help_text="Enter the URL of the etherpad server you would like to use"
220+ )
221+ qr = models.URLField(
222+ verify_exists=False,
223+ max_length=100,
224+ blank=True,
225+ default='',
226+ help_text="Enter the URL of the QR code for mobile device application"
227+ )
228 hashtag = models.CharField(max_length=25, blank=True)
229- timezone = models.CharField(max_length=50,
230- choices=[(x, x) for x in pytz.common_timezones])
231+ timezone = models.CharField(
232+ max_length=50,
233+ choices=[(x, x) for x in pytz.common_timezones]
234+ )
235 last_update = models.DateTimeField(null=True, blank=True)
236- state = models.CharField(max_length=10, choices=STATE_CHOICES,
237- default=STATE_CHOICES[0][0])
238+ state = models.CharField(
239+ max_length=10,
240+ choices=STATE_CHOICES,
241+ default=STATE_CHOICES[0][0]
242+ )
243 date_start = models.DateField(blank=False, null=True)
244 date_end = models.DateField(blank=False, null=True)
245- managers = models.ManyToManyField(User, blank=True, related_name='managers')
246- schedulers = models.ManyToManyField(User, blank=True, related_name='schedulers')
247+ managers = models.ManyToManyField(
248+ User,
249+ blank=True,
250+ related_name='managers'
251+ )
252+ schedulers = models.ManyToManyField(
253+ User,
254+ blank=True,
255+ related_name='schedulers'
256+ )
257 virtual_summit = models.BooleanField(
258 help_text="Check this if the entire sprint is virtual"
259 )
260- help_text = models.TextField(null=True, blank=True, help_text='Summit specific instructions and links for getting help during the event')
261+ help_text = models.TextField(
262+ null=True,
263+ blank=True,
264+ help_text='Instructions and links for getting help during the event'
265+ )
266
267 objects = models.Manager()
268 on_site = SummitManager()
269@@ -109,7 +142,14 @@
270 return self.name
271
272 def get_absolute_url(self):
273- return getattr(settings, 'SITE_ROOT', 'http://summit.ubuntu.com') + reverse('summit.schedule.views.summit', args=(self.name,))
274+ return getattr(
275+ settings,
276+ 'SITE_ROOT',
277+ 'http://summit.ubuntu.com'
278+ ) + reverse(
279+ 'summit.schedule.views.summit',
280+ args=(self.name,)
281+ )
282
283 def localize(self, datetime):
284 """Convert a datetime to the summit-local timezone.
285@@ -172,7 +212,14 @@
286 return sorted(dates)
287
288 def ical_url(self):
289- return getattr(settings, 'SITE_ROOT', 'http://summit.ubuntu.com') + reverse('summit.schedule.views.ical', args=(self.name,))
290+ return getattr(
291+ settings,
292+ 'SITE_ROOT',
293+ 'http://summit.ubuntu.com'
294+ ) + reverse(
295+ 'summit.schedule.views.ical',
296+ args=(self.name,)
297+ )
298
299 def public_rooms(self):
300 """List of public rooms for this summit.
301@@ -192,7 +239,9 @@
302 else:
303 return cmp(a.track.title, b.track.title)
304
305- rooms = self.room_set.exclude(Q(type__exact='closed') | Q(type__exact='private'))
306+ rooms = self.room_set.exclude(
307+ Q(type__exact='closed') | Q(type__exact='private')
308+ )
309 return sorted(rooms, cmp=by_title)
310
311 def open_rooms(self):
312@@ -231,8 +280,12 @@
313 if sprints.count() > 0:
314 urls = [sprint.import_url for sprint in sprints]
315 else:
316- urls = [("https://launchpad.net/sprints/%s/+temp-meeting-export"
317- % self.name)]
318+ urls = [
319+ (
320+ "https://launchpad.net/sprints/%s/+temp-meeting-export"
321+ % self.name
322+ )
323+ ]
324 return urls
325
326 def update_from_launchpad_response(self, response, options={}):
327@@ -253,9 +306,16 @@
328 while trycounter <= retrytotal:
329 req = urllib2.Request(url)
330 req.add_header("Cache-Control", "no-cache")
331- req.add_header("Cookie", "lp=%s" % getattr(settings, "LP_AUTH_COOKIE", "please-don't-cache-me"))
332+ req.add_header(
333+ "Cookie",
334+ "lp=%s" % getattr(
335+ settings,
336+ "LP_AUTH_COOKIE",
337+ "please-don't-cache-me"
338+ )
339+ )
340 try:
341- export = urllib2.urlopen(req)
342+ export = urllib2.urlopen(req)
343 except urllib2.HTTPError, e:
344 trycounter += 1
345 if trycounter >= retrytotal:
346@@ -278,12 +338,16 @@
347 in_lp |= self.update_from_launchpad_response(sprint_info, options)
348
349 if not options.get('skip_meetings', False):
350- in_db = set(m for m in self.meeting_set.exclude(launchpad_blueprint_id__isnull=True))
351+ in_db = set(
352+ m for m in self.meeting_set.exclude(
353+ launchpad_blueprint_id__isnull=True
354+ )
355+ )
356
357 for extra in in_db.difference(in_lp):
358 print "Marking %s as removed" % extra.name
359 extra.agenda_set.all().delete()
360- extra.approved='REMOVED'
361+ extra.approved = 'REMOVED'
362 extra.save()
363
364 self.last_update = datetime.utcnow()
365@@ -298,19 +362,26 @@
366
367 print "user %s" % username
368 try:
369- attendee = self.attendee_set.get(user__username__exact=username[:30])
370+ attendee = self.attendee_set.get(
371+ user__username__exact=username[:30]
372+ )
373 except ObjectDoesNotExist:
374 try:
375 user = User.objects.get(username__exact=username[:30])
376 except ObjectDoesNotExist:
377- user = User.objects.create_user(username[:30], '', password=None)
378+ user = User.objects.create_user(
379+ username[:30],
380+ '',
381+ password=None
382+ )
383 launchpad.set_user_openid(user)
384
385 # Create with any start/end time since we overwrite shortly
386- attendee = self.attendee_set.create(user=user,
387- start=datetime.utcnow(),
388- end=datetime.utcnow())
389-
390+ attendee = self.attendee_set.create(
391+ user=user,
392+ start=datetime.utcnow(),
393+ end=datetime.utcnow()
394+ )
395
396 attendee.update_from_launchpad(elem)
397
398@@ -333,7 +404,12 @@
399 try:
400 meeting = self.meeting_set.get(launchpad_blueprint_id=bp_id)
401 except ObjectDoesNotExist:
402- meeting = self.meeting_set.create(name=name, title=full_name[:100], slots=slot_length, launchpad_blueprint_id=bp_id)
403+ meeting = self.meeting_set.create(
404+ name=name,
405+ title=full_name[:100],
406+ slots=slot_length,
407+ launchpad_blueprint_id=bp_id
408+ )
409 except:
410 pass
411
412@@ -347,13 +423,18 @@
413 This is a pretty simple best-fit/first-come-first-served scheduler,
414 but it suffices.
415 """
416- for meeting in self.meeting_set.filter(approved='APPROVED', agenda__isnull=True).order_by('id'):
417- meeting.try_schedule(with_interested = True)
418+ for meeting in self.meeting_set.filter(
419+ approved='APPROVED',
420+ agenda__isnull=True
421+ ).order_by('id'):
422+ meeting.try_schedule(with_interested=True)
423
424- for meeting in self.meeting_set.filter(approved='APPROVED', agenda__isnull=True).order_by('id'):
425+ for meeting in self.meeting_set.filter(
426+ approved='APPROVED',
427+ agenda__isnull=True
428+ ).order_by('id'):
429 meeting.try_schedule()
430
431-
432 def check_schedule(self):
433 """Check the schedule for existant errors."""
434 for meeting in self.meeting_set.all():
435@@ -361,14 +442,20 @@
436 try:
437 missing = meeting.check_schedule(agenda.slot, agenda.room)
438 if len(missing):
439- print "Warning: required people not available: %s at %s in %s: %s" % (
440- meeting, agenda.slot, agenda.room,
441- ', '.join(m.user.username for m in missing))
442+ print "Warning: required people not available:"
443+ "%s at %s in %s: %s" % (
444+ meeting,
445+ agenda.slot,
446+ agenda.room,
447+ ', '.join(m.user.username for m in missing)
448+ )
449 except meeting.SchedulingError, e:
450- print "Error: %s at %s in %s: %s" % (meeting,
451- agenda.slot,
452- agenda.room,
453- e)
454+ print "Error: %s at %s in %s: %s" % (
455+ meeting,
456+ agenda.slot,
457+ agenda.room,
458+ e
459+ )
460
461 def reschedule(self):
462 """Delete any automatically created agenda items that have problems."""
463@@ -426,6 +513,7 @@
464 return self.lead_set.filter(lead=attendee).exists()
465 return False
466
467+
468 class SummitSprint(models.Model):
469
470 summit = models.ForeignKey(Summit, related_name='sprint_set')
471
472=== added file 'summit/schedule/templates/schedule/edit_hangout.html'
473--- summit/schedule/templates/schedule/edit_hangout.html 1970-01-01 00:00:00 +0000
474+++ summit/schedule/templates/schedule/edit_hangout.html 2013-02-22 01:25:24 +0000
475@@ -0,0 +1,45 @@
476+{% extends "base.html" %}
477+
478+{% block page_name %}Edit Hangout - {{ summit.title }}{%endblock %}
479+{% block sub_nav %}{% endblock %}
480+
481+{% block extrahead %}{{ block.super }}
482+ <script type="text/javascript" src="{{MEDIA_URL}}js/colortip-1.0-jquery.js"></script>
483+ <link rel="stylesheet" type="text/css" href="{{MEDIA_URL}}css/colortip-1.0-jquery.css"/>
484+{% endblock %}
485+
486+{% block closure %}
487+<script type="text/javascript"><!--
488+$(document).ready(function(){
489+ $('span[rel*=help]').colorTip({color:'orange'});
490+});
491+--></script>
492+<style>
493+form ul {
494+ height: 12em;
495+ overflow-y: scroll;
496+ overflow-x: hidden;
497+}
498+</style>
499+{% endblock %}
500+
501+
502+{% block content %}
503+<div class="row">
504+ <article id="form" class="span-8">
505+ {% if form.errors %}
506+ <p style="color: red;">
507+ Please correct the error{{ form.errors|pluralize }} below.
508+ </p>
509+ {% endif %}
510+
511+ <form action="{{ request.path_info }}" method="POST">
512+ <fieldset>
513+ <h3>Edit Hangout</h3>
514+ {{ form.as_template }}
515+ {% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %}
516+ <input type="submit" name="submit" value="Save" class="submit-button" />
517+ </fieldset>
518+ </form>
519+ </article>
520+{% endblock %}
521
522=== added file 'summit/schedule/templates/schedule/virtual_meeting.html'
523--- summit/schedule/templates/schedule/virtual_meeting.html 1970-01-01 00:00:00 +0000
524+++ summit/schedule/templates/schedule/virtual_meeting.html 2013-02-22 01:25:24 +0000
525@@ -0,0 +1,146 @@
526+{% extends "base.html" %}
527+{% load schedule_perms datetime markup %}
528+
529+{% block page_name %}
530+ {{ meeting.title }} -
531+ {% if schedule.date %}{{ schedule.date|strftime:"%Y-%m-%d" }}{% endif %}
532+ {% if schedule.room %}{{ schedule.room.title }} - {{ summit.title }}{% endif %}
533+{% endblock %}
534+
535+{% block extrahead %}{{ block.super }}
536+ <link rel="stylesheet" type="text/css" media="screen" href="/media/css/virt.css" />
537+<meta property="fb:app_id" content="310260202349342" />
538+<meta property="og:title" content="{{ meeting.title }}{% if schedule.date %} - {{ schedule.date|strftime:"%Y-%m-%d" }}{% endif %}{% if schedule.room %}{{ schedule.room.title }}{% endif %}" />
539+{% if meeting.description %}
540+<meta property="og:description" content="{{ meeting.description|linebreaks|striptags }}" />
541+{% endif %}
542+<meta property="og:url" content="http://summit.ubuntu.com{% url summit.schedule.views.meeting meeting.summit.name, meeting.id, meeting.name|default:'-' %}" />
543+<meta property="og:image" content="http://summit.ubuntu.com/media/images/cof_orange_hex1.png" />
544+<meta property="og:site_name" content="The Summit Scheduler" />
545+<meta property="og:type" content="article" />
546+<meta itemprop="name" content="{{ meeting.title }}{% if schedule.date %} - {{ schedule.date|strftime:"%Y-%m-%d" }}{% endif %}{% if schedule.room %}{{ schedule.room.title }}{% endif %}" />
547+<meta itemprop="description" content="{{ meeting.description|linebreaks|striptags }}" />
548+{% endblock %}
549+
550+{% block sub_nav_links %}
551+ {% if meeting.private %}
552+ {% if meeting.private_key and meeting.private_key != '' %}
553+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.private_meeting meeting.summit.name, meeting.private_key, meeting.name|default:'-' %}">Shared URL</a></li>
554+ {% else %}
555+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.meeting meeting.summit.name, meeting.id, meeting.name|default:'-' %}+share">Share meeting</a></li>
556+ {% endif %}
557+ {% endif %}
558+
559+ {% if meeting.spec_url %}
560+ {% if summit_organizer or drafter %}
561+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.attendee_review summit.name, meeting.id, meeting.name|default:'-' %}">Review attendees</a></li>
562+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.edit_meeting_hangout summit.name, meeting.id, meeting.name|default:'-' %}">Edit Hangout Details</a></li>
563+ {% endif %}
564+ <li><a class="sub-nav-item" href="{{ meeting.spec_url }}">Blueprint</a></li>
565+ {% else %}
566+ {% if summit_organizer or drafter %}
567+ {% if not drafter %}
568+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.organizer_edit_meeting summit.name, meeting.id, meeting.name|default:'-' %}">Edit meeting</a></li>
569+ {% endif %}
570+ {% if not summit_organizer %}
571+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.edit_meeting summit.name, meeting.id, meeting.name|default:'-' %}">Edit meeting</a></li>
572+ {% endif %}
573+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.attendee_review summit.name, meeting.id, meeting.name|default:'-' %}">Review attendees</a></li>
574+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.edit_meeting_hangout summit.name, meeting.id, meeting.name|default:'-' %}">Edit Hangout Details</a></li>
575+ {% endif %}
576+ {% endif %}
577+
578+ {% if user_is_attending %}
579+ {% if user_is_participating %}
580+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.unregister meeting.summit.name, meeting.id, meeting.name|default:'-' %}">Skip this meeting</a></li>
581+ {% endif %}
582+ {% else %}
583+ {% if meeting.spec_url %}
584+ <li><a class="sub-nav-item" href="{{ meeting.spec_url }}/+subscribe">Subscribe to blueprint</a></li>
585+ {% endif %}
586+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.attend_meeting meeting.summit.name, meeting.id %}">Attend this meeting</a></li>
587+ {% endif %}
588+
589+ {% if scheduler %}
590+ <li><a class="sub-nav-item" href="{% url summit.schedule.views.meeting_copy meeting.summit.name, meeting.id, meeting.name|default:'-' %}">Copy meeting</a></li>
591+ {% endif %}
592+{% endblock %}
593+
594+{% block content %}
595+<div class="row">
596+<section class="span-9">
597+ <h2>{{ meeting.title }}</h2>
598+ <div id="description">
599+ {{ meeting.description|markdown:'safe' }}
600+ <h3><a href="{{ meeting.hangout_url }}">Join the Hangout on Air</a></h3>
601+ </div>
602+
603+</section>
604+<article class="span-3 last">
605+{% if meeting.private %}
606+{% else %}
607+<div class="share">
608+ <a href="http://www.reddit.com/submit" onclick="window.location = 'http://www.reddit.com/submit?url=' + encodeURIComponent(window.location); return false"> <img style="padding-bottom: 4px;"src="http://www.reddit.com/static/spreddit7.gif" alt="submit to reddit" border="0" /></a><br />
609+ <div id="fb-root"></div>
610+ <script>(function(d, s, id) {
611+ var js, fjs = d.getElementsByTagName(s)[0];
612+ if (d.getElementById(id)) {return;}
613+ js = d.createElement(s); js.id = id;
614+ js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=310260202349342";
615+ fjs.parentNode.insertBefore(js, fjs);
616+ }(document, 'script', 'facebook-jssdk'));</script>
617+ <div class="fb-like" data-href="" data-send="false" data-layout="box_count" data-width="40" data-show-faces="false" data-font="arial"></div>
618+ <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
619+ <g:plusone size="tall"></g:plusone>
620+ <a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-lang="en">Tweet</a>
621+ <script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
622+ <script src="http://www.stumbleupon.com/hostedbadge.php?s=5"></script>
623+</div>
624+
625+{% endif %}
626+</article>
627+</div>
628+<div class="row">
629+ <div class="span-4">
630+ <div align="center"><iframe width="420" height="295" src="{{ meeting.broadcast_url }}" frameborder="0" allowfullscreen></iframe></div>
631+ <iframe src="http://webchat.freenode.net?channels={% for ai in agenda_items %}{{ ai.room.irc_channel }}{% endfor %}&uio=Mj10cnVlJjQ9dHJ1ZSY5PXRydWUmMTA9dHJ1ZSYxMz1mYWxzZSYxND1mYWxzZQbf" width="100%" height="395"></iframe>
632+</div>
633+<div class="span-7 last">
634+ {% if meeting.private %}
635+ <h3>WARNING: Contents of this pad may not be private, and may be searcheable by non-attendees!</h3>
636+ {% endif %}
637+
638+<iframe width=100% height=700 src="{{ meeting.link_to_pad }}"></iframe>
639+</div>
640+</div>
641+<div class="row">
642+ {% ifnotequal meeting.type 'plenary' %}
643+ <div id="Attendees" class="span-4">
644+ <h3>Attendees</h3>
645+ {% for attendee in attendees %}
646+ <a href="http://launchpad.net/~{{ attendee.user.username }}">{% if attendee.participation = 'REQUIRED' %}<strong>{% endif %}{{ attendee.name }}{% if attendee.required %}</strong>{% endif %}</a>{% if not forloop.last %}, {% endif %}
647+ {% endfor %}
648+ </div>
649+ {% endifnotequal %}
650+ <div class="span-3">
651+{% if summit_organizer %}
652+ {% include "schedule/admin.html" %}
653+{% endif %}
654+ </div>
655+ <div id="Links" class="span-3 last">
656+ <h3>Links</h3>
657+ <ul>
658+ <li><a href="{{meeting.link_to_pad}}" target="_new">Notes in a separate window</a></li>
659+ <li><a href="{{meeting.edit_link_to_pad}}" target="_new">Edit notes window</a></li>
660+ {% if meeting.spec_url %}<li><a href="{{ meeting.spec_url }}">Blueprint</a></li>{% endif %}
661+ {% if meeting.wiki_url %}<li><a href="{{ meeting.wiki_url }}">Wiki page</a></li>{% endif %}
662+ {% for ai in agenda_items %}
663+ {% if ai.room.irc_channel %}<li><a href="https://webchat.freenode.net/?channels={{ai.room.irc_channel}}">IRC Channel: #{{ai.room.irc_channel}}</a></li>{% endif %}
664+ {% endfor %}
665+
666+ </ul>
667+ </div>
668+
669+</article>
670+</div>
671+{% endblock %}
672
673=== added directory 'summit/schedule/tests'
674=== added file 'summit/schedule/tests/__init__.py'
675--- summit/schedule/tests/__init__.py 1970-01-01 00:00:00 +0000
676+++ summit/schedule/tests/__init__.py 2013-02-22 01:25:24 +0000
677@@ -0,0 +1,17 @@
678+# The Summit Scheduler web application
679+# Copyright (C) 2008 - 2012 Ubuntu Community, Canonical Ltd
680+#
681+# This program is free software: you can redistribute it and/or modify
682+# it under the terms of the GNU Affero General Public License as
683+# published by the Free Software Foundation, either version 3 of the
684+# License, or (at your option) any later version.
685+#
686+# This program is distributed in the hope that it will be useful,
687+# but WITHOUT ANY WARRANTY; without even the implied warranty of
688+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
689+# GNU Affero General Public License for more details.
690+#
691+# You should have received a copy of the GNU Affero General Public License
692+# along with this program. If not, see <http://www.gnu.org/licenses/>.
693+
694+from tests import *
695
696=== renamed file 'summit/schedule/tests.py' => 'summit/schedule/tests/tests.py'
697=== modified file 'summit/schedule/views.py'
698--- summit/schedule/views.py 2012-10-26 10:23:28 +0000
699+++ summit/schedule/views.py 2013-02-22 01:25:24 +0000
700@@ -49,7 +49,8 @@
701 EditMeeting,
702 MeetingReview,
703 AttendMeeting,
704- OrganizerChangeAttend
705+ OrganizerChangeAttend,
706+ EditMeetingHangout
707 )
708
709 __all__ = (
710@@ -60,6 +61,7 @@
711 'today_view',
712 )
713
714+
715 @summit_required
716 def summit(request, summit, attendee):
717 edit = False
718@@ -81,14 +83,17 @@
719 return render_to_response("schedule/summit.html", context,
720 context_instance=RequestContext(request))
721
722+
723 @summit_only_required
724 def search(request, summit):
725 query = request.GET.get('q', None)
726 if query:
727- meetings = summit.meeting_set.filter(Q(name__icontains=query) | Q(title__icontains=query))
728+ meetings = summit.meeting_set.filter(
729+ Q(name__icontains=query) | Q(title__icontains=query)
730+ )
731 else:
732 meetings = []
733-
734+
735 context = {
736 'summit': summit,
737 'query': query,
738@@ -96,17 +101,28 @@
739 }
740 return render_to_response("schedule/search.html", context,
741 context_instance=RequestContext(request))
742+
743+
744 @summit_required
745 def daily_schedule(request, summit, attendee, date):
746- viewdate = summit.as_localtime(datetime.datetime.strptime(date, "%Y-%m-%d"))
747+ viewdate = summit.as_localtime(
748+ datetime.datetime.strptime(date, "%Y-%m-%d")
749+ )
750 utc_date = summit.delocalize(viewdate)
751 day = datetime.timedelta(days=1)
752
753 schedule = SortedDict()
754 multislot_meetings = SortedDict()
755
756- for slot in summit.slot_set.filter(start_utc__gte=utc_date, end_utc__lte=(utc_date+day)).order_by('start_utc'):
757- if not (slot.type == 'open' or slot.type == 'plenary' or slot.type == 'lunch'):
758+ for slot in summit.slot_set.filter(
759+ start_utc__gte=utc_date,
760+ end_utc__lte=(utc_date+day)
761+ ).order_by('start_utc'):
762+ if not (
763+ slot.type == 'open' or
764+ slot.type == 'plenary' or
765+ slot.type == 'lunch'
766+ ):
767 continue
768 if not slot in schedule:
769 schedule[slot] = SortedDict()
770@@ -117,7 +133,7 @@
771 if count == 1:
772 del multislot_meetings[agenda]
773 else:
774- multislot_meetings[agenda] = count -1
775+ multislot_meetings[agenda] = count - 1
776
777 # Add meetings from this slot
778 for agenda in slot.agenda_set.select_related().order_by('room__name'):
779@@ -125,7 +141,7 @@
780 schedule[slot][agenda.room] = agenda
781 if agenda.meeting.slots > 1:
782 multislot_meetings[agenda] = agenda.meeting.slots - 1
783-
784+
785 if '_popup' in request.GET:
786 is_popup = True
787
788@@ -141,29 +157,49 @@
789 }
790 return render_to_response("schedule/daily.html", context,
791 context_instance=RequestContext(request))
792-
793+
794+
795 @summit_attendee_required
796 def attendee_schedule(request, summit, attendee):
797 pass
798-
799+
800+
801 @summit_required
802 def by_date(request, summit, attendee, date):
803 return _process_date_view(request, summit, attendee, date)
804
805+
806 @summit_required
807 def today_view(request, summit, attendee):
808 today = summit.localize(datetime.datetime.now()).date()
809- return _process_date_view(request, summit, attendee, today.strftime("%Y-%m-%d"))
810+ return _process_date_view(
811+ request,
812+ summit,
813+ attendee,
814+ today.strftime("%Y-%m-%d")
815+ )
816+
817
818 def _process_date_view(request, summit, attendee, date):
819 if 'rooms' in request.GET:
820 roomnames = request.GET.get('rooms', '').split(',')
821 rooms = list(summit.room_set.filter(name__in=roomnames, type='open'))
822 if request.user.is_authenticated() and request.user.is_staff:
823- rooms += list(summit.room_set.filter(name__in=roomnames, type='private'))
824+ rooms += list(
825+ summit.room_set.filter(
826+ name__in=roomnames,
827+ type='private'
828+ )
829+ )
830 else:
831 rooms = None
832- schedule = schedule_factory(request, summit, attendee, room=rooms, date=date)
833+ schedule = schedule_factory(
834+ request,
835+ summit,
836+ attendee,
837+ room=rooms,
838+ date=date
839+ )
840
841 if request.method == 'POST':
842 return schedule.save_change()
843@@ -183,25 +219,42 @@
844 'previousday': viewdate - day,
845 'can_change_agenda': summit.can_change_agenda(attendee),
846 }
847- converted_date = summit.delocalize(datetime.datetime.strptime(date, "%Y-%m-%d"))
848- if 'edit' in request.GET or Slot.objects.filter(summit=summit, start_utc__gte=converted_date, end_utc__lte=converted_date+datetime.timedelta(days=1)).count() > 0:
849+ converted_date = summit.delocalize(
850+ datetime.datetime.strptime(date, "%Y-%m-%d")
851+ )
852+ if 'edit' in request.GET or Slot.objects.filter(
853+ summit=summit,
854+ start_utc__gte=converted_date,
855+ end_utc__lte=converted_date+datetime.timedelta(days=1)
856+ ).count() > 0:
857 schedule.calculate()
858 else:
859 return render_to_response("schedule/nosession.html", context,
860- context_instance=RequestContext(request))
861+ context_instance=RequestContext(request))
862 return render_to_response("schedule/schedule.html", context,
863 context_instance=RequestContext(request))
864
865+
866 @summit_required
867 def next_table(request, summit, attendee):
868 if 'rooms' in request.GET:
869 roomnames = request.GET.get('rooms', '').split(',')
870 rooms = list(summit.room_set.filter(name__in=roomnames, type='open'))
871 if request.user.is_authenticated() and request.user.is_staff:
872- rooms += list(summit.room_set.filter(name__in=roomnames, type='private'))
873+ rooms += list(
874+ summit.room_set.filter(
875+ name__in=roomnames, type='private'
876+ )
877+ )
878 else:
879 rooms = None
880- schedule = Schedule.from_request(request, summit, attendee, room=rooms, nextonly=True)
881+ schedule = Schedule.from_request(
882+ request,
883+ summit,
884+ attendee,
885+ room=rooms,
886+ nextonly=True
887+ )
888
889 schedule.calculate()
890
891@@ -214,6 +267,7 @@
892 return render_to_response("schedule/nextsession_table.html", context,
893 context_instance=RequestContext(request))
894
895+
896 @summit_required
897 def next_session(request, summit, attendee):
898 url_content = request.GET.urlencode(safe='_:')
899@@ -226,16 +280,21 @@
900 return render_to_response("schedule/nextsession.html", context,
901 context_instance=RequestContext(request))
902
903+
904 @summit_required
905 def by_room(request, summit, attendee, room_name):
906 schedule = SortedDict()
907 multislot_meetings = SortedDict()
908
909 room = get_object_or_404(Room, name=room_name, summit=summit)
910-
911+
912 for slot in summit.slot_set.all().order_by('start_utc'):
913
914- if not (slot.type == 'open' or slot.type == 'plenary' or slot.type == 'lunch'):
915+ if not (
916+ slot.type == 'open' or
917+ slot.type == 'plenary' or
918+ slot.type == 'lunch'
919+ ):
920 continue
921 if not slot in schedule:
922 schedule[slot] = SortedDict()
923@@ -246,7 +305,7 @@
924 if count == 1:
925 del multislot_meetings[agenda]
926 else:
927- multislot_meetings[agenda] = count -1
928+ multislot_meetings[agenda] = count - 1
929
930 # Add meetings from this slot
931 for agenda in slot.agenda_set.filter(room=room).select_related():
932@@ -277,7 +336,11 @@
933
934 for slot in summit.slot_set.all().order_by('start_utc'):
935
936- if not (slot.type == 'open' or slot.type == 'plenary' or slot.type == 'lunch'):
937+ if not (
938+ slot.type == 'open' or
939+ slot.type == 'plenary' or
940+ slot.type == 'lunch'
941+ ):
942 continue
943 if not slot in schedule:
944 schedule[slot] = SortedDict()
945@@ -288,10 +351,12 @@
946 if count == 1:
947 del multislot_meetings[agenda]
948 else:
949- multislot_meetings[agenda] = count -1
950+ multislot_meetings[agenda] = count - 1
951
952 # Add meetings from this slot
953- for agenda in slot.agenda_set.filter(meeting__tracks=track).select_related().order_by('room__name'):
954+ for agenda in slot.agenda_set.filter(
955+ meeting__tracks=track
956+ ).select_related().order_by('room__name'):
957 if not agenda.meeting.private or attendee in agenda.meeting.attendees:
958 schedule[slot][agenda.room] = agenda
959 if agenda.meeting.slots > 1:
960@@ -309,16 +374,25 @@
961 return render_to_response("schedule/by_track.html", context,
962 context_instance=RequestContext(request))
963
964+
965 @summit_required
966 def by_participant(request, summit, attendee, username):
967 schedule = SortedDict()
968 multislot_meetings = SortedDict()
969
970- participant = get_object_or_404(Attendee, user__username=username, summit=summit)
971+ participant = get_object_or_404(
972+ Attendee,
973+ user__username=username,
974+ summit=summit
975+ )
976
977 for slot in summit.slot_set.all().order_by('start_utc'):
978
979- if not (slot.type == 'open' or slot.type == 'plenary' or slot.type == 'lunch'):
980+ if not (
981+ slot.type == 'open' or
982+ slot.type == 'plenary' or
983+ slot.type == 'lunch'
984+ ):
985 continue
986 if not slot in schedule:
987 schedule[slot] = SortedDict()
988@@ -329,10 +403,18 @@
989 if count == 1:
990 del multislot_meetings[agenda]
991 else:
992- multislot_meetings[agenda] = count -1
993+ multislot_meetings[agenda] = count - 1
994
995 # Add meetings from this slot
996- for agenda in slot.agenda_set.filter(Q(meeting__participant__attendee=participant) | Q(meeting__drafter=participant) | Q(meeting__assignee=participant)).select_related().order_by('room__name'):
997+ for agenda in slot.agenda_set.filter(
998+ Q(
999+ meeting__participant__attendee=participant
1000+ ) | Q(
1001+ meeting__drafter=participant
1002+ ) | Q(
1003+ meeting__assignee=participant
1004+ )
1005+ ).select_related().order_by('room__name'):
1006 if not agenda.meeting.private or attendee in agenda.meeting.attendees:
1007 schedule[slot][agenda.room] = agenda
1008 if agenda.meeting.slots > 1:
1009@@ -350,6 +432,7 @@
1010 return render_to_response("schedule/by_participant.html", context,
1011 context_instance=RequestContext(request))
1012
1013+
1014 @summit_only_required
1015 def tracks(request, summit):
1016
1017@@ -359,6 +442,7 @@
1018 return render_to_response("schedule/tracks.html", context,
1019 context_instance=RequestContext(request))
1020
1021+
1022 @summit_required
1023 def meeting(request, summit, attendee, meeting_id, meeting_slug):
1024 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1025@@ -366,11 +450,13 @@
1026 raise Http404
1027 return _show_meeting(request, summit, meeting, attendee)
1028
1029+
1030 @summit_required
1031 def private_meeting(request, summit, attendee, private_key, meeting_slug):
1032 meeting = get_object_or_404(summit.meeting_set, private_key=private_key)
1033 return _show_meeting(request, summit, meeting, attendee)
1034
1035+
1036 def _show_meeting(request, summit, meeting, attendee):
1037 agendaitems = meeting.agenda_set.all()
1038 participants = meeting.participant_set.all()
1039@@ -378,29 +464,40 @@
1040 tracks = meeting.tracks.all()
1041 user_is_attending = attendee is not None and attendee in meeting.attendees
1042 user_is_participating = attendee is not None and attendee in [p.attendee for p in participants if not p.from_launchpad]
1043-
1044+
1045 if attendee == meeting.drafter:
1046 drafter = True
1047 else:
1048 drafter = False
1049-
1050+
1051 context = {
1052 'summit': summit,
1053- 'meeting':meeting,
1054- 'agenda_items':agendaitems,
1055- 'participants':participants,
1056+ 'meeting': meeting,
1057+ 'agenda_items': agendaitems,
1058+ 'participants': participants,
1059 'attendees': attendees,
1060 'user_is_attending': user_is_attending,
1061 'user_is_participating': user_is_participating,
1062- 'tracks':tracks,
1063+ 'tracks': tracks,
1064 'ETHERPAD_HOST': summit.etherpad,
1065 'summit_organizer': summit.is_organizer(attendee),
1066 'scheduler': summit.can_change_agenda(attendee),
1067 'is_scheduler': summit.is_scheduler(attendee),
1068 'drafter': drafter,
1069 }
1070- return render_to_response("schedule/meeting.html", context,
1071- context_instance=RequestContext(request))
1072+ if summit.virtual_summit or meeting.virtual_meeting:
1073+ return render_to_response(
1074+ "schedule/virtual_meeting.html",
1075+ context,
1076+ context_instance=RequestContext(request)
1077+ )
1078+ else:
1079+ return render_to_response(
1080+ "schedule/meeting.html",
1081+ context,
1082+ context_instance=RequestContext(request)
1083+ )
1084+
1085
1086 @summit_required
1087 def share_meeting(request, summit, attendee, meeting_id, meeting_slug):
1088@@ -409,30 +506,62 @@
1089 # check if the user should be able to see this private meeting
1090 if attendee is None:
1091 raise Http404
1092-
1093+
1094 attendee_allowed = False
1095 for a in meeting.attendees:
1096 if a.user.pk == attendee.user.pk:
1097 meeting.share()
1098- return HttpResponseRedirect(reverse(private_meeting, args=[summit.name, meeting.private_key, meeting_slug]))
1099+ return HttpResponseRedirect(
1100+ reverse(
1101+ private_meeting,
1102+ args=[summit.name, meeting.private_key, meeting_slug]
1103+ )
1104+ )
1105 raise Http404
1106- return HttpResponseRedirect(reverse(meeting, summit.name, meeting.id, meeting_slug))
1107-
1108+ return HttpResponseRedirect(
1109+ reverse(
1110+ meeting,
1111+ summit.name,
1112+ meeting.id,
1113+ meeting_slug
1114+ )
1115+ )
1116+
1117+
1118 @summit_attendee_required
1119 def register(request, summit, attendee, meeting_id, meeting_slug):
1120 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1121 user_is_attending = attendee is not None and attendee in meeting.attendees
1122 if not user_is_attending:
1123- meeting.participant_set.create(attendee=attendee, participation = 'ATTENDING', from_launchpad=False)
1124-
1125- return HttpResponseRedirect(reverse('summit.schedule.views.meeting', args=(summit.name, meeting.id, meeting_slug)))
1126+ meeting.participant_set.create(
1127+ attendee=attendee,
1128+ participation='ATTENDING',
1129+ from_launchpad=False
1130+ )
1131+
1132+ return HttpResponseRedirect(
1133+ reverse(
1134+ 'summit.schedule.views.meeting',
1135+ args=(summit.name, meeting.id, meeting_slug)
1136+ )
1137+ )
1138+
1139
1140 @summit_attendee_required
1141 def unregister(request, summit, attendee, meeting_id, meeting_slug):
1142 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1143- meeting.participant_set.filter(attendee=attendee, from_launchpad=False).delete()
1144-
1145- return HttpResponseRedirect(reverse('summit.schedule.views.meeting', args=(summit.name, meeting.id, meeting_slug)))
1146+ meeting.participant_set.filter(
1147+ attendee=attendee,
1148+ from_launchpad=False
1149+ ).delete()
1150+
1151+ return HttpResponseRedirect(
1152+ reverse(
1153+ 'summit.schedule.views.meeting',
1154+ args=(summit.name, meeting.id, meeting_slug)
1155+ )
1156+ )
1157+
1158
1159 @summit_only_required
1160 def csv(request, summit):
1161@@ -442,70 +571,82 @@
1162 return HttpResponse(schedule.as_csv(),
1163 mimetype='text/csv')
1164
1165+
1166 @summit_only_required
1167 def ical(request, summit):
1168 """Return any list events as an ical"""
1169 schedule = Schedule.from_request(request, summit)
1170 schedule.calculate()
1171-
1172+
1173 filename = "%s.ical" % summit.name.replace(' ', '-').lower()
1174 response = HttpResponse(mimetype='text/calendar')
1175 response['Content-Disposition'] = 'attachment; filename=%s' % filename.encode('ascii', 'replace')
1176 response.write(schedule.as_ical())
1177 return response
1178
1179+
1180 @summit_only_required
1181 def user_ical(request, summit, username):
1182 """Returns a user's registered events as an ical"""
1183 schedule = Schedule.from_request(request, summit)
1184 schedule.calculate()
1185-
1186+
1187 filename = "%s_%s.ical" % (summit.name, username)
1188 response = HttpResponse(mimetype='text/calendar')
1189 response['Content-Disposition'] = 'attachment; filename=%s' % filename.replace(' ', '-').lower().encode('ascii', 'replace')
1190 response.write(schedule.as_ical(only_username=username))
1191 return response
1192-
1193+
1194+
1195 @summit_only_required
1196 def user_private_ical(request, summit, secret_key):
1197 """Returns a user's registered events as an ical"""
1198 attendee = get_object_or_404(Attendee, secret_key_id=secret_key)
1199 schedule = Schedule.from_request(request, summit, show_private=True)
1200 schedule.calculate()
1201-
1202+
1203 response = HttpResponse(mimetype='text/calendar')
1204 response['Content-Disposition'] = 'attachment; filename=my_schedule_%s.ical' % attendee.secret_key
1205- response.write(schedule.as_ical(only_username=attendee.user.username, show_private=True))
1206+ response.write(
1207+ schedule.as_ical(
1208+ only_username=attendee.user.username,
1209+ show_private=True
1210+ )
1211+ )
1212 return response
1213-
1214+
1215+
1216 @summit_only_required
1217 def room_ical(request, summit, room_name):
1218 """Returns a room's events as an ical"""
1219 schedule = Schedule.from_request(request, summit)
1220 schedule.calculate()
1221-
1222+
1223 filename = "%s_%s.ical" % (summit.name, room_name)
1224 response = HttpResponse(mimetype='text/calendar')
1225 response['Content-Disposition'] = 'attachment; filename=%s' % filename.replace(' ', '-').lower().encode('ascii', 'replace')
1226 response.write(schedule.as_ical(only_room=room_name))
1227 return response
1228-
1229+
1230+
1231 @summit_only_required
1232 def track_ical(request, summit, track_slug):
1233 """Returns a track's events as an ical"""
1234 schedule = Schedule.from_request(request, summit)
1235 schedule.calculate()
1236-
1237+
1238 filename = "%s_%s.ical" % (summit.name, track_slug)
1239 response = HttpResponse(mimetype='text/calendar')
1240 response['Content-Disposition'] = 'attachment; filename=%s' % filename.replace(' ', '-').lower().encode('ascii', 'replace')
1241 response.write(schedule.as_ical(only_track=track_slug))
1242 return response
1243-
1244+
1245+
1246 def logout_view(request):
1247 logout(request)
1248 return HttpResponseRedirect('/')
1249
1250+
1251 @summit_required
1252 def mobile(request, summit, attendee):
1253 context = {
1254@@ -514,6 +655,7 @@
1255 }
1256 return render_to_response("schedule/mobile.html", context, RequestContext(request))
1257
1258+
1259 def past(request):
1260 pastsummit = Summit.on_site.filter(date_end__lte=datetime.date.today())
1261 context = {
1262@@ -522,15 +664,26 @@
1263 return render_to_response("schedule/past_summit.html", context,
1264 context_instance=RequestContext(request))
1265
1266+
1267 @summit_attendee_required
1268 def create_meeting(request, summit, attendee):
1269
1270 if not summit.is_organizer(attendee):
1271- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1272+ return HttpResponseRedirect(
1273+ reverse(
1274+ 'summit.schedule.views.summit',
1275+ args=(summit.name,)
1276+ )
1277+ )
1278 else:
1279- meeting = Meeting(summit=summit, approver=attendee, drafter=attendee, approved='APPROVED')
1280-
1281- if request.method == 'POST':
1282+ meeting = Meeting(
1283+ summit=summit,
1284+ approver=attendee,
1285+ drafter=attendee,
1286+ approved='APPROVED'
1287+ )
1288+
1289+ if request.method == 'POST':
1290 form = CreateMeeting(data=request.POST, instance=meeting)
1291 if form.is_valid():
1292 form.save()
1293@@ -542,15 +695,21 @@
1294 'summit': summit,
1295 'form': form,
1296 }
1297- return render_to_response('schedule/create_meeting.html',
1298+ return render_to_response('schedule/create_meeting.html',
1299 context, RequestContext(request))
1300
1301+
1302 @summit_attendee_required
1303 def propose_meeting(request, summit, attendee):
1304
1305- meeting = Meeting(summit=summit, drafter=attendee, private=False, approved='PENDING')
1306+ meeting = Meeting(
1307+ summit=summit,
1308+ drafter=attendee,
1309+ private=False,
1310+ approved='PENDING'
1311+ )
1312
1313- if request.method == 'POST':
1314+ if request.method == 'POST':
1315 form = ProposeMeeting(data=request.POST, instance=meeting)
1316 if form.is_valid():
1317 form.save()
1318@@ -562,17 +721,29 @@
1319 'summit': summit,
1320 'form': form,
1321 }
1322- return render_to_response('schedule/propose_meeting.html',
1323+ return render_to_response('schedule/propose_meeting.html',
1324 context, RequestContext(request))
1325-
1326+
1327+
1328 @summit_attendee_required
1329-def organizer_edit_meeting(request, summit, attendee, meeting_id, meeting_slug):
1330+def organizer_edit_meeting(
1331+ request,
1332+ summit,
1333+ attendee,
1334+ meeting_id,
1335+ meeting_slug
1336+):
1337 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1338-
1339+
1340 if not summit.is_organizer(attendee):
1341- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1342+ return HttpResponseRedirect(
1343+ reverse(
1344+ 'summit.schedule.views.summit',
1345+ args=(summit.name,)
1346+ )
1347+ )
1348 else:
1349- if request.method == 'POST':
1350+ if request.method == 'POST':
1351 form = OrganizerEditMeeting(data=request.POST, instance=meeting)
1352 if form.is_valid():
1353 form.save()
1354@@ -584,17 +755,23 @@
1355 'summit': summit,
1356 'form': form,
1357 }
1358- return render_to_response('schedule/org_edit_meeting.html',
1359+ return render_to_response('schedule/org_edit_meeting.html',
1360 context, RequestContext(request))
1361
1362+
1363 @summit_attendee_required
1364 def edit_meeting(request, summit, attendee, meeting_id, meeting_slug):
1365 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1366-
1367+
1368 if attendee != meeting.drafter:
1369- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1370+ return HttpResponseRedirect(
1371+ reverse(
1372+ 'summit.schedule.views.summit',
1373+ args=(summit.name,)
1374+ )
1375+ )
1376 else:
1377- if request.method == 'POST':
1378+ if request.method == 'POST':
1379 form = EditMeeting(data=request.POST, instance=meeting)
1380 if form.is_valid():
1381 form.save()
1382@@ -606,14 +783,55 @@
1383 'summit': summit,
1384 'form': form,
1385 }
1386- return render_to_response('schedule/edit_meeting.html',
1387- context, RequestContext(request))
1388+ return render_to_response('schedule/edit_meeting.html',
1389+ context, RequestContext(request))
1390+
1391+
1392+@summit_attendee_required
1393+def edit_meeting_hangout(
1394+ request,
1395+ summit,
1396+ attendee,
1397+ meeting_id,
1398+ meeting_slug
1399+):
1400+ meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1401+ # TODO: Add logic that prevents this view from being accessed if the
1402+ # Summit or meeting is not virtual
1403+ if not summit.is_organizer(attendee) and attendee != meeting.drafter:
1404+ return HttpResponseRedirect(
1405+ reverse(
1406+ 'summit.schedule.views.summit',
1407+ args=(summit.name,)
1408+ )
1409+ )
1410+ else:
1411+ if request.method == 'POST':
1412+ form = EditMeetingHangout(data=request.POST, instance=meeting)
1413+ if form.is_valid():
1414+ form.save()
1415+ return HttpResponseRedirect(meeting.meeting_page_url)
1416+ else:
1417+ form = EditMeetingHangout(instance=meeting)
1418+
1419+ context = {
1420+ 'summit': summit,
1421+ 'form': form,
1422+ }
1423+ return render_to_response('schedule/edit_hangout.html',
1424+ context, RequestContext(request))
1425+
1426
1427 @summit_required
1428 def review_pending(request, summit, attendee):
1429
1430 if not summit.is_organizer(attendee):
1431- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1432+ return HttpResponseRedirect(
1433+ reverse(
1434+ 'summit.schedule.views.summit',
1435+ args=(summit.name,)
1436+ )
1437+ )
1438 else:
1439 schedule = SortedDict()
1440
1441@@ -632,12 +850,18 @@
1442 return render_to_response("schedule/review.html", context,
1443 context_instance=RequestContext(request))
1444
1445+
1446 @summit_required
1447 def meeting_review(request, summit, attendee, meeting_id):
1448 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1449
1450 if not summit.is_organizer(attendee):
1451- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1452+ return HttpResponseRedirect(
1453+ reverse(
1454+ 'summit.schedule.views.summit',
1455+ args=(summit.name,)
1456+ )
1457+ )
1458 else:
1459 if request.method == 'POST':
1460 form = MeetingReview(data=request.POST, instance=meeting)
1461@@ -656,12 +880,19 @@
1462 return render_to_response('schedule/meeting_review.html',
1463 context, RequestContext(request))
1464
1465+
1466 @summit_required
1467 def created_meetings(request, summit, attendee, username):
1468
1469- drafter = get_object_or_404(Attendee, summit=summit, user__username=username)
1470+ drafter = get_object_or_404(
1471+ Attendee,
1472+ summit=summit,
1473+ user__username=username
1474+ )
1475 if attendee is None or attendee.id != drafter.id:
1476- meetings = summit.meeting_set.filter(drafter=drafter).exclude(private=True)
1477+ meetings = summit.meeting_set.filter(
1478+ drafter=drafter
1479+ ).exclude(private=True)
1480 else:
1481 meetings = summit.meeting_set.filter(drafter=drafter)
1482
1483@@ -674,12 +905,18 @@
1484 return render_to_response("schedule/mine.html", context,
1485 context_instance=RequestContext(request))
1486
1487+
1488 @summit_required
1489 def meeting_copy(request, summit, attendee, meeting_id, meeting_slug):
1490 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1491
1492 if not summit.can_change_agenda(attendee):
1493- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1494+ return HttpResponseRedirect(
1495+ reverse(
1496+ 'summit.schedule.views.summit',
1497+ args=(summit.name,)
1498+ )
1499+ )
1500 else:
1501 if request.method == 'POST':
1502 form = CreateMeeting(instance=meeting, data=request.POST)
1503@@ -692,7 +929,6 @@
1504 meeting = form.save()
1505 meeting_id = meeting.id
1506 return HttpResponseRedirect(meeting.meeting_page_url)
1507-
1508 else:
1509 form = CreateMeeting(instance=meeting)
1510
1511@@ -700,19 +936,23 @@
1512 'summit': summit,
1513 'form': form,
1514 }
1515-
1516- return render_to_response('schedule/create_meeting.html',
1517+
1518+ return render_to_response('schedule/create_meeting.html',
1519 context, RequestContext(request))
1520
1521+
1522 @summit_attendee_required
1523 def attend_meeting(request, summit, attendee, meeting_id):
1524 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1525
1526 try:
1527- participant = Participant.objects.get(attendee=attendee, meeting=meeting)
1528+ participant = Participant.objects.get(
1529+ attendee=attendee,
1530+ meeting=meeting
1531+ )
1532 except Participant.DoesNotExist:
1533 participant = Participant(attendee=attendee, meeting=meeting)
1534-
1535+
1536 if request.method == 'POST':
1537 form = AttendMeeting(data=request.POST, instance=participant)
1538 if form.is_valid():
1539@@ -731,44 +971,79 @@
1540 return render_to_response('schedule/attend.html',
1541 context, RequestContext(request))
1542
1543+
1544 @summit_required
1545 def attendee_review(request, summit, attendee, meeting_slug, meeting_id):
1546 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1547
1548 if not summit.is_organizer(attendee) and attendee != meeting.drafter:
1549- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1550+ return HttpResponseRedirect(
1551+ reverse(
1552+ 'summit.schedule.views.summit',
1553+ args=(summit.name,)
1554+ )
1555+ )
1556 else:
1557 participants = meeting.participant_set.all()
1558
1559 context = {
1560 'summit': summit,
1561- 'meeting':meeting,
1562- 'participants':participants,
1563+ 'meeting': meeting,
1564+ 'participants': participants,
1565 'summit_organizer': summit.is_organizer(attendee),
1566
1567 }
1568 return render_to_response("schedule/attendees.html", context,
1569 context_instance=RequestContext(request))
1570
1571+
1572 @summit_attendee_required
1573-def organizer_edit_attendees(request, summit, logged_in_user, username, meeting_id):
1574+def organizer_edit_attendees(
1575+ request,
1576+ summit,
1577+ logged_in_user,
1578+ username,
1579+ meeting_id
1580+):
1581 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1582- attendee = get_object_or_404(Attendee, summit=summit, user__username=username)
1583+ attendee = get_object_or_404(
1584+ Attendee,
1585+ summit=summit,
1586+ user__username=username
1587+ )
1588 meeting_slug = get_object_or_404(Meeting, summit=summit, id=meeting_id)
1589
1590- if not summit.is_organizer(logged_in_user) and logged_in_user != meeting.drafter:
1591- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1592+ if not summit.is_organizer(
1593+ logged_in_user
1594+ ) and logged_in_user != meeting.drafter:
1595+ return HttpResponseRedirect(
1596+ reverse(
1597+ 'summit.schedule.views.summit',
1598+ args=(summit.name,)
1599+ )
1600+ )
1601 else:
1602 try:
1603- participant = Participant.objects.get(attendee=attendee, meeting=meeting)
1604+ participant = Participant.objects.get(
1605+ attendee=attendee,
1606+ meeting=meeting
1607+ )
1608 except Participant.DoesNotExist:
1609 participant = Participant(attendee=attendee, meeting=meeting)
1610-
1611+
1612 if request.method == 'POST':
1613- form = OrganizerChangeAttend(data=request.POST, instance=participant)
1614+ form = OrganizerChangeAttend(
1615+ data=request.POST,
1616+ instance=participant
1617+ )
1618 if form.is_valid():
1619 form.save()
1620- return HttpResponseRedirect(reverse('summit.schedule.views.attendee_review', args=(summit.name, meeting.id, meeting.name)))
1621+ return HttpResponseRedirect(
1622+ reverse(
1623+ 'summit.schedule.views.attendee_review',
1624+ args=(summit.name, meeting.id, meeting.name)
1625+ )
1626+ )
1627 else:
1628 form = OrganizerChangeAttend(instance=participant)
1629
1630@@ -784,11 +1059,22 @@
1631
1632
1633 @summit_attendee_required
1634-def delete_meeting_confirm(request, summit, attendee, meeting_id, meeting_slug):
1635+def delete_meeting_confirm(
1636+ request,
1637+ summit,
1638+ attendee,
1639+ meeting_id,
1640+ meeting_slug
1641+):
1642 meeting = get_object_or_404(summit.meeting_set, id=meeting_id)
1643-
1644+
1645 if not attendee.user in summit.schedulers.all() and not attendee.user.has_perm('schedule.change_agenda'):
1646- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1647+ return HttpResponseRedirect(
1648+ reverse(
1649+ 'summit.schedule.views.summit',
1650+ args=(summit.name,)
1651+ )
1652+ )
1653
1654 context = {
1655 'summit': summit,
1656@@ -801,18 +1087,29 @@
1657
1658 @summit_attendee_required
1659 def delete_meeting(request, summit, attendee, meeting_id, meeting_slug):
1660- meeting = get_object_or_404(summit.meeting_set, pk = meeting_id)
1661+ meeting = get_object_or_404(summit.meeting_set, pk=meeting_id)
1662 if not attendee.user in summit.schedulers.all() and not attendee.user.has_perm('schedule.change_agenda'):
1663- return HttpResponseRedirect(reverse('summit.schedule.views.summit', args=(summit.name,)))
1664+ return HttpResponseRedirect(
1665+ reverse(
1666+ 'summit.schedule.views.summit',
1667+ args=(summit.name,)
1668+ )
1669+ )
1670 else:
1671 meeting.approved = 'REMOVED'
1672 meeting.save()
1673 meeting.agenda_set.all().delete()
1674- return HttpResponseRedirect(reverse('summit.schedule.views.delete_confirmed', args=(summit.name,)))
1675+ return HttpResponseRedirect(
1676+ reverse(
1677+ 'summit.schedule.views.delete_confirmed',
1678+ args=(summit.name,)
1679+ )
1680+ )
1681+
1682
1683 def delete_confirmed(request, summit_name):
1684 summit = get_object_or_404(Summit, name=summit_name)
1685-
1686+
1687 context = {
1688 'summit': summit
1689 }
1690
1691=== modified file 'summit/urls.py'
1692--- summit/urls.py 2012-10-26 09:32:11 +0000
1693+++ summit/urls.py 2013-02-22 01:25:24 +0000
1694@@ -16,7 +16,6 @@
1695
1696 from django.conf.urls.defaults import *
1697 from django.conf import settings
1698-import ubuntu_website
1699
1700 from common.views import login_failure
1701
1702@@ -24,13 +23,15 @@
1703 admin.autodiscover()
1704
1705
1706-urlpatterns = patterns('',
1707+urlpatterns = patterns(
1708+ '',
1709 (r'^$', 'summit.common.views.index'),
1710 (r'^admin/', admin.site.urls),
1711 (r'^api/', include('services.urls')),
1712 )
1713
1714-urlpatterns += patterns('django_openid_auth.views',
1715+urlpatterns += patterns(
1716+ 'django_openid_auth.views',
1717 url(r'^openid/login/$', 'login_begin', name='openid-login',
1718 kwargs={'render_failure': login_failure}),
1719 url(r'^openid/complete/$', 'login_complete', name='openid-complete',
1720@@ -38,19 +39,17 @@
1721 url(r'^openid/logo.gif$', 'logo', name='openid-logo'),
1722 )
1723
1724-urlpatterns += patterns('summit.sponsor.views',
1725+urlpatterns += patterns(
1726+ 'summit.sponsor.views',
1727 (r'^(?P<summit_name>[\w-]+)/sponsorship/$', 'sponsorship'),
1728 (r'^(?P<summit_name>[\w-]+)/sponsorship/done/$', 'done'),
1729 (r'^(?P<summit_name>[\w-]+)/sponsorship/review/$', 'review_list'),
1730-
1731 (r'^(?P<summit_name>[\w-]+)/suggestsponsorship/$', 'suggestsponsorship'),
1732 (r'^(?P<summit_name>[\w-]+)/suggestsponsorship/done/$', 'suggestiondone'),
1733-
1734 (r'^(?P<summit_name>[\w-]+)/nonlaunchpadsponsorship/$',
1735 'nonlaunchpadsponsorship'),
1736 (r'^(?P<summit_name>[\w-]+)/nonlaunchpadsponsorship/done/$',
1737 'nonlaunchpaddone'),
1738-
1739 (r'^(?P<summit_name>[\w-]+)/sponsorship/review/(?P<sponsorship_id>[0-9]+)$',
1740 'review'),
1741 (r'^(?P<summit_name>[\w-]+)/suggestedsponsorship/review/(?P<sponsorship_id>[0-9]+)$',
1742@@ -61,7 +60,8 @@
1743 (r'^(?P<summit_name>[\w-]+)/sponsorship/export/$', 'export'),
1744 )
1745
1746-urlpatterns += patterns('summit.schedule.views',
1747+urlpatterns += patterns(
1748+ 'summit.schedule.views',
1749 url(r'^today/(?P<summit_name>[\w-]+)/$', 'today_view', name='today'),
1750 url(r'^past/', 'past', name='past'),
1751 url(r'^logout$', 'logout_view', name='logout'),
1752@@ -69,42 +69,66 @@
1753 (r'^(?P<summit_name>[\w-]+)/mobile/$', 'mobile'),
1754 (r'^(?P<summit_name>[\w-]+)/search/$', 'search'),
1755 (r'^(?P<summit_name>[\w-]+)/propose_meeting/$', 'propose_meeting'),
1756- (r'^(?P<summit_name>[\w-]+)/edit_meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'edit_meeting'),
1757+ (r'^(?P<summit_name>[\w-]+)/edit_meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
1758+ 'edit_meeting'),
1759 (r'^(?P<summit_name>[\w-]+)/review/$', 'review_pending'),
1760- (r'^(?P<summit_name>[\w-]+)/review_meeting/(?P<meeting_id>\d+)/$', 'meeting_review'),
1761- (r'^(?P<summit_name>[\w-]+)/attend_meeting/(?P<meeting_id>\d+)/$', 'attend_meeting'),
1762- (r'^(?P<summit_name>[\w-]+)/edit_attendee/(?P<meeting_id>\d+)/(?P<username>[%+\.\w-]+)/$', 'organizer_edit_attendees'),
1763+ (r'^(?P<summit_name>[\w-]+)/review_meeting/(?P<meeting_id>\d+)/$',
1764+ 'meeting_review'),
1765+ (r'^(?P<summit_name>[\w-]+)/attend_meeting/(?P<meeting_id>\d+)/$',
1766+ 'attend_meeting'),
1767+ (r'^(?P<summit_name>[\w-]+)/edit_attendee/(?P<meeting_id>\d+)/(?P<username>[%+\.\w-]+)/$',
1768+ 'organizer_edit_attendees'),
1769 (r'^(?P<summit_name>[\w-]+)/create_meeting/$', 'create_meeting'),
1770- (r'^(?P<summit_name>[\w-]+)/edit_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'organizer_edit_meeting'),
1771- (r'^(?P<summit_name>[\w-]+)/confirm_del_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'delete_meeting_confirm'),
1772- (r'^(?P<summit_name>[\w-]+)/del_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'delete_meeting'),
1773+ (r'^(?P<summit_name>[\w-]+)/edit_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
1774+ 'organizer_edit_meeting'),
1775+ (r'^(?P<summit_name>[\w-]+)/hangout/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
1776+ 'edit_meeting_hangout'),
1777+ (r'^(?P<summit_name>[\w-]+)/confirm_del_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
1778+ 'delete_meeting_confirm'),
1779+ (r'^(?P<summit_name>[\w-]+)/del_mtg/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
1780+ 'delete_meeting'),
1781 (r'^(?P<summit_name>[\w-]+)/deleted/$', 'delete_confirmed'),
1782- (r'^(?P<summit_name>[\w-]+)/attendee_review/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'attendee_review'),
1783+ (r'^(?P<summit_name>[\w-]+)/attendee_review/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
1784+ 'attendee_review'),
1785 (r'^(?P<summit_name>[\w-]+)/tracks$', 'tracks'),
1786 (r'^(?P<summit_name>[\w-]+)/next$', 'next_session'),
1787 (r'^(?P<summit_name>[\w-]+)/next_table$', 'next_table'),
1788- (r'^(?P<summit_name>[\w-]+)/(?P<username>[%+\.\w-]+)/meetings$', 'created_meetings'),
1789+ (r'^(?P<summit_name>[\w-]+)/(?P<username>[%+\.\w-]+)/meetings$',
1790+ 'created_meetings'),
1791 (r'^(?P<summit_name>[\w-]+)/(?P<date>[\d-]+)/$', 'daily_schedule'),
1792 (r'^(?P<summit_name>[\w-]+)/(?P<date>[\d-]+)/display$', 'by_date'),
1793 (r'^(?P<summit_name>[\w-]+)/(?P<room_name>[%+\.\w-]+)/$', 'by_room'),
1794- (r'^(?P<summit_name>[\w-]+)/track/(?P<track_slug>[%+\.\w-]+)/$', 'by_track'),
1795- (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/\+share$', 'share_meeting'),
1796- (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/\+register', 'register'),
1797- (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/\+unregister', 'unregister'),
1798- (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$', 'meeting'),
1799- (r'^(?P<summit_name>[\w-]+)/private/(?P<private_key>[0-9a-f]{32})/(?P<meeting_slug>[%+\.\w-]+)/$', 'private_meeting'),
1800- (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/copy/$', 'meeting_copy'),
1801+ (r'^(?P<summit_name>[\w-]+)/track/(?P<track_slug>[%+\.\w-]+)/$',
1802+ 'by_track'),
1803+ (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/\+share$',
1804+ 'share_meeting'),
1805+ (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/\+register',
1806+ 'register'),
1807+ (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/\+unregister',
1808+ 'unregister'),
1809+ (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
1810+ 'meeting'),
1811+ (r'^(?P<summit_name>[\w-]+)/private/(?P<private_key>[0-9a-f]{32})/(?P<meeting_slug>[%+\.\w-]+)/$',
1812+ 'private_meeting'),
1813+ (r'^(?P<summit_name>[\w-]+)/meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/copy/$',
1814+ 'meeting_copy'),
1815 (r'^(?P<summit_name>[\w-]+)\.csv$', 'csv'),
1816 (r'^(?P<summit_name>[\w-]+)\.ical$', 'ical'),
1817- (r'^(?P<summit_name>[\w-]+)/participant/(?P<username>[%+\.\w-]+)/$', 'by_participant'),
1818- (r'^(?P<summit_name>[\w-]+)/participant/my_schedule_(?P<secret_key>[0-9a-f]{32})\.ical$', 'user_private_ical'),
1819- (r'^(?P<summit_name>[\w-]+)/participant/(?P<username>[%+\.\w-]+)\.ical$', 'user_ical'),
1820- (r'^(?P<summit_name>[\w-]+)/room/(?P<room_name>[%+\.\w-]+).ical$', 'room_ical'),
1821- (r'^(?P<summit_name>[\w-]+)/track/(?P<track_slug>[%+\.\w-]+).ical$', 'track_ical'),
1822+ (r'^(?P<summit_name>[\w-]+)/participant/(?P<username>[%+\.\w-]+)/$',
1823+ 'by_participant'),
1824+ (r'^(?P<summit_name>[\w-]+)/participant/my_schedule_(?P<secret_key>[0-9a-f]{32})\.ical$',
1825+ 'user_private_ical'),
1826+ (r'^(?P<summit_name>[\w-]+)/participant/(?P<username>[%+\.\w-]+)\.ical$',
1827+ 'user_ical'),
1828+ (r'^(?P<summit_name>[\w-]+)/room/(?P<room_name>[%+\.\w-]+).ical$',
1829+ 'room_ical'),
1830+ (r'^(?P<summit_name>[\w-]+)/track/(?P<track_slug>[%+\.\w-]+).ical$',
1831+ 'track_ical'),
1832 )
1833
1834 if settings.DEBUG or settings.SERVE_STATIC:
1835- urlpatterns += patterns('',
1836+ urlpatterns += patterns(
1837+ '',
1838 (r'^media/(?P<path>.*)$', 'django.views.static.serve',
1839 {'document_root': settings.MEDIA_ROOT}),
1840 (r'^(robots.txt)$', 'django.views.static.serve',

Subscribers

People subscribed via source and target branches