Merge lp:~cjohnston/summit/quick-links into lp:summit

Proposed by Chris Johnston
Status: Superseded
Proposed branch: lp:~cjohnston/summit/quick-links
Merge into: lp:summit
Diff against target: 744 lines (+594/-12)
13 files modified
EXTERNALS (+7/-0)
summit/common/widgets.py (+111/-0)
summit/media/css/style.css (+44/-0)
summit/media/js/events-ui.js (+11/-0)
summit/schedule/forms.py (+40/-0)
summit/schedule/templates/schedule/actions.html (+8/-3)
summit/schedule/templates/schedule/form.html (+47/-0)
summit/schedule/templates/schedule/summit.html (+3/-7)
summit/schedule/tests/__init__.py (+1/-0)
summit/schedule/tests/registration.py (+272/-0)
summit/schedule/views.py (+44/-1)
summit/settings.py (+1/-1)
summit/urls.py (+5/-0)
To merge this branch: bzr merge lp:~cjohnston/summit/quick-links
Reviewer Review Type Date Requested Status
Summit Hackers Pending
Review via email: mp+157550@code.launchpad.net

This proposal has been superseded by a proposal from 2013-04-07.

Commit message

Does some work on the actions area

To post a comment you must log in.
lp:~cjohnston/summit/quick-links updated
521. By Chris Johnston

Update from other branches

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'EXTERNALS'
2--- EXTERNALS 2012-04-22 20:20:10 +0000
3+++ EXTERNALS 2013-04-07 16:28:22 +0000
4@@ -19,3 +19,10 @@
5
6 - Twitter JS
7 http://twitter.com/javascripts/blogger.js
8+
9+- Date Picker
10+provided by the JQuery UI project. See http://jqueryui.com/
11+
12+- DateTimeWidget inspired by:
13+http://copiesofcopies.org/webl/2010/04/26/a-better-datetime-widget-for-django/
14+
15
16=== added file 'summit/common/widgets.py'
17--- summit/common/widgets.py 1970-01-01 00:00:00 +0000
18+++ summit/common/widgets.py 2013-04-07 16:28:22 +0000
19@@ -0,0 +1,111 @@
20+# -*- coding: utf-8 -*-
21+from datetime import time
22+from time import strptime, strftime
23+
24+from django import forms
25+
26+
27+class DateWidget(forms.DateInput):
28+ """
29+ A more-friendly date widget with a pop-up calendar.
30+ """
31+ def __init__(self, attrs=None):
32+ self.date_class = 'datepicker'
33+ if not attrs:
34+ attrs = {}
35+ if 'date_class' in attrs:
36+ self.date_class = attrs.pop('date_class')
37+ if 'class' not in attrs:
38+ attrs['class'] = 'date'
39+
40+ super(DateWidget, self).__init__(attrs=attrs)
41+
42+ def render(self, name, value, attrs=None):
43+ return '<span class="%s">%s</span>' % (
44+ self.date_class,
45+ super(DateWidget, self).render(name, value, attrs)
46+ )
47+
48+
49+class TimeWidget(forms.MultiWidget):
50+ """
51+ A more-friendly time widget.
52+ """
53+ def __init__(self, attrs=None):
54+ self.time_class = 'timepicker'
55+ if not attrs:
56+ attrs = {}
57+ if 'time_class' in attrs:
58+ self.time_class = attrs.pop('time_class')
59+ if 'class' not in attrs:
60+ attrs['class'] = 'time'
61+
62+ widgets = (
63+ forms.Select(
64+ attrs=attrs,
65+ choices=[(i + 1, "%02d" % (i + 1)) for i in range(0, 12)],
66+ ),
67+ forms.Select(
68+ attrs=attrs,
69+ choices=[(i, "%02d" % i) for i in range(00, 60, 15)],
70+ ),
71+ forms.Select(
72+ attrs=attrs,
73+ choices=[('AM', 'AM'), ('PM', 'PM')],
74+ )
75+ )
76+
77+ super(TimeWidget, self).__init__(widgets, attrs)
78+
79+ def decompress(self, value):
80+ if isinstance(value, time):
81+ hour = int(value.strftime("%I"))
82+ minute = int(value.strftime("%M"))
83+ meridian = value.strftime("%p")
84+ return (hour, minute, meridian)
85+ return (None, None, None)
86+
87+ def value_from_datadict(self, data, files, name):
88+ value = super(TimeWidget, self).value_from_datadict(data, files, name)
89+ t = strptime(
90+ "%02d:%02d %s" % (
91+ int(value[0]),
92+ int(value[1]),
93+ value[2]
94+ ),
95+ "%I:%M %p",
96+ )
97+ return strftime("%H:%M:%S", t)
98+
99+ def format_output(self, rendered_widgets):
100+ return '<span class="%s">%s%s%s</span>' % (
101+ self.time_class,
102+ rendered_widgets[0], rendered_widgets[1], rendered_widgets[2]
103+ )
104+
105+
106+class DateTimeWidget(forms.SplitDateTimeWidget):
107+ """
108+ A more-friendly date/time widget.
109+
110+ Inspired by:
111+
112+ http://copiesofcopies.org/webl/2010/04/26/a-better-datetime-widget-for-django/
113+ """
114+ def __init__(self, attrs=None, date_format=None, time_format=None):
115+ super(DateTimeWidget, self).__init__(attrs, date_format, time_format)
116+ self.widgets = (
117+ DateWidget(attrs=attrs),
118+ TimeWidget(attrs=attrs),
119+ )
120+
121+ def decompress(self, value):
122+ if value:
123+ d = strftime("%Y-%m-%d", value.timetuple())
124+ t = strftime("%I:%M %p", value.timetuple())
125+ return (d, t)
126+ else:
127+ return (None, None)
128+
129+ def format_output(self, rendered_widgets):
130+ return '%s%s' % (rendered_widgets[0], rendered_widgets[1])
131
132=== modified file 'summit/media/css/style.css'
133--- summit/media/css/style.css 2012-01-22 18:36:40 +0000
134+++ summit/media/css/style.css 2013-04-07 16:28:22 +0000
135@@ -66,3 +66,47 @@
136 .summit-columns ul li h3 a:hover { text-decoration: underline; }
137 .summit-columns ul li img { padding: 10px 0 5px; }
138 .summit-columns p { margin-bottom: 5px; }
139+
140+#id_start_utc_0, #id_start_utc_1,
141+#id_end_utc_0, #id_end_utc_1,
142+#id_start_utc_1_0, #id_start_utc_1_1, #id_start_utc_1_2,
143+#id_end_utc_1_0, #id_end_utc_1_1, #id_end_utc_1_2 {
144+ width: 100px;
145+ display: inline;
146+}
147+
148+#id_start_utc_1_0, #id_start_utc_1_1, #id_start_utc_1_2,
149+#id_end_utc_1_0, #id_end_utc_1_1, #id_end_utc_1_2 {
150+ width: 60px;
151+}
152+
153+#id_name, #id_announce, #id_registration {
154+ width: 350px;
155+}
156+
157+.link-cta {
158+ margin-top: 10px;
159+ padding: 10px;
160+ background: url('../img/background-cta.png') center 0 repeat-x #dd4814;
161+ display: block;
162+ float: left;
163+ color: #fff !important;
164+ -moz-border-radius: 4px;
165+ -webkit-border-radius: 4px;
166+ border-radius: 4px;
167+}
168+
169+.link-cta + p {
170+ margin: 18px 0 0 10px;
171+ float: left;
172+}
173+
174+.link-cta.disabled {
175+ background-image: none;
176+ background-color: #aea79f !important;
177+ cursor: not-allowed;
178+}
179+
180+.link-arrow:after {
181+ content: " ›";
182+}
183
184=== added file 'summit/media/js/events-ui.js'
185--- summit/media/js/events-ui.js 1970-01-01 00:00:00 +0000
186+++ summit/media/js/events-ui.js 2013-04-07 16:28:22 +0000
187@@ -0,0 +1,11 @@
188+$(document).ready(function(){
189+
190+ $.datepicker.setDefaults({
191+ showOn: 'focus',
192+ dateFormat: 'yy-mm-dd',
193+ });
194+
195+ $("#id_start_utc_0").datepicker();
196+ $("#id_end_utc_0").datepicker();
197+
198+});
199
200=== modified file 'summit/schedule/forms.py'
201--- summit/schedule/forms.py 2013-03-09 05:14:19 +0000
202+++ summit/schedule/forms.py 2013-04-07 16:28:22 +0000
203@@ -14,6 +14,7 @@
204 # You should have received a copy of the GNU Affero General Public License
205 # along with this program. If not, see <http://www.gnu.org/licenses/>.
206
207+from django.conf import settings
208 from django import forms
209
210 from summit.schedule.models.meetingmodel import Meeting
211@@ -21,6 +22,7 @@
212 from summit.schedule.models.participantmodel import Participant
213
214 from common.forms import RenderableMixin
215+from common.widgets import DateTimeWidget
216
217
218 class MultipleAttendeeField(forms.ModelMultipleChoiceField):
219@@ -226,3 +228,41 @@
220 fields = ('hangout_url', 'broadcast_url')
221
222 broadcast_url = YouTubeEmbedURL(label='Broadcast URL')
223+
224+
225+class Registration(forms.ModelForm, RenderableMixin):
226+ class Media:
227+ css = {'all': (
228+ '//code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css',
229+ )}
230+ js = (
231+ '//code.jquery.com/ui/1.10.2/jquery-ui.js',
232+ settings.MEDIA_URL + 'js/events-ui.js',
233+ )
234+
235+ class Meta:
236+ model = Attendee
237+ fields = (
238+ 'start_utc',
239+ 'end_utc',
240+ 'crew',
241+ )
242+
243+ def __init__(self, *args, **kargs):
244+ super(Registration, self).__init__(*args, **kargs)
245+ self.fields['start_utc'].widget = DateTimeWidget()
246+ self.fields['end_utc'].widget = DateTimeWidget()
247+
248+ def clean(self):
249+ begin = self.cleaned_data.get('start_utc')
250+ end = self.cleaned_data.get('end_utc')
251+ if begin and end and begin > end:
252+ raise forms.ValidationError(
253+ "Availability can not end before it starts."
254+ )
255+ return self.cleaned_data
256+
257+ def save(self, commit=True):
258+ instance = super(Registration, self).save(commit)
259+ instance.from_launchpad=False
260+ instance.save()
261
262=== modified file 'summit/schedule/templates/schedule/actions.html'
263--- summit/schedule/templates/schedule/actions.html 2012-08-08 15:10:25 +0000
264+++ summit/schedule/templates/schedule/actions.html 2013-04-07 16:28:22 +0000
265@@ -1,9 +1,10 @@
266 {% load schedule_perms %}
267
268 {% ifnotequal summit.state "public" %}
269-<div class="action-links">
270- <p style="font-size: 16px; font-weight: bold;">Actions</p>
271- <ul>
272+<div class="box box-padded">
273+ <h3>Quick Links</h3>
274+ <div>
275+ <ul class="list">
276
277 {% ifchangeschedule summit attendee %}
278 {% if schedule.date %}
279@@ -43,7 +44,11 @@
280 {% endif %}
281 {% endifequal %}
282
283+{% if attendee %}
284+ <li><a href="{% url registration summit.name %}">Update registration</a></li>
285+{% endif %}
286 </ul>
287 </div>
288+</div>
289
290 {% endifnotequal %}
291
292=== added file 'summit/schedule/templates/schedule/form.html'
293--- summit/schedule/templates/schedule/form.html 1970-01-01 00:00:00 +0000
294+++ summit/schedule/templates/schedule/form.html 2013-04-07 16:28:22 +0000
295@@ -0,0 +1,47 @@
296+{% extends "base.html" %}
297+
298+{% block page_name %}{{ form_title }} - {{ summit.title }}{%endblock %}
299+{% block sub_nav %}{% endblock %}
300+
301+{% block extrahead %}{{ block.super }}
302+{{ form.media }}
303+<script type="text/javascript" src="{{MEDIA_URL}}js/colortip-1.0-jquery.js"></script>
304+ <link rel="stylesheet" type="text/css" href="{{MEDIA_URL}}css/colortip-1.0-jquery.css"/>
305+{% endblock %}
306+
307+{% block closure %}
308+<script type="text/javascript"><!--
309+$(document).ready(function(){
310+ $('span[rel*=help]').colorTip({color:'orange'});
311+});
312+--></script>
313+<style>
314+form ul {
315+ height: 12em;
316+ overflow-y: scroll;
317+ overflow-x: hidden;
318+}
319+</style>
320+{% endblock %}
321+
322+
323+{% block content %}
324+<div class="row">
325+ <article id="form" class="span-8">
326+ {% if form.errors %}
327+ <p style="color: red;">
328+ Please correct the error{{ form.errors|pluralize }} below.
329+ </p>
330+ {% endif %}
331+
332+ <form action="{{ request.path_info }}" method="POST">{% csrf_token %}
333+ <fieldset>
334+ <h3>{{ form_title }}</h3>
335+ {{ form.as_template }}
336+ {% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %}
337+ <input type="submit" name="submit" value="Create" class="submit-button" />
338+ </fieldset>
339+ </form>
340+ </article>
341+</div>
342+{% endblock %}
343
344=== modified file 'summit/schedule/templates/schedule/summit.html'
345--- summit/schedule/templates/schedule/summit.html 2013-03-20 02:00:45 +0000
346+++ summit/schedule/templates/schedule/summit.html 2013-04-07 16:28:22 +0000
347@@ -38,19 +38,15 @@
348 <div class="row">
349 <section class="span-8">
350 {% if attendee %}
351- <p>You are attending, you can update the days and times of your attendance <ins></ins>
352- <a class="launchpad" href="http://launchpad.net/sprints/{{ summit.name }}/+attend"><img src="/media/img/gem-sm.png" /> Launchpad</a>.
353+ <p>You are registered as attending {{ summit.title }}. <a href="{% url registration summit %}">Update registration</a>.
354 </p>
355 <p>Download your
356 <a href="/{{ summit.name }}/participant/my_schedule_{{ attendee.secret_key }}.ical">Participation Schedule</a> to import into your Calendar.
357 </p>
358 {% else %}
359 {% if request.user.is_authenticated %}
360- <p><strong>You are not registered as attending.</strong></p>
361- <p>You can register your attendance in
362- <a class="launchpad" href="http://launchpad.net/sprints/{{ summit.name }}/+attend"><img src="/media/img/gem-sm.png" /> Launchpad</a>.
363- If you have recently done so, wait a few minutes and reload this page.
364- </p>
365+ <p><strong>You have not registered in Summit.</strong></p>
366+ <p><a class="link-cta" href="{% url registration summit %}">Register in Summit</a></p>
367 {% else %}
368 <p><strong>You are not logged in.</strong></p>
369 <p><a href="/openid/login?next={{login_next}}">Log in now</a></p>
370
371=== modified file 'summit/schedule/tests/__init__.py'
372--- summit/schedule/tests/__init__.py 2013-03-14 20:52:12 +0000
373+++ summit/schedule/tests/__init__.py 2013-04-07 16:28:22 +0000
374@@ -31,3 +31,4 @@
375 from schedule import *
376 from summit_model import *
377 from propose_meeting import *
378+from registration import RegistrationTestCase
379
380=== added file 'summit/schedule/tests/registration.py'
381--- summit/schedule/tests/registration.py 1970-01-01 00:00:00 +0000
382+++ summit/schedule/tests/registration.py 2013-04-07 16:28:22 +0000
383@@ -0,0 +1,272 @@
384+# The Summit Scheduler web application
385+# Copyright (C) 2008 - 2013 Ubuntu Community, Canonical Ltd
386+#
387+# This program is free software: you can redistribute it and/or modify
388+# it under the terms of the GNU Affero General Public License as
389+# published by the Free Software Foundation, either version 3 of the
390+# License, or (at your option) any later version.
391+#
392+# This program is distributed in the hope that it will be useful,
393+# but WITHOUT ANY WARRANTY; without even the implied warranty of
394+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
395+# GNU Affero General Public License for more details.
396+#
397+# You should have received a copy of the GNU Affero General Public License
398+# along with this program. If not, see <http://www.gnu.org/licenses/>.
399+
400+import datetime
401+
402+from django import test as djangotest
403+from django.core.urlresolvers import reverse
404+
405+from django.contrib.auth.models import User
406+from django.test.client import Client
407+
408+from model_mommy import mommy as factory
409+
410+from summit.schedule.models import (
411+ Summit,
412+ Attendee,
413+)
414+
415+
416+class RegistrationTestCase(djangotest.TestCase):
417+ """
418+ Tests for registering to attend a Summit
419+ """
420+ c = Client()
421+
422+ def setUp(self):
423+ self.now = datetime.datetime.utcnow()
424+ self.one_hour = datetime.timedelta(0, 3600)
425+ self.one_day = datetime.timedelta(days=1)
426+ self.week = datetime.timedelta(days=5)
427+ self.end_summit = self.now + self.week
428+ self.summit = factory.make_one(
429+ Summit,
430+ name='test-summit',
431+ title='Test Summit',
432+ virtual_summit=True,
433+ date_start=self.now,
434+ date_end=self.now + self.week,
435+ timezone='UTC',
436+ )
437+
438+ self.user1 = factory.make_one(
439+ User,
440+ username='testuser',
441+ first_name='Test',
442+ last_name='User',
443+ is_active=True,
444+ is_superuser=False,
445+ )
446+ self.user1.set_password('password')
447+ self.user1.save()
448+
449+ def create_attendee(self):
450+ self.attendee1 = factory.make_one(
451+ Attendee,
452+ summit=self.summit,
453+ user=self.user1,
454+ start_utc=self.now,
455+ end_utc=self.now+self.week
456+ )
457+
458+ def tearDown(self):
459+ self.client.logout()
460+
461+ def login(self):
462+ logged_in = self.c.login(
463+ username='testuser',
464+ password='password')
465+ self.assertTrue(logged_in)
466+
467+ def get_attendee(self):
468+ attendee = Attendee.objects.get(user=self.user1)
469+ return attendee
470+
471+ def view_summit_page(self):
472+ rev_args = [self.summit.name, ]
473+ response = self.c.get(
474+ reverse(
475+ 'summit.schedule.views.summit',
476+ args=rev_args
477+ )
478+ )
479+ self.assertEqual(response.status_code, 200)
480+ self.assertTemplateUsed(response, 'schedule/summit.html')
481+
482+ return response
483+
484+ def with_summit_registration_times(self):
485+ """
486+ Using the start and end of the summit as the registration times
487+ """
488+ self.start_date = self.now.strftime("%Y-%m-%d")
489+ self.start_hour = self.now.strftime("%I")
490+ self.start_minute = self.now.strftime("%M")
491+ self.start_period = self.now.strftime("%p")
492+ self.end_hour = self.end_summit.strftime("%I")
493+ self.end_minute = self.end_summit.strftime("%M")
494+ self.end_period = self.end_summit.strftime("%p")
495+ self.end_date = self.end_summit.strftime("%Y-%m-%d")
496+ self.edit_registration_form()
497+ attendee = self.get_attendee()
498+ self.assertEqual(
499+ attendee.start_utc.replace(second=0),
500+ self.now.replace(second=0, microsecond=0),
501+ )
502+ self.assertEqual(
503+ attendee.end_utc.replace(second=0, microsecond=0),
504+ self.end_summit.replace(second=0, microsecond=0),
505+ )
506+
507+ def with_custom_registration_times(self):
508+ """
509+ Using custom start and end registration times
510+ """
511+ start = self.now + self.one_day
512+ self.start_date = start.strftime("%Y-%m-%d")
513+ self.start_hour = self.now.strftime("%I")
514+ self.start_minute = self.now.strftime("%M")
515+ self.start_period = self.now.strftime("%p")
516+ self.end_hour = self.end_summit.strftime("%I")
517+ self.end_minute = self.end_summit.strftime("%M")
518+ self.end_period = self.end_summit.strftime("%p")
519+ self.end_date = self.end_summit.strftime("%Y-%m-%d")
520+ self.edit_registration_form()
521+ attendee = self.get_attendee()
522+ self.assertEqual(
523+ attendee.start_utc.replace(second=0),
524+ start.replace(second=0, microsecond=0),
525+ )
526+ self.assertEqual(
527+ attendee.end_utc.replace(second=0, microsecond=0),
528+ self.end_summit.replace(second=0, microsecond=0),
529+ )
530+
531+ def edit_registration_form(self):
532+ """
533+ Tests that a user can register for a Summit
534+ """
535+ # Define data to fill our the form
536+
537+ # Post the form
538+ post = self.c.post(
539+ reverse(
540+ 'registration',
541+ args=(self.summit.name,)
542+ ),
543+ data={
544+ 'end_utc_0': self.end_date,
545+ 'end_utc_1_0': self.end_hour,
546+ 'end_utc_1_1': self.end_minute,
547+ 'end_utc_1_2': self.end_period,
548+ 'start_utc_1_0': self.start_hour,
549+ 'start_utc_1_1': self.start_minute,
550+ 'start_utc_1_2': self.start_period,
551+ 'start_utc_0': self.start_date,
552+ }
553+ )
554+
555+ # A successful post should redirect to the summit page
556+ response = reverse(
557+ 'summit.schedule.views.summit',
558+ args=(self.summit.name,)
559+ )
560+ self.assertEqual(post.status_code, 302)
561+ self.assertRedirects(post, response)
562+ attendee = self.get_attendee()
563+ self.assertEqual(attendee.user, self.user1)
564+ self.assertEqual(attendee.from_launchpad, False)
565+
566+ def test_non_attendee_registers(self):
567+ self.login()
568+ self.assertRaises(Attendee.DoesNotExist, lambda: self.get_attendee())
569+ rev_args = [self.summit.name, ]
570+ response = self.c.get(reverse('registration', args=rev_args))
571+ self.assertEqual(response.status_code, 200)
572+ self.assertTemplateUsed(response, 'schedule/form.html')
573+ self.assertIn('Register for ' + self.summit.title, response.content)
574+ self.with_summit_registration_times()
575+
576+ def test_attendee_updates_registration(self):
577+ self.create_attendee()
578+ self.login()
579+ self.assertEquals(
580+ self.user1.username,
581+ self.get_attendee().user.username,
582+ )
583+ rev_args = [self.summit.name, ]
584+ response = self.c.get(reverse('registration', args=rev_args))
585+ self.assertEqual(response.status_code, 200)
586+ self.assertTemplateUsed(response, 'schedule/form.html')
587+ self.assertIn(
588+ 'Update registration for ' + self.summit.title,
589+ response.content
590+ )
591+ self.with_custom_registration_times()
592+
593+ def test_update_registration_from_launchpad_true(self):
594+ """
595+ update resgistration with from_launchpad=True
596+ to save from_launchpad=False
597+ """
598+ self.create_attendee()
599+ self.attendee1.from_launchpad = True
600+ self.attendee1.save()
601+ self.login()
602+ self.assertEquals(
603+ self.user1.username,
604+ self.get_attendee().user.username,
605+ )
606+ self.assertEquals(
607+ True,
608+ self.get_attendee().from_launchpad,
609+ )
610+ rev_args = [self.summit.name, ]
611+ response = self.c.get(reverse('registration', args=rev_args))
612+ self.assertEqual(response.status_code, 200)
613+ self.assertTemplateUsed(response, 'schedule/form.html')
614+ self.assertIn(
615+ 'Update registration for ' + self.summit.title,
616+ response.content
617+ )
618+ self.with_custom_registration_times()
619+
620+ def test_registered_view(self):
621+ """
622+ Test that when a user is already registered for the summit
623+ that they will see a link to update their registration
624+ """
625+ self.create_attendee()
626+ self.attendee1.from_launchpad = True
627+ self.attendee1.save()
628+ self.login()
629+ rev_args = [self.summit.name, ]
630+ response = self.view_summit_page()
631+ self.assertIn(
632+ reverse(
633+ 'registration',
634+ args=rev_args
635+ ),
636+ response.content
637+ )
638+ self.assertIn('Update registration', response.content)
639+
640+ def test_unregistered_view(self):
641+ """
642+ Test that when a user is not registered for the summit
643+ that they will see a button to register
644+ """
645+ self.login()
646+ rev_args = [self.summit.name, ]
647+ response = self.view_summit_page()
648+ self.assertIn(
649+ reverse(
650+ 'registration',
651+ args=rev_args
652+ ),
653+ response.content
654+ )
655+ self.assertIn('Register in Summit', response.content)
656
657=== modified file 'summit/schedule/views.py'
658--- summit/schedule/views.py 2013-03-15 01:06:10 +0000
659+++ summit/schedule/views.py 2013-04-07 16:28:22 +0000
660@@ -52,7 +52,8 @@
661 MeetingReview,
662 AttendMeeting,
663 OrganizerChangeAttend,
664- EditMeetingHangout
665+ EditMeetingHangout,
666+ Registration,
667 )
668
669 __all__ = (
670@@ -1173,3 +1174,45 @@
671 context,
672 RequestContext(request)
673 )
674+
675+
676+@login_required
677+@summit_required
678+def registration_form(request, summit, attendee):
679+ registration_args = dict()
680+
681+ if attendee is None:
682+ attendee = Attendee(
683+ user=request.user,
684+ summit=summit,
685+ from_launchpad=False,
686+ )
687+ registration_args['instance'] = attendee
688+ form_title="Register for %s" % summit.title
689+ else:
690+ registration_args['instance'] = attendee
691+ form_title="Update registration for %s" % summit.title
692+
693+ if request.method == 'POST':
694+ form = Registration(data=request.POST, **registration_args)
695+ if form.is_valid():
696+ form.save()
697+ return HttpResponseRedirect(
698+ reverse(
699+ 'summit.schedule.views.summit',
700+ args=(summit.name,)
701+ )
702+ )
703+ else:
704+ form = Registration(**registration_args)
705+
706+ context = {
707+ 'summit': summit,
708+ 'form': form,
709+ 'form_title': form_title,
710+ }
711+ return render_to_response(
712+ 'schedule/form.html',
713+ context,
714+ RequestContext(request)
715+ )
716
717=== modified file 'summit/settings.py'
718--- summit/settings.py 2013-04-04 02:13:03 +0000
719+++ summit/settings.py 2013-04-07 16:28:22 +0000
720@@ -167,7 +167,7 @@
721 'bzr_apps': ('http://bazaar.launchpad.net/~django-foundations-dev/ubuntu-django-foundations/bzr_apps', '7'),
722
723 ## ubuntu-website supplied templates and styles
724- 'ubuntu_website': ('http://bazaar.launchpad.net/~ubuntu-community-webthemes/ubuntu-community-webthemes/light-django-theme', '55'),
725+ 'ubuntu_website': ('http://bazaar.launchpad.net/~ubuntu-community-webthemes/ubuntu-community-webthemes/light-django-theme', '61'),
726
727 ## linaro-website supplied templates and styles
728 'linaro_website': ('http://bazaar.launchpad.net/~linaro-connect-theme-devs/ubuntu-community-webthemes/light-django-linaro-theme', '52'),
729
730=== modified file 'summit/urls.py'
731--- summit/urls.py 2013-02-26 19:31:21 +0000
732+++ summit/urls.py 2013-04-07 16:28:22 +0000
733@@ -68,6 +68,11 @@
734 (r'^(?P<summit_name>[\w-]+)/$', 'summit'),
735 (r'^(?P<summit_name>[\w-]+)/mobile/$', 'mobile'),
736 (r'^(?P<summit_name>[\w-]+)/search/$', 'search'),
737+ url(
738+ r'^(?P<summit_name>[\w-]+)/registration/$',
739+ 'registration_form',
740+ name='registration',
741+ ),
742 (r'^(?P<summit_name>[\w-]+)/propose_meeting/$', 'propose_meeting'),
743 (r'^(?P<summit_name>[\w-]+)/edit_meeting/(?P<meeting_id>\d+)/(?P<meeting_slug>[%+\.\w-]+)/$',
744 'edit_meeting'),

Subscribers

People subscribed via source and target branches