Merge pull request #62 from codersquid/json_endpoint
Adds a schedule_json view
This commit is contained in:
		
						commit
						0fb224cbf6
					
				
					 7 changed files with 248 additions and 1 deletions
				
			
		
							
								
								
									
										11
									
								
								requirements-test.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								requirements-test.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| Django==1.4.15 | ||||
| Pillow==2.5.3 | ||||
| django-discover-runner==1.0 | ||||
| django-markitup==2.2.2 | ||||
| django-model-utils==1.5.0 | ||||
| django-nose==1.2 | ||||
| django-reversion==1.8.0 | ||||
| django-timezones==0.2 | ||||
| factory-boy==2.4.1 | ||||
| nose==1.3.4 | ||||
| pytz==2014.7 | ||||
|  | @ -1,3 +1,5 @@ | |||
| import datetime | ||||
| 
 | ||||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| from django.db import models | ||||
| 
 | ||||
|  | @ -92,6 +94,29 @@ class Slot(models.Model): | |||
|         except ObjectDoesNotExist: | ||||
|             return None | ||||
| 
 | ||||
|     @property | ||||
|     def start_datetime(self): | ||||
|         return datetime.datetime( | ||||
|             self.day.date.year, | ||||
|             self.day.date.month, | ||||
|             self.day.date.day, | ||||
|             self.start.hour, | ||||
|             self.start.minute) | ||||
| 
 | ||||
|     @property | ||||
|     def end_datetime(self): | ||||
|         return datetime.datetime( | ||||
|             self.day.date.year, | ||||
|             self.day.date.month, | ||||
|             self.day.date.day, | ||||
|             self.end.hour, | ||||
|             self.end.minute) | ||||
| 
 | ||||
|     @property | ||||
|     def length_in_minutes(self): | ||||
|         return int( | ||||
|             (self.end_datetime - self.start_datetime).total_seconds() / 60) | ||||
| 
 | ||||
|     @property | ||||
|     def rooms(self): | ||||
|         return Room.objects.filter(pk__in=self.slotroom_set.values("room")) | ||||
|  |  | |||
							
								
								
									
										63
									
								
								symposion/schedule/tests/factories.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								symposion/schedule/tests/factories.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| import datetime | ||||
| import random | ||||
| 
 | ||||
| import factory | ||||
| from factory import fuzzy | ||||
| 
 | ||||
| from symposion.schedule.models import Schedule, Day, Slot, SlotKind | ||||
| from symposion.conference.models import Section, Conference | ||||
| 
 | ||||
| 
 | ||||
| class ConferenceFactory(factory.DjangoModelFactory): | ||||
|     title = fuzzy.FuzzyText() | ||||
|     start_date = fuzzy.FuzzyDate(datetime.date(2014, 1, 1)) | ||||
|     end_date = fuzzy.FuzzyDate(datetime.date(2014, 1, 1) | ||||
|                                + datetime.timedelta(days=random.randint(1, 10))) | ||||
|     # timezone = TimeZoneField("UTC") | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = Conference | ||||
| 
 | ||||
| 
 | ||||
| class SectionFactory(factory.DjangoModelFactory): | ||||
|     conference = factory.SubFactory(ConferenceFactory) | ||||
|     name = fuzzy.FuzzyText() | ||||
|     slug = fuzzy.FuzzyText() | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = Section | ||||
| 
 | ||||
| 
 | ||||
| class ScheduleFactory(factory.DjangoModelFactory): | ||||
|     section = factory.SubFactory(SectionFactory) | ||||
|     published = True | ||||
|     hidden = False | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = Schedule | ||||
| 
 | ||||
| 
 | ||||
| class SlotKindFactory(factory.DjangoModelFactory): | ||||
|     schedule = factory.SubFactory(ScheduleFactory) | ||||
|     label = fuzzy.FuzzyText() | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = SlotKind | ||||
| 
 | ||||
| 
 | ||||
| class DayFactory(factory.DjangoModelFactory): | ||||
|     schedule = factory.SubFactory(ScheduleFactory) | ||||
|     date = fuzzy.FuzzyDate(datetime.date(2014, 1, 1)) | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = Day | ||||
| 
 | ||||
| 
 | ||||
| class SlotFactory(factory.DjangoModelFactory): | ||||
|     day = factory.SubFactory(DayFactory) | ||||
|     kind = factory.SubFactory(SlotKindFactory) | ||||
|     start = datetime.time(random.randint(0, 23), random.randint(0, 59)) | ||||
|     end = datetime.time(random.randint(0, 23), random.randint(0, 59)) | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = Slot | ||||
							
								
								
									
										68
									
								
								symposion/schedule/tests/runtests.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								symposion/schedule/tests/runtests.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| #!/usr/bin/env python | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # see runtests.py in https://github.com/pydanny/cookiecutter-djangopackage | ||||
| 
 | ||||
| import sys | ||||
| 
 | ||||
| try: | ||||
|     from django.conf import settings | ||||
| 
 | ||||
|     settings.configure( | ||||
|         DEBUG=True, | ||||
|         USE_TZ=True, | ||||
|         DATABASES={ | ||||
|             "default": { | ||||
|                 "ENGINE": "django.db.backends.sqlite3", | ||||
|             } | ||||
|         }, | ||||
|         ROOT_URLCONF="symposion.schedule.urls", | ||||
|         INSTALLED_APPS=[ | ||||
|             "django.contrib.auth", | ||||
|             "django.contrib.contenttypes", | ||||
|             "django.contrib.sites", | ||||
| 
 | ||||
|             "markitup", | ||||
|             "reversion", | ||||
| 
 | ||||
|             "symposion", | ||||
|             "symposion.conference", | ||||
|             "symposion.speakers", | ||||
|             "symposion.schedule", | ||||
|             "symposion.proposals", | ||||
| 
 | ||||
|         ], | ||||
|         SITE_ID=1, | ||||
|         NOSE_ARGS=['-s'], | ||||
| 
 | ||||
|         MARKITUP_FILTER=('django.contrib.markup.templatetags.markup.textile', {}), | ||||
|     ) | ||||
| 
 | ||||
|     try: | ||||
|         import django | ||||
|         setup = django.setup | ||||
|     except AttributeError: | ||||
|         pass | ||||
|     else: | ||||
|         setup() | ||||
| 
 | ||||
|     from django_nose import NoseTestSuiteRunner | ||||
| except ImportError: | ||||
|     raise ImportError("To fix this error, run: pip install -r requirements-test.txt") | ||||
| 
 | ||||
| 
 | ||||
| def run_tests(*test_args): | ||||
|     if not test_args: | ||||
|         test_args = ['tests'] | ||||
| 
 | ||||
|     # Run tests | ||||
|     test_runner = NoseTestSuiteRunner(verbosity=1) | ||||
| 
 | ||||
|     failures = test_runner.run_tests(test_args) | ||||
| 
 | ||||
|     if failures: | ||||
|         sys.exit(failures) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     run_tests("symposion.schedule.tests.test_views") | ||||
							
								
								
									
										30
									
								
								symposion/schedule/tests/test_views.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								symposion/schedule/tests/test_views.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| import json | ||||
| 
 | ||||
| from django.test.client import Client | ||||
| from django.test import TestCase | ||||
| 
 | ||||
| from . import factories | ||||
| 
 | ||||
| 
 | ||||
| class ScheduleViewTests(TestCase): | ||||
| 
 | ||||
|     def test_empty_json(self): | ||||
|         c = Client() | ||||
|         r = c.get('/conference.json') | ||||
|         assert r.status_code == 200 | ||||
| 
 | ||||
|         conference = json.loads(r.content) | ||||
|         assert 'schedule' in conference | ||||
|         assert len(conference['schedule']) == 0 | ||||
| 
 | ||||
|     def test_populated_empty_presentations(self): | ||||
| 
 | ||||
|         factories.SlotFactory.create_batch(size=5) | ||||
| 
 | ||||
|         c = Client() | ||||
|         r = c.get('/conference.json') | ||||
|         assert r.status_code == 200 | ||||
| 
 | ||||
|         conference = json.loads(r.content) | ||||
|         assert 'schedule' in conference | ||||
|         assert len(conference['schedule']) == 5 | ||||
|  | @ -1,7 +1,6 @@ | |||
| # flake8: noqa | ||||
| from django.conf.urls.defaults import url, patterns | ||||
| 
 | ||||
| 
 | ||||
| urlpatterns = patterns("symposion.schedule.views", | ||||
|     url(r"^$", "schedule_conference", name="schedule_conference"), | ||||
|     url(r"^edit/$", "schedule_edit", name="schedule_edit"), | ||||
|  | @ -13,4 +12,5 @@ urlpatterns = patterns("symposion.schedule.views", | |||
|     url(r"^([\w\-]+)/list/$", "schedule_list", name="schedule_list"), | ||||
|     url(r"^([\w\-]+)/presentations.csv$", "schedule_list_csv", name="schedule_list_csv"), | ||||
|     url(r"^([\w\-]+)/edit/slot/(\d+)/", "schedule_slot_edit", name="schedule_slot_edit"), | ||||
|     url(r"^conference.json", "schedule_json", name="schedule_json"), | ||||
| ) | ||||
|  |  | |||
|  | @ -1,8 +1,12 @@ | |||
| import json | ||||
| 
 | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.http import Http404, HttpResponse | ||||
| from django.shortcuts import render, get_object_or_404, redirect | ||||
| from django.template import loader, Context | ||||
| 
 | ||||
| from django.contrib.auth.decorators import login_required | ||||
| from django.contrib.sites.models import Site | ||||
| 
 | ||||
| from symposion.schedule.forms import SlotEditForm | ||||
| from symposion.schedule.models import Schedule, Day, Slot, Presentation | ||||
|  | @ -156,3 +160,49 @@ def schedule_presentation_detail(request, pk): | |||
|         "schedule": schedule, | ||||
|     } | ||||
|     return render(request, "schedule/presentation_detail.html", ctx) | ||||
| 
 | ||||
| 
 | ||||
| def schedule_json(request): | ||||
|     slots = Slot.objects.filter( | ||||
|         day__schedule__published=True, | ||||
|         day__schedule__hidden=False | ||||
|     ).order_by("start") | ||||
| 
 | ||||
|     protocol = request.META.get('HTTP_X_FORWARDED_PROTO', 'http') | ||||
|     data = [] | ||||
|     for slot in slots: | ||||
|         slot_data = { | ||||
|             "room": ", ".join(room["name"] for room in slot.rooms.values()), | ||||
|             "rooms": [room["name"] for room in slot.rooms.values()], | ||||
|             "start": slot.start_datetime.isoformat(), | ||||
|             "end": slot.end_datetime.isoformat(), | ||||
|             "duration": slot.length_in_minutes, | ||||
|             "kind": slot.kind.label, | ||||
|             "section": slot.day.schedule.section.slug, | ||||
|         } | ||||
|         if hasattr(slot.content, "proposal"): | ||||
|             slot_data.update({ | ||||
|                 "name": slot.content.title, | ||||
|                 "authors": [s.name for s in slot.content.speakers()], | ||||
|                 "contact": [ | ||||
|                     s.email for s in slot.content.speakers() | ||||
|                 ] if request.user.is_staff else ["redacted"], | ||||
|                 "abstract": slot.content.abstract.raw, | ||||
|                 "description": slot.content.description.raw, | ||||
|                 "content_href": "%s://%s%s" % ( | ||||
|                     protocol, | ||||
|                     Site.objects.get_current().domain, | ||||
|                     reverse("schedule_presentation_detail", args=[slot.content.pk]) | ||||
|                 ), | ||||
|                 "cancelled": slot.content.cancelled, | ||||
|             }) | ||||
|         else: | ||||
|             slot_data.update({ | ||||
|                 "name": slot.content_override.raw if slot.content_override else "Slot", | ||||
|             }) | ||||
|         data.append(slot_data) | ||||
| 
 | ||||
|     return HttpResponse( | ||||
|         json.dumps({'schedule': data}), | ||||
|         content_type="application/json" | ||||
|     ) | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Sheila Miguez
						Sheila Miguez