Merge lp:~mhall119/summit/menu-fixes into lp:~cjohnston/summit/menu-fixes
- menu-fixes
- Merge into menu-fixes
Proposed by
Chris Johnston
Status: | Merged |
---|---|
Merge reported by: | Chris Johnston |
Merged at revision: | not available |
Proposed branch: | lp:~mhall119/summit/menu-fixes |
Merge into: | lp:~cjohnston/summit/menu-fixes |
Diff against target: |
618 lines (+332/-32) (has conflicts) 9 files modified
summit/common/management/commands/lpupdate.py (+11/-2) summit/common/templatetags/menubuilder.py (+13/-0) summit/common/tests.py (+11/-0) summit/schedule/admin/meetingadmin.py (+1/-1) summit/schedule/management/commands/initslots.py (+14/-6) summit/schedule/migrations/0025_add_meeting_blueprint_id.py (+207/-0) summit/schedule/models/meetingmodel.py (+8/-0) summit/schedule/models/summitmodel.py (+32/-15) summit/schedule/tests.py (+35/-8) Text conflict in summit/common/templatetags/menubuilder.py Text conflict in summit/common/tests.py |
To merge this branch: | bzr merge lp:~mhall119/summit/menu-fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Johnston | Pending | ||
Review via email: mp+127885@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'summit/common/management/commands/lpupdate.py' |
2 | --- summit/common/management/commands/lpupdate.py 2012-02-25 00:13:45 +0000 |
3 | +++ summit/common/management/commands/lpupdate.py 2012-10-03 21:15:28 +0000 |
4 | @@ -17,6 +17,7 @@ |
5 | from django.core.management.base import BaseCommand, CommandError |
6 | |
7 | from summit.schedule.models import Summit |
8 | +from optparse import make_option |
9 | |
10 | __all__ = ( |
11 | 'Command', |
12 | @@ -24,16 +25,24 @@ |
13 | |
14 | |
15 | class Command(BaseCommand): |
16 | + option_list = BaseCommand.option_list + ( |
17 | + make_option("-s", "--slots", dest="slots", |
18 | + help="Number of slots an imported meeting needs", type=int, default=1), |
19 | + make_option("-A", "--no-attendees", dest="skip_attendees", action="store_true", |
20 | + help="Don't import Attendee data", default=False), |
21 | + make_option("-M", "--no-meetings", dest="skip_meetings", action="store_true", |
22 | + help="Don't import Meeting data", default=False), |
23 | + ) |
24 | |
25 | def handle(self, summit='', *args, **options): |
26 | if not summit: |
27 | for summit in Summit.objects.all(): |
28 | print "Updating %s" % summit |
29 | - summit.update_from_launchpad() |
30 | + summit.update_from_launchpad(options) |
31 | else: |
32 | try: |
33 | summit = Summit.objects.get(name=summit) |
34 | except Summit.DoesNotExist: |
35 | raise CommandError("Summit doesn't exist: %s" % summit) |
36 | print "Updating %s" % summit |
37 | - summit.update_from_launchpad() |
38 | + summit.update_from_launchpad(options) |
39 | |
40 | === modified file 'summit/common/templatetags/menubuilder.py' |
41 | --- summit/common/templatetags/menubuilder.py 2012-10-03 21:01:17 +0000 |
42 | +++ summit/common/templatetags/menubuilder.py 2012-10-03 21:15:28 +0000 |
43 | @@ -70,6 +70,7 @@ |
44 | menuitems = [] |
45 | |
46 | try: |
47 | +<<<<<<< TREE |
48 | menu = Menu.objects.get(slug=menu_name) |
49 | except Menu.DoesNotExist: |
50 | return [] |
51 | @@ -85,6 +86,18 @@ |
52 | |
53 | if cache_time >= 0 and not debug: |
54 | cache.set(cache_key, menuitems, cache_time) |
55 | +======= |
56 | + menu_instance = Menu.objects.get(slug=menu) |
57 | + base_path = menu_instance.base_url or '' |
58 | + for i in MenuItem.objects.filter(menu=menu_instance).order_by('order'): |
59 | + current = ( i.link_url != '/' and current_path == (base_path + i.link_url)) or ( i.link_url == '/' and current_path == '/' ) |
60 | + if not i.login_required or ( i.login_required and user.is_authenticated() ): |
61 | + menuitems.append({'url': i.link_url, 'title': i.title, 'current': current,}) |
62 | + except Menu.DoesNotExist: |
63 | + pass# No Menu by this name, fail gracefully |
64 | + except MenuItem.DoesNotExist: |
65 | + pass# No Menu by this name, fail gracefully |
66 | +>>>>>>> MERGE-SOURCE |
67 | return menuitems |
68 | |
69 | register.tag('menu', build_menu) |
70 | |
71 | === modified file 'summit/common/tests.py' |
72 | --- summit/common/tests.py 2012-10-03 21:01:17 +0000 |
73 | +++ summit/common/tests.py 2012-10-03 21:15:28 +0000 |
74 | @@ -44,6 +44,7 @@ |
75 | |
76 | def test_toplevel_menu_highlights(self): |
77 | schedule_page = self.client.get('/uds-test/') |
78 | +<<<<<<< TREE |
79 | print schedule_page.content |
80 | self.assertContains(schedule_page, |
81 | '<li class=\'active\' id="main-nav"><a class="main-nav-item" href="/uds-test/" title="Schedule">Schedule</a>', 1) |
82 | @@ -53,6 +54,16 @@ |
83 | '<li class=\'active\' id="main-nav"><a class="main-nav-item" href="/today/uds-test/" title="Today">Today</a>', 0) |
84 | self.assertContains(schedule_page, |
85 | '<li id="main-nav"><a class="main-nav-item" href="/today/uds-test/" title="Today">Today</a>', 1) |
86 | +======= |
87 | + self.assertContains(schedule_page, |
88 | + '<li class=\'active\' id="main-nav"><a class="main-nav-item" href="/uds-test/" title="Schedule">Schedule</a>', 1) |
89 | + self.assertContains(schedule_page, |
90 | + '<li id="main-nav"><a class="main-nav-item" href="/uds-test/" title="Schedule">Schedule</a>', 0) |
91 | + self.assertContains(schedule_page, |
92 | + '<li class=\'active\' id="main-nav"><a class="main-nav-item" href="/today/uds-test/" title="Today">Today</a>', 0) |
93 | + self.assertContains(schedule_page, |
94 | + '<li id="main-nav"><a class="main-nav-item" href="/today/uds-test/" title="Today">Today</a>', 1) |
95 | +>>>>>>> MERGE-SOURCE |
96 | |
97 | def test_sublevel_menu_highlights(self): |
98 | today_page = self.client.get('/today/uds-test/') |
99 | |
100 | === modified file 'summit/schedule/admin/meetingadmin.py' |
101 | --- summit/schedule/admin/meetingadmin.py 2012-05-16 14:59:59 +0000 |
102 | +++ summit/schedule/admin/meetingadmin.py 2012-10-03 21:15:28 +0000 |
103 | @@ -144,7 +144,7 @@ |
104 | 'type', 'tracks', 'requires_dial_in', 'video'), |
105 | }), |
106 | ("References", { |
107 | - 'fields': ('spec_url', 'wiki_url', 'pad_url'), |
108 | + 'fields': ('spec_url', 'launchpad_blueprint_id', 'wiki_url', 'pad_url'), |
109 | }), |
110 | ("Scheduling details", { |
111 | 'classes': ('collapse', ), |
112 | |
113 | === modified file 'summit/schedule/management/commands/initslots.py' |
114 | --- summit/schedule/management/commands/initslots.py 2012-03-08 22:19:17 +0000 |
115 | +++ summit/schedule/management/commands/initslots.py 2012-10-03 21:15:28 +0000 |
116 | @@ -58,6 +58,9 @@ |
117 | duration = datetime.timedelta(minutes=options["duration"]) |
118 | interval = datetime.timedelta(minutes=options["interval"]) |
119 | breaktime = datetime.timedelta(minutes=15) |
120 | + |
121 | + slots_per_hour = (60 * 60) / duration.seconds |
122 | + |
123 | try: |
124 | summit = Summit.objects.get(name=summit.__str__) |
125 | except Summit.DoesNotExist: |
126 | @@ -77,14 +80,19 @@ |
127 | # Determines the type of the session |
128 | if slottime.time() == lunch: |
129 | slot_type = 'lunch' |
130 | + slot_duration = datetime.timedelta(minutes=60) |
131 | + slot_count += (slots_per_hour - 1) |
132 | elif slottime.time() == plenary: |
133 | slot_type = 'plenary' |
134 | + slot_duration = datetime.timedelta(minutes=60) |
135 | + slot_count += (slots_per_hour - 1) |
136 | else: |
137 | slot_type = 'open' |
138 | - slot_length = duration |
139 | + slot_duration = duration |
140 | + slot_length = slot_duration |
141 | |
142 | # Morning Break |
143 | - if slot_count == 2: |
144 | + if slot_count == (2 * slots_per_hour): |
145 | slot, created = Slot.objects.get_or_create( |
146 | summit=summit, |
147 | start_utc=start_time + slot_length - breaktime, |
148 | @@ -93,7 +101,7 @@ |
149 | ) |
150 | slot_length = slot_length - breaktime |
151 | # Afternoon Break |
152 | - elif slot_count == 8: |
153 | + elif slot_count == (7 * slots_per_hour)+1: |
154 | slot, created = Slot.objects.get_or_create( |
155 | summit=summit, |
156 | start_utc=start_time, |
157 | @@ -105,10 +113,10 @@ |
158 | slottime = slottime + interval |
159 | # Non-break intervals |
160 | elif slot_type == 'open': |
161 | - nexthour = slottime + hour |
162 | + nexthour = slottime + duration |
163 | if nexthour.time() != lunch \ |
164 | and nexthour.time() != plenary \ |
165 | - and slot_count != 7: |
166 | + and slot_count != (7*slots_per_hour): |
167 | slot_length = slot_length - interval |
168 | |
169 | end_time = start_time + slot_length |
170 | @@ -120,7 +128,7 @@ |
171 | end_utc=end_time, |
172 | type=slot_type) |
173 | |
174 | - slottime = slottime + duration |
175 | + slottime = slottime + slot_duration |
176 | |
177 | date = date + day |
178 | print "Initializing slots complete." |
179 | |
180 | === added file 'summit/schedule/migrations/0025_add_meeting_blueprint_id.py' |
181 | --- summit/schedule/migrations/0025_add_meeting_blueprint_id.py 1970-01-01 00:00:00 +0000 |
182 | +++ summit/schedule/migrations/0025_add_meeting_blueprint_id.py 2012-10-03 21:15:28 +0000 |
183 | @@ -0,0 +1,207 @@ |
184 | +# encoding: utf-8 |
185 | +import datetime |
186 | +from south.db import db |
187 | +from south.v2 import SchemaMigration |
188 | +from django.db import models |
189 | + |
190 | +class Migration(SchemaMigration): |
191 | + |
192 | + def forwards(self, orm): |
193 | + |
194 | + # Adding field 'Meeting.launchpad_blueprint_id' |
195 | + db.add_column('schedule_meeting', 'launchpad_blueprint_id', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True), keep_default=False) |
196 | + |
197 | + |
198 | + def backwards(self, orm): |
199 | + |
200 | + # Deleting field 'Meeting.launchpad_blueprint_id' |
201 | + db.delete_column('schedule_meeting', 'launchpad_blueprint_id') |
202 | + |
203 | + |
204 | + models = { |
205 | + 'auth.group': { |
206 | + 'Meta': {'object_name': 'Group'}, |
207 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
208 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
209 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
210 | + }, |
211 | + 'auth.permission': { |
212 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
213 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
214 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
215 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
216 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
217 | + }, |
218 | + 'auth.user': { |
219 | + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, |
220 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
221 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
222 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
223 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
224 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
225 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
226 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
227 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
228 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
229 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
230 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
231 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
232 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
233 | + }, |
234 | + 'contenttypes.contenttype': { |
235 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
236 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
237 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
238 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
239 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
240 | + }, |
241 | + 'schedule.agenda': { |
242 | + 'Meta': {'ordering': "('slot', 'room')", 'unique_together': "(('slot', 'room'),)", 'object_name': 'Agenda'}, |
243 | + 'auto': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
244 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
245 | + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Meeting']"}), |
246 | + 'room': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Room']"}), |
247 | + 'slot': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Slot']"}) |
248 | + }, |
249 | + 'schedule.attendee': { |
250 | + 'Meta': {'ordering': "('user__username', 'summit')", 'object_name': 'Attendee'}, |
251 | + 'crew': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_column': "'crew'"}), |
252 | + 'end_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'end'"}), |
253 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
254 | + 'secret_key_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), |
255 | + 'start_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'start'"}), |
256 | + 'summit': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Summit']"}), |
257 | + 'tracks': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['schedule.Track']", 'symmetrical': 'False', 'blank': 'True'}), |
258 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) |
259 | + }, |
260 | + 'schedule.attendeebusy': { |
261 | + 'Meta': {'ordering': "('attendee', 'start_utc', 'end_utc')", 'object_name': 'AttendeeBusy'}, |
262 | + 'attendee': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'busy_set'", 'to': "orm['schedule.Attendee']"}), |
263 | + 'end_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'end'"}), |
264 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
265 | + 'start_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'start'"}) |
266 | + }, |
267 | + 'schedule.crew': { |
268 | + 'Meta': {'ordering': "('date_utc', 'attendee')", 'object_name': 'Crew'}, |
269 | + 'attendee': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'crew_schedule'", 'to': "orm['schedule.Attendee']"}), |
270 | + 'date_utc': ('django.db.models.fields.DateField', [], {'db_column': "'date'"}), |
271 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) |
272 | + }, |
273 | + 'schedule.lead': { |
274 | + 'Meta': {'ordering': "('summit', 'track')", 'object_name': 'Lead'}, |
275 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
276 | + 'lead': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'lead'", 'to': "orm['schedule.Attendee']"}), |
277 | + 'summit': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Summit']"}), |
278 | + 'track': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Track']"}) |
279 | + }, |
280 | + 'schedule.meeting': { |
281 | + 'Meta': {'object_name': 'Meeting'}, |
282 | + 'approved': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '10', 'null': 'True'}), |
283 | + 'approver': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'approver_set'", 'null': 'True', 'to': "orm['schedule.Attendee']"}), |
284 | + 'assignee': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'assignee_set'", 'null': 'True', 'to': "orm['schedule.Attendee']"}), |
285 | + 'description': ('django.db.models.fields.TextField', [], {'max_length': '2047', 'blank': 'True'}), |
286 | + 'drafter': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'drafter_set'", 'null': 'True', 'to': "orm['schedule.Attendee']"}), |
287 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
288 | + 'launchpad_blueprint_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
289 | + 'name': ('summit.schedule.fields.NameField', [], {'max_length': '100'}), |
290 | + 'override_break': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
291 | + 'pad_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), |
292 | + 'participants': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['schedule.Attendee']", 'symmetrical': 'False', 'through': "orm['schedule.Participant']", 'blank': 'True'}), |
293 | + 'priority': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
294 | + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
295 | + 'private_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), |
296 | + 'requires_dial_in': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
297 | + 'scribe': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'scribe_set'", 'null': 'True', 'to': "orm['schedule.Attendee']"}), |
298 | + 'slots': ('django.db.models.fields.IntegerField', [], {'default': '1'}), |
299 | + 'spec_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), |
300 | + 'status': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), |
301 | + 'summit': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Summit']"}), |
302 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
303 | + 'tracks': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['schedule.Track']", 'symmetrical': 'False', 'blank': 'True'}), |
304 | + 'type': ('django.db.models.fields.CharField', [], {'default': "u'discussion'", 'max_length': '15'}), |
305 | + 'video': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
306 | + 'wiki_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) |
307 | + }, |
308 | + 'schedule.participant': { |
309 | + 'Meta': {'ordering': "('meeting', 'attendee', 'participation')", 'object_name': 'Participant'}, |
310 | + 'attendee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Attendee']"}), |
311 | + 'from_launchpad': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
312 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
313 | + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Meeting']"}), |
314 | + 'participation': ('django.db.models.fields.CharField', [], {'default': "'ATTENDING'", 'max_length': '32', 'null': 'True'}) |
315 | + }, |
316 | + 'schedule.room': { |
317 | + 'Meta': {'ordering': "('summit', 'name')", 'object_name': 'Room'}, |
318 | + 'end_utc': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_column': "'end'", 'blank': 'True'}), |
319 | + 'has_dial_in': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
320 | + 'icecast_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), |
321 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
322 | + 'irc_channel': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), |
323 | + 'name': ('summit.schedule.fields.NameField', [], {'max_length': '50'}), |
324 | + 'size': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
325 | + 'start_utc': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_column': "'start'", 'blank': 'True'}), |
326 | + 'summit': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Summit']"}), |
327 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
328 | + 'tracks': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['schedule.Track']", 'symmetrical': 'False', 'blank': 'True'}), |
329 | + 'type': ('django.db.models.fields.CharField', [], {'default': "u'open'", 'max_length': '7'}) |
330 | + }, |
331 | + 'schedule.roombusy': { |
332 | + 'Meta': {'ordering': "('room', 'start_utc', 'end_utc')", 'object_name': 'RoomBusy'}, |
333 | + 'end_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'end'"}), |
334 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
335 | + 'room': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'busy_set'", 'to': "orm['schedule.Room']"}), |
336 | + 'start_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'start'"}) |
337 | + }, |
338 | + 'schedule.slot': { |
339 | + 'Meta': {'ordering': "('summit', 'start_utc', 'end_utc')", 'object_name': 'Slot'}, |
340 | + 'end_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'end'"}), |
341 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
342 | + 'start_utc': ('django.db.models.fields.DateTimeField', [], {'db_column': "'start'"}), |
343 | + 'summit': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Summit']"}), |
344 | + 'type': ('django.db.models.fields.CharField', [], {'default': "u'open'", 'max_length': '7'}) |
345 | + }, |
346 | + 'schedule.summit': { |
347 | + 'Meta': {'ordering': "('name',)", 'object_name': 'Summit'}, |
348 | + 'date_end': ('django.db.models.fields.DateField', [], {'null': 'True'}), |
349 | + 'date_start': ('django.db.models.fields.DateField', [], {'null': 'True'}), |
350 | + 'description': ('django.db.models.fields.TextField', [], {'max_length': '2047', 'blank': 'True'}), |
351 | + 'etherpad': ('django.db.models.fields.URLField', [], {'default': "'http://pad.ubuntu.com/'", 'max_length': '75'}), |
352 | + 'hashtag': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}), |
353 | + 'help_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), |
354 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
355 | + 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
356 | + 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), |
357 | + 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'managers'", 'blank': 'True', 'to': "orm['auth.User']"}), |
358 | + 'name': ('summit.schedule.fields.NameField', [], {'max_length': '50'}), |
359 | + 'qr': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}), |
360 | + 'schedulers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'schedulers'", 'blank': 'True', 'to': "orm['auth.User']"}), |
361 | + 'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False'}), |
362 | + 'state': ('django.db.models.fields.CharField', [], {'default': "u'sponsor'", 'max_length': '10'}), |
363 | + 'timezone': ('django.db.models.fields.CharField', [], {'max_length': '50'}), |
364 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
365 | + }, |
366 | + 'schedule.summitsprint': { |
367 | + 'Meta': {'ordering': "('summit', 'import_url')", 'object_name': 'SummitSprint'}, |
368 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
369 | + 'import_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), |
370 | + 'summit': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sprint_set'", 'to': "orm['schedule.Summit']"}) |
371 | + }, |
372 | + 'schedule.track': { |
373 | + 'Meta': {'ordering': "('summit', 'title', 'slug')", 'object_name': 'Track'}, |
374 | + 'allow_adjacent_sessions': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
375 | + 'color': ('django.db.models.fields.CharField', [], {'default': "'FFFFFF'", 'max_length': '6'}), |
376 | + 'description': ('django.db.models.fields.TextField', [], {'max_length': '1000', 'null': 'True'}), |
377 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
378 | + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}), |
379 | + 'summit': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Summit']"}), |
380 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
381 | + }, |
382 | + 'sites.site': { |
383 | + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, |
384 | + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
385 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
386 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
387 | + } |
388 | + } |
389 | + |
390 | + complete_apps = ['schedule'] |
391 | |
392 | === modified file 'summit/schedule/models/meetingmodel.py' |
393 | --- summit/schedule/models/meetingmodel.py 2012-07-14 20:19:27 +0000 |
394 | +++ summit/schedule/models/meetingmodel.py 2012-10-03 21:15:28 +0000 |
395 | @@ -74,6 +74,7 @@ |
396 | (u'PENDING', u'Pending'), |
397 | (u'APPROVED', u'Approved'), |
398 | (u'DECLINED', u'Declined'), |
399 | + (u'REMOVED', u'Removed'), |
400 | ) |
401 | |
402 | summit = models.ForeignKey(Summit) |
403 | @@ -118,6 +119,7 @@ |
404 | related_name='scribe_set') |
405 | participants = models.ManyToManyField(Attendee, blank=True, |
406 | through='Participant') |
407 | + launchpad_blueprint_id = models.IntegerField(blank=True, null=True) |
408 | |
409 | class Meta: |
410 | app_label = 'schedule' |
411 | @@ -296,6 +298,12 @@ |
412 | |
413 | self.approved = 'APPROVED' |
414 | |
415 | + name = elem.get("name") |
416 | + if name: |
417 | + self.name = name[:100] |
418 | + else: |
419 | + self.name = None |
420 | + |
421 | status = elem.get("status") |
422 | if status: |
423 | self.status = status |
424 | |
425 | === modified file 'summit/schedule/models/summitmodel.py' |
426 | --- summit/schedule/models/summitmodel.py 2012-08-09 15:53:51 +0000 |
427 | +++ summit/schedule/models/summitmodel.py 2012-10-03 21:15:28 +0000 |
428 | @@ -233,14 +233,16 @@ |
429 | % self.name)] |
430 | return urls |
431 | |
432 | - def update_from_launchpad_response(self, response): |
433 | + def update_from_launchpad_response(self, response, options={}): |
434 | meetings = set() |
435 | - for elem in response.find("attendees").findall("person"): |
436 | - self.update_attendee_from_launchpad(elem) |
437 | - for elem in response.find("unscheduled").findall("meeting"): |
438 | - meeting = self.update_meeting_from_launchpad(elem) |
439 | - if meeting is not None: |
440 | - meetings.add(meeting) |
441 | + if not options.get('skip_attendees', False): |
442 | + for elem in response.find("attendees").findall("person"): |
443 | + self.update_attendee_from_launchpad(elem, options) |
444 | + if not options.get('skip_meetings', False): |
445 | + for elem in response.find("unscheduled").findall("meeting"): |
446 | + meeting = self.update_meeting_from_launchpad(elem, options) |
447 | + if meeting is not None: |
448 | + meetings.add(meeting) |
449 | return meetings |
450 | |
451 | def _get_sprint_info_from_launchpad(self, url): |
452 | @@ -264,26 +266,33 @@ |
453 | sprint_info = ElementTree.parse(export) |
454 | return sprint_info |
455 | |
456 | - def update_from_launchpad(self): |
457 | + def update_from_launchpad(self, options={}): |
458 | """Update from Launchpad data.""" |
459 | in_lp = set() |
460 | urls = self.launchpad_sprint_import_urls() |
461 | for url in urls: |
462 | print "Importing from %s" % url |
463 | sprint_info = self._get_sprint_info_from_launchpad(url) |
464 | - in_lp |= self.update_from_launchpad_response(sprint_info) |
465 | - |
466 | + in_lp |= self.update_from_launchpad_response(sprint_info, options) |
467 | + |
468 | + in_db = set(m for m in self.meeting_set.exclude(launchpad_blueprint_id__isnull=True)) |
469 | + |
470 | + for extra in in_db.difference(in_lp): |
471 | + if not len(extra.agenda_set.all()): |
472 | + print "will delete %s" % extra.name |
473 | + extra.approved='REMOVED' |
474 | + extra.save() |
475 | self.last_update = datetime.utcnow() |
476 | self.save() |
477 | |
478 | - def update_attendee_from_launchpad(self, elem): |
479 | + def update_attendee_from_launchpad(self, elem, options={}): |
480 | """Update or create single attendee from Launchpad data.""" |
481 | + |
482 | username = elem.get("name", "") |
483 | if not username: |
484 | return |
485 | |
486 | print "user %s" % username |
487 | - |
488 | try: |
489 | attendee = self.attendee_set.get(user__username__exact=username[:30]) |
490 | except ObjectDoesNotExist: |
491 | @@ -298,10 +307,15 @@ |
492 | start=datetime.utcnow(), |
493 | end=datetime.utcnow()) |
494 | |
495 | + |
496 | attendee.update_from_launchpad(elem) |
497 | |
498 | - def update_meeting_from_launchpad(self, elem): |
499 | + def update_meeting_from_launchpad(self, elem, options={}): |
500 | """Update or create single meeting from Launchpad data.""" |
501 | + bp_id = elem.get("id", None) |
502 | + if not bp_id: |
503 | + return |
504 | + |
505 | full_name = elem.get("name", "") |
506 | if not full_name: |
507 | return |
508 | @@ -309,10 +323,13 @@ |
509 | |
510 | print "meeting %s" % name |
511 | meeting = "" |
512 | + |
513 | + slot_length = options.get('slots', 1) |
514 | + |
515 | try: |
516 | - meeting = self.meeting_set.get(name__exact=name) |
517 | + meeting = self.meeting_set.get(launchpad_blueprint_id=bp_id) |
518 | except ObjectDoesNotExist: |
519 | - meeting = self.meeting_set.create(name=name, title=full_name[:100]) |
520 | + meeting = self.meeting_set.create(name=name, title=full_name[:100], slots=slot_length, launchpad_blueprint_id=bp_id) |
521 | except: |
522 | pass |
523 | |
524 | |
525 | === modified file 'summit/schedule/tests.py' |
526 | --- summit/schedule/tests.py 2012-09-09 21:15:17 +0000 |
527 | +++ summit/schedule/tests.py 2012-10-03 21:15:28 +0000 |
528 | @@ -1667,7 +1667,7 @@ |
529 | |
530 | def test_update_meeting_trims_name(self): |
531 | summit = factory.make_one(Summit) |
532 | - elem = LaunchpadExportNode(name="very " * 20 + "longname") |
533 | + elem = LaunchpadExportNode(name="very " * 20 + "longname", id="42") |
534 | meeting = summit.update_meeting_from_launchpad(elem) |
535 | # Names are truncated at 100 chars. |
536 | expected_name = "very " * 20 |
537 | @@ -1678,7 +1678,7 @@ |
538 | summit = factory.make_one(Summit) |
539 | name = "meeting-name" |
540 | title = "other-title" |
541 | - elem = LaunchpadExportNode(name=name) |
542 | + elem = LaunchpadExportNode(name=name, id="42") |
543 | summit.meeting_set.create(name=name, title=title) |
544 | meeting = summit.update_meeting_from_launchpad(elem) |
545 | self.assertEqual(name, meeting.name) |
546 | @@ -1695,7 +1695,7 @@ |
547 | def test_update_from_launchpad_response_handles_no_name(self): |
548 | summit = factory.make_one(Summit) |
549 | elem = self.get_basic_launchpad_response() |
550 | - meeting_node = LaunchpadExportNode(name=None) |
551 | + meeting_node = LaunchpadExportNode(name=None, id="42") |
552 | elem.find("unscheduled").add_child("meeting", meeting_node) |
553 | meetings = summit.update_from_launchpad_response(elem) |
554 | self.assertEqual(set(), meetings) |
555 | @@ -1738,16 +1738,30 @@ |
556 | summit = factory.make_one(Summit) |
557 | def get_sprint_info(url): |
558 | elem = self.get_basic_launchpad_response() |
559 | - meeting_node = LaunchpadExportNode(name="foo") |
560 | + meeting_node = LaunchpadExportNode(name="foo", id="42") |
561 | elem.find("unscheduled").add_child("meeting", meeting_node) |
562 | return elem |
563 | summit._get_sprint_info_from_launchpad = get_sprint_info |
564 | summit.update_from_launchpad() |
565 | self.assertEqual(1, summit.meeting_set.all().count()) |
566 | |
567 | + def test_update_from_launchpad_does_renames(self): |
568 | + summit = factory.make_one(Summit) |
569 | + meeting = summit.meeting_set.create(name="name", launchpad_blueprint_id="42") |
570 | + def get_sprint_info(url): |
571 | + elem = self.get_basic_launchpad_response() |
572 | + meeting_node = LaunchpadExportNode(name="other", id="42") |
573 | + elem.find("unscheduled").add_child("meeting", meeting_node) |
574 | + return elem |
575 | + summit._get_sprint_info_from_launchpad = get_sprint_info |
576 | + summit.update_from_launchpad() |
577 | + # Since both had blueprint id 42, it should just update the existing meeting |
578 | + self.assertEqual(0, summit.meeting_set.filter(name__exact="name").count()) |
579 | + self.assertEqual(1, summit.meeting_set.filter(name__exact="other").count()) |
580 | + |
581 | def test_update_from_launchpad_deletes_unseen_meetings(self): |
582 | summit = factory.make_one(Summit) |
583 | - meeting = summit.meeting_set.create(spec_url='test_url', name="name") |
584 | + meeting = summit.meeting_set.create(spec_url='test_url', name="name", launchpad_blueprint_id="42") |
585 | def get_sprint_info(url): |
586 | elem = self.get_basic_launchpad_response() |
587 | meeting_node = LaunchpadExportNode(name="other") |
588 | @@ -1755,14 +1769,27 @@ |
589 | return elem |
590 | summit._get_sprint_info_from_launchpad = get_sprint_info |
591 | summit.update_from_launchpad() |
592 | - self.assertEqual(0, summit.meeting_set.filter(name__exact="name").count()) |
593 | + self.assertEqual(1, summit.meeting_set.filter(name__exact="name").count()) |
594 | + self.assertEqual(0, summit.meeting_set.filter(name__exact="name").exclude(approved='REMOVED').count()) |
595 | + |
596 | + def test_update_from_launchpad_doesnt_delete_meetings_with_spec_url(self): |
597 | + summit = factory.make_one(Summit) |
598 | + meeting = summit.meeting_set.create(spec_url='http://example.com/foo', name="name", launchpad_blueprint_id="42") |
599 | + def get_sprint_info(url): |
600 | + elem = self.get_basic_launchpad_response() |
601 | + meeting_node = LaunchpadExportNode(name="other", id="43") |
602 | + elem.find("unscheduled").add_child("meeting", meeting_node) |
603 | + return elem |
604 | + summit._get_sprint_info_from_launchpad = get_sprint_info |
605 | + summit.update_from_launchpad() |
606 | + self.assertEqual(1, summit.meeting_set.filter(name__exact="name").count()) |
607 | |
608 | def test_update_from_launchpad_doesnt_delete_meetings_with_no_spec_url(self): |
609 | summit = factory.make_one(Summit) |
610 | - meeting = summit.meeting_set.create(spec_url='', name="name") |
611 | + meeting = summit.meeting_set.create(spec_url='', name="name", launchpad_blueprint_id="42") |
612 | def get_sprint_info(url): |
613 | elem = self.get_basic_launchpad_response() |
614 | - meeting_node = LaunchpadExportNode(name="other") |
615 | + meeting_node = LaunchpadExportNode(name="other", id="43") |
616 | elem.find("unscheduled").add_child("meeting", meeting_node) |
617 | return elem |
618 | summit._get_sprint_info_from_launchpad = get_sprint_info |