Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into feature/django-g…
Browse files Browse the repository at this point in the history
…uardian-support
  • Loading branch information
dirkmoors committed Nov 17, 2016
2 parents 4e355aa + edcf2c0 commit 089226f
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 16 deletions.
7 changes: 2 additions & 5 deletions schedule/feeds/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.utils.six.moves.builtins import str
from schedule.models import Calendar
from django.contrib.syndication.views import Feed, FeedDoesNotExist
from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from schedule.feeds.ical import ICalendarFeed
import itertools
Expand All @@ -14,10 +13,8 @@ class UpcomingEventsFeed(Feed):
def feed_title(self, obj):
return "Upcoming Events for %s" % obj.name

def get_object(self, request, bits):
if len(bits) != 1:
raise ObjectDoesNotExist
return Calendar.objects.get(pk=bits[0])
def get_object(self, request, calendar_id):
return Calendar.objects.get(pk=calendar_id)

def link(self, obj):
if not obj:
Expand Down
32 changes: 29 additions & 3 deletions schedule/models/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def hours(self):
def get_absolute_url(self):
return reverse('event', args=[self.id])

def get_occurrences(self, start, end):
def get_occurrences(self, start, end, clear_prefetch=True):
"""
>>> rule = Rule(frequency = "MONTHLY", name = "Monthly")
>>> rule.save()
Expand All @@ -131,9 +131,35 @@ def get_occurrences(self, start, end):
>>> occurrences = event.get_occurrences(datetime.datetime(2008,1,24), datetime.datetime(2008,3,2))
>>> ["%s to %s" %(o.start, o.end) for o in occurrences]
[]
`
"""
persisted_occurrences = self.occurrence_set.all()

# Explanation of clear_prefetch:
#
# Periods, and their subclasses like Week, call
# prefetch_related('occurrence_set') on all events in their
# purview. This reduces the database queries they make from
# len()+1 to 2. However, having a cached occurrence_set on the
# Event model instance can sometimes cause Events to have a
# different view of the state of occurrences than the Period
# managing them.
#
# E.g., if you create an unsaved occurrence, move it to a
# different time [which saves the event], keep a reference to
# the moved occurrence, & refetch all occurrences from the
# Period without clearing the prefetch cache, you'll end up
# with two Occurrences for the same event but different moved
# states. It's a complicated scenario, but can happen. (See
# tests/test_occurrence.py#test_moved_occurrences, which caught
# this bug in the first place.)
#
# To prevent this, we clear the select_related cache by default
# before we call an event's get_occurrences, but allow Period
# to override this cache clear since it already fetches all
# occurrence_sets via prefetch_related in its get_occurrences.
if clear_prefetch:
persisted_occurrences = self.occurrence_set.select_related(None).all()
else:
persisted_occurrences = self.occurrence_set.all()
occ_replacer = OccurrenceReplacer(persisted_occurrences)
occurrences = self._get_occurrence_list(start, end)
final_occurrences = []
Expand Down
12 changes: 11 additions & 1 deletion schedule/periods.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
import calendar as standardlib_calendar

from django.conf import settings
try:
from django.db.models import prefetch_related_objects
except ImportError:
from django.db.models.query import prefetch_related_objects

from django.utils.translation import ugettext
from django.utils.encoding import python_2_unicode_compatible
from django.template.defaultfilters import date as date_filter
Expand Down Expand Up @@ -77,8 +82,13 @@ def _get_sorted_occurrences(self):
if occurrence.start <= self.utc_end and occurrence.end >= self.utc_start:
occurrences.append(occurrence)
return occurrences

try:
prefetch_related_objects(self.events, 'occurrence_set')
except AttributeError:
prefetch_related_objects(self.events, ['occurrence_set'])
for event in self.events:
event_occurrences = event.get_occurrences(self.start, self.end)
event_occurrences = event.get_occurrences(self.start, self.end, clear_prefetch=False)
occurrences += event_occurrences
return sorted(occurrences)

Expand Down
8 changes: 4 additions & 4 deletions schedule/templates/schedule/calendar.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

<h1>{% trans "Calendar metadata" %}</h1>

<p>{% blocktrans with calendar_name=calendar.name %}Name: {{calendar_name}}{% endblocktrans %}</p>
<p>{% blocktrans with calendar_slug=calendar.slug %}Slug: {{calendar_slug}}{% endblocktrans %}</p>
<p>{% blocktrans with events_count %}Event count: {{events_count}}{% endblocktrans %}</p>
<p>{% trans "Name:" %} {{calendar_name}} </p>
<p>{% trans "Slug:" %} {{calendar_slug}} </p>
<p>{% trans "Event count:" %} {{events_count}} </p>

<div>
<p>{% trans "See as:" %}</p>
Expand All @@ -19,7 +19,7 @@ <h1>{% trans "Calendar metadata" %}</h1>
<li><a href="{% url "year_calendar" calendar.slug %}">{% trans "This Year" %}</a></li>
<li><a href="{% url "week_calendar" calendar.slug %}">{% trans "Weekly" %}</a></li>
<li><a href="{% url "day_calendar" calendar.slug %}">{% trans "Daily" %}</a></li>
<li><a href="/schedule/feed/calendar/upcoming/{{ calendar.id }}/">{% trans "Feed" %}</a></li>
<li><a href="{% url "upcoming_events_feed" calendar_id=calendar.id %}">{% trans "Feed" %}</a></li>
</ul>
</div>

Expand Down
2 changes: 1 addition & 1 deletion schedule/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
name="edit_occurrence_by_date"),

# feed urls
url(r'^feed/calendar/upcoming/(.*)/$', UpcomingEventsFeed(), name='upcoming_events_feed'),
url(r'^feed/calendar/upcoming/(?P<calendar_id>\d+)/$', UpcomingEventsFeed(), name='upcoming_events_feed'),
url(r'^ical/calendar/(.*)/$', CalendarICalendar(), name='calendar_ical'),

# api urls
Expand Down
18 changes: 16 additions & 2 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import json
import pytz

from django.test.utils import override_settings
from django.test import TestCase
from django.test import override_settings
from django.core.urlresolvers import reverse
from django.test import TestCase

from schedule.models.calendars import Calendar
from schedule.models.events import Event, Occurrence
Expand Down Expand Up @@ -291,3 +291,17 @@ def test_check_next_url_invalid_case(self):
self.assertEquals(expected, res)
res = check_next_url(None)
self.assertEquals(expected, res)

@override_settings(SITE_ID=1)
def test_feed_link(self):
feed_url = reverse('upcoming_events_feed', kwargs={'calendar_id': 1})
response = self.client.get(feed_url)
self.assertEquals(response.status_code, 200)
expected_feed = '<?xml version="1.0" encoding="utf-8"?>\n<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title></title><link>http://example.com/calendar/example/</link><description></description><atom:link href="http://example.com/feed/calendar/upcoming/1/" rel="self"></atom:link><language>en-us</language><lastBuildDate>'
self.assertTrue(expected_feed in response.content)

def test_calendar_view_home(self):
calendar_view_url = reverse('calendar_home', kwargs={'calendar_slug': 'example'})
response = self.client.get(calendar_view_url)
self.assertEquals(response.status_code, 200)
self.assertTrue('<a href="/feed/calendar/upcoming/1/">Feed</a>' in response.content)

0 comments on commit 089226f

Please sign in to comment.