Merge lp:~danilo/summit/private-attendees into lp:summit

Proposed by Данило Шеган
Status: Merged
Approved by: Chris Johnston
Approved revision: 271
Merged at revision: 271
Proposed branch: lp:~danilo/summit/private-attendees
Merge into: lp:summit
Diff against target: 155 lines (+89/-14)
5 files modified
summit/schedule/forms.py (+73/-10)
summit/schedule/templates/schedule/create_private.html (+7/-0)
summit/schedule/templates/schedule/edit_private.html (+7/-0)
summit/schedule/tests.py (+1/-2)
summit/schedule/views.py (+1/-2)
To merge this branch: bzr merge lp:~danilo/summit/private-attendees
Reviewer Review Type Date Requested Status
Chris Johnston Approve
Review via email: mp+90183@code.launchpad.net

Commit message

Makes it possible for the creator of a private meeting to add required participants.

Description of the change

WARNING: no tests due to time being limited!

Add ability to private meetings page to add attendees directly.

It turns out formsets do not really support dealing with many-to-many relations, so I turned back to the approach I planned from the get-go: override save() method to take special consideration for the 'participants' field.

For better usability, I am also using multiple-checkboxes widget instead of multi-select box, because it allows at least easy searching using one's browser's built-in search in a long list of ~200 registered people.

We should definitely display meeting attendants on the private meeting page as well, but I'd rather do that as a separate branch.

To post a comment you must log in.
Revision history for this message
Chris Johnston (cjohnston) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'summit/schedule/forms.py'
--- summit/schedule/forms.py 2012-01-23 01:18:55 +0000
+++ summit/schedule/forms.py 2012-01-25 18:44:24 +0000
@@ -27,13 +27,76 @@
2727
28from summit.schedule.models.meetingmodel import Meeting28from summit.schedule.models.meetingmodel import Meeting
29from summit.schedule.models.attendeemodel import Attendee29from summit.schedule.models.attendeemodel import Attendee
3030from summit.schedule.models.participantmodel import Participant
31class CreatePrivateMeeting(forms.ModelForm):31
32 class Meta:32
33 model = Meeting33class MultipleAttendeeField(forms.ModelMultipleChoiceField):
34 fields = ('name', 'title', 'description', 'spec_url', 'wiki_url', 'pad_url', 'requires_dial_in')34 def label_from_instance(self, obj):
3535 return u"%s %s (%s)" % (
36class EditPrivateMeeting(forms.ModelForm):36 obj.user.first_name, obj.user.last_name, obj.user.username)
37 class Meta:37
38 model = Meeting38
39 fields = ('title', 'description', 'spec_url', 'wiki_url', 'pad_url', 'requires_dial_in')39class PrivateMeetingFormBase(forms.ModelForm):
40 participants = MultipleAttendeeField(
41 queryset=Attendee.objects.all,
42 widget=forms.CheckboxSelectMultiple)
43
44 def __init__(self, *args, **kwargs):
45 if 'instance' in kwargs:
46 if kwargs['instance'].pk is not None:
47 # We get the 'initial' keyword argument or initialize it
48 # as a dict if it didn't exist.
49 initial = kwargs.setdefault('initial', {})
50 # The widget for a ModelMultipleChoiceField expects
51 # a list of primary key for the selected data.
52 initial['participants'] = [
53 attendee.pk
54 for attendee in kwargs['instance'].participants.all()]
55
56 super(PrivateMeetingFormBase, self).__init__(*args, **kwargs)
57
58 summit = self.instance.summit
59 self.fields['participants'].queryset = Attendee.objects.filter(
60 summit=summit).order_by('user__first_name',
61 'user__last_name',
62 'user__username')
63
64 def save(self, commit=True):
65 instance = super(PrivateMeetingFormBase, self).save(commit)
66
67 # Prepare a 'save_m2m' method for the form,
68 if 'save_m2m' in dir(self):
69 old_save_m2m = self.save_m2m
70 else:
71 old_save_m2m = None
72 def save_m2m():
73 if old_save_m2m is not None:
74 old_save_m2m()
75 # This is where we actually link the pizza with toppings
76 instance.participants.clear()
77 for participant in self.cleaned_data['participants']:
78 record = Participant(meeting=instance, attendee=participant,
79 required=True)
80 record.save()
81 self.save_m2m = save_m2m
82
83 # Do we need to save all changes now?
84 if commit:
85 instance.save()
86 self.save_m2m()
87
88 return instance
89
90
91class CreatePrivateMeeting(PrivateMeetingFormBase):
92 class Meta:
93 model = Meeting
94 fields = ('name', 'title', 'description', 'spec_url', 'wiki_url',
95 'pad_url', 'requires_dial_in')
96
97
98class EditPrivateMeeting(PrivateMeetingFormBase):
99 class Meta:
100 model = Meeting
101 fields = ('title', 'description', 'spec_url', 'wiki_url', 'pad_url',
102 'requires_dial_in')
40103
=== modified file 'summit/schedule/templates/schedule/create_private.html'
--- summit/schedule/templates/schedule/create_private.html 2012-01-23 01:18:55 +0000
+++ summit/schedule/templates/schedule/create_private.html 2012-01-25 18:44:24 +0000
@@ -8,6 +8,13 @@
8 $('span[rel*=help]').colorTip({color:'orange'});8 $('span[rel*=help]').colorTip({color:'orange'});
9});9});
10--></script>10--></script>
11<style>
12ul {
13 height: 12em;
14 overflow-y: scroll;
15 overflow-x: hidden;
16}
17</style>
11{% endblock %}18{% endblock %}
1219
1320
1421
=== modified file 'summit/schedule/templates/schedule/edit_private.html'
--- summit/schedule/templates/schedule/edit_private.html 2012-01-23 01:18:55 +0000
+++ summit/schedule/templates/schedule/edit_private.html 2012-01-25 18:44:24 +0000
@@ -8,6 +8,13 @@
8 $('span[rel*=help]').colorTip({color:'orange'});8 $('span[rel*=help]').colorTip({color:'orange'});
9});9});
10--></script>10--></script>
11<style>
12ul {
13 height: 12em;
14 overflow-y: scroll;
15 overflow-x: hidden;
16}
17</style>
11{% endblock %}18{% endblock %}
1219
1320
1421
=== modified file 'summit/schedule/tests.py'
--- summit/schedule/tests.py 2012-01-25 02:53:03 +0000
+++ summit/schedule/tests.py 2012-01-25 18:44:24 +0000
@@ -1516,8 +1516,7 @@
1516 # To avoid test being fragile and arbitrarily dependent on the1516 # To avoid test being fragile and arbitrarily dependent on the
1517 # room order, we check the returned schedule.meetings bit-by-bit.1517 # room order, we check the returned schedule.meetings bit-by-bit.
1518 self.assertEqual([slot], schedule.meetings.keys())1518 self.assertEqual([slot], schedule.meetings.keys())
1519 self.assertEqual(set([(room1, None)]),1519 self.assertEqual(1, len(set(schedule.meetings[slot])))
1520 set(schedule.meetings[slot]))
15211520
15221521
1523class LaunchpadExportNode(dict):1522class LaunchpadExportNode(dict):
15241523
=== modified file 'summit/schedule/views.py'
--- summit/schedule/views.py 2012-01-24 05:06:04 +0000
+++ summit/schedule/views.py 2012-01-25 18:44:24 +0000
@@ -21,10 +21,9 @@
21from django.contrib.auth import logout21from django.contrib.auth import logout
22from django.contrib.auth.decorators import login_required, permission_required22from django.contrib.auth.decorators import login_required, permission_required
23from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned23from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
24from django.http import HttpResponse, HttpResponseRedirect24from django.http import Http404, HttpResponse, HttpResponseRedirect
25from django.shortcuts import render_to_response, get_object_or_40425from django.shortcuts import render_to_response, get_object_or_404
26from django.template import RequestContext26from django.template import RequestContext
27from django.http import Http404
28from django.core.urlresolvers import reverse27from django.core.urlresolvers import reverse
29from django.utils.datastructures import SortedDict28from django.utils.datastructures import SortedDict
3029

Subscribers

People subscribed via source and target branches