Commits

Luke Plant committed f9c64c7

Added 'midweek meetings' functionality

  • Participants
  • Parent commits 36b7b75

Comments (0)

Files changed (4)

christchurch/templates/christchurch/midweek.html

+{% extends "christchurch/iframe.html" %}
+{% block content %}
+{% if message %}
+  {{ message }}
+{% else %}
+  {% for event in events %}
+    {% ifchanged event.start.date %}
+      <h2>{{ event.start|date:"F j, Y" }}</h2>
+    {% endifchanged %}
+  <p><b>{{ event.summary }}:</b><br/>
+    Location: {% if event.location %}{{ event.location }}{% else %}Unknown{% endif %}<br/>
+    {% if event.description %}More information: {{ event.description }}<br/>{% endif %}
+  </p>
+  {% endfor %}
+{% endif %}
+{% endblock %}

christchurch/templates/christchurch/thissunday.html

     {% ifchanged event.start.date %}
       <h2>{{ event.start|date:"F j, Y" }}</h2>
     {% endifchanged %}
-  <p><b>{{ event.nice_time }}:</b> {{ event.speaker }}</p>
+  <p><b>{{ event.nice_time }}:</b> {{ event.summary }}</p>
   {% endfor %}
 {% endif %}
 {% endblock %}

christchurch/urls.py

 admin.autodiscover()
 
 urlpatterns = patterns('',
-                       url(r'^thissunday/', 'christchurch.views.this_sunday'),
+                       url(r'^thissunday/$', 'christchurch.views.this_sunday'),
+                       url(r'^upcoming-midweek/$', 'christchurch.views.upcoming_midweek'),
                        url(r'^admin/', include(admin.site.urls)),
                        url(r'^', include('cms.urls')),
                        # Sermons views included via apphooks

christchurch/views.py

 from datetime import datetime, timedelta
-from dateutil import tz
+from dateutil import tz, rrule
 import pytz
 import re
 
 
 local_timezone = pytz.timezone('Europe/London')
 
+
 def get_calendar(url):
     data = requests.get(url).content
     data = bad_dates.sub('', data)
 
 
 class Event(object):
-    def __init__(self, start, speaker):
+    def __init__(self, summary, start, location=None, description=None, vevent=None):
         self.start = start
-        self.speaker = speaker
+        self.summary = summary
+        self.location = location
+        self.description = description
+        self.vevent = vevent # for debugging
 
     def nice_time(self):
         if self.start.hour < 11:
             return "Afternoon"
 
     def __cmp__(self, other):
-        return cmp(self.start, other.start)
+        if type(self.start) != type(other.start):
+            # Cope with 'date' objects by converting both to 'date'
+            return cmp(self.start.date if hasattr(self.start, 'date') else self.start,
+                       other.start.date if hasattr(other.start, 'date') else other.start)
+        else:
+            return cmp(self.start, other.start)
+
+    def __repr__(self):
+        return '<Event: %s, %s, location=%s, description=%s>' % (self.summary, self.start, self.location, self.description)
 
 def this_sunday(request):
     try:
     if cal is not None:
         events = []
         for vevent in cal.vevent_list:
-            d = vevent.dtstart.value
-            if d.tzinfo is None:
-                d = d.replace(tzinfo=tz.tzutc())
-
-            d = d.astimezone(local_timezone)
+            d = vevent.dtstart.value.astimezone(local_timezone)
             # Clock should 'tick over' to the next week at the end of Sunday,
             # not part way through, so truncate hour to zero
             today = datetime.now(local_timezone).replace(hour=0)
     return render(request, "christchurch/thissunday.html", c)
 
 
+def upcoming_midweek(request):
+    try:
+        cal = get_calendar(MIDWEEK_ICAL)
+    except Exception:
+        cal = None
+
+    c = {}
+    if cal is not None:
+        today = datetime.now(local_timezone).replace(hour=0)
+        events = search(cal, today, today + timedelta(60))
+        c['events'] = events
+    else:
+        c['message'] = "Calendar not available"
+
+    return render(request, "christchurch/midweek.html", c)
+
+
+def search(calendar, start_date, end_date):
+    """
+    Returns a list of events in calendar betweem the specified datetime objects,
+    creating recurring events as necessary.
+    """
+    # First, do a pre run to get all the dates we nned to exclude,
+    # i.e. those that have specific instances, identified by recurrence-id
+
+    exclusions = []
+    for v in calendar.vevent_list:
+        rc = v.contents.get('recurrence-id', None)
+        if rc is not None:
+            # rc is a list, don't know if it can ever contain more than one
+            # item, but we'll deal with that anyway.
+            for d in rc:
+                exclusions.append(d.value)
+
+    events = []
+    def mk_event(v, startdate):
+        return Event(v.summary.value if hasattr(v, 'summary') else '',
+                     startdate,
+                     location=v.location.value if hasattr(v, 'location') else None,
+                     description=v.description.value if hasattr(v, 'description') else None,
+                     vevent=v,
+                     )
+
+    for v in calendar.vevent_list:
+        if not hasattr(v, 'rrule'):
+            # No recurrence, just look at dtstart
+            dt = v.dtstart.value
+            if not hasattr(dt, 'date'):
+                # A 'date', not 'datetime'
+                if dt >= start_date.date() and dt <= end_date.date():
+                    events.append(mk_event(v, dt))
+            else:
+                if dt >= start_date and dt <= end_date:
+                    events.append(mk_event(v, dt))
+        else:
+            ruleset = rrule.rruleset()
+            rule = rrule.rrulestr(v.rrule.value, dtstart=v.dtstart.value)
+            ruleset.rrule(rule)
+            if hasattr(v, 'exdate_list'):
+                for l in v.exdate_list:
+                    for d in l.value:
+                        ruleset.exdate(d)
+            for d in exclusions:
+                ruleset.exdate(d)
+            events.extend([mk_event(v, ev_date)
+                           for ev_date in ruleset.between(start_date, end_date)])
+
+    events.sort()
+    return events