calendarium.views: 168 total statements, 93.6% covered

Generated: Sun 2013-03-24 21:11 CET

Source file: /home/tobi/Projects/calendarium/src/calendarium/views.py

Stats: 146 executed, 10 missed, 12 excluded, 86 ignored

  1. """Views for the ``calendarium`` app."""
  2. import calendar
  3. from django.contrib.auth.decorators import permission_required
  4. from django.core.urlresolvers import reverse
  5. from django.forms.models import model_to_dict
  6. from django.http import Http404, HttpResponseRedirect
  7. from django.utils.decorators import method_decorator
  8. from django.utils.timezone import datetime, now, timedelta, utc
  9. from django.views.generic import (
  10. CreateView,
  11. DeleteView,
  12. DetailView,
  13. RedirectView,
  14. TemplateView,
  15. UpdateView,
  16. )
  17. from calendarium.constants import OCCURRENCE_DECISIONS
  18. from calendarium.forms import OccurrenceForm
  19. from calendarium.models import Event, Occurrence
  20. from calendarium.utils import monday_of_week
  21. class CalendariumRedirectView(RedirectView):
  22. """View to redirect to the current month view."""
  23. def get_redirect_url(self, **kwargs):
  24. return reverse('calendar_month', kwargs={'year': now().year,
  25. 'month': now().month})
  26. class MonthView(TemplateView):
  27. """View to return all occurrences of an event for a whole month."""
  28. template_name = 'calendarium/calendar_month.html'
  29. def dispatch(self, request, *args, **kwargs):
  30. self.month = int(kwargs.get('month'))
  31. self.year = int(kwargs.get('year'))
  32. if self.month not in range(1, 13):
  33. raise Http404
  34. if request.method == 'POST':
  35. if request.POST.get('next'):
  36. new_date = datetime(self.year, self.month, 1) + timedelta(
  37. days=31)
  38. return HttpResponseRedirect(reverse('calendar_month', kwargs={
  39. 'year': new_date.year, 'month': new_date.month}))
  40. elif request.POST.get('previous'):
  41. new_date = datetime(self.year, self.month, 1) - timedelta(
  42. days=1)
  43. return HttpResponseRedirect(reverse('calendar_month', kwargs={
  44. 'year': new_date.year, 'month': new_date.month}))
  45. elif request.POST.get('today'):
  46. return HttpResponseRedirect(reverse('calendar_month', kwargs={
  47. 'year': now().year, 'month': now().month}))
  48. if request.is_ajax():
  49. self.template_name = 'calendarium/partials/calendar_month.html'
  50. return super(MonthView, self).dispatch(request, *args, **kwargs)
  51. def get_context_data(self, **kwargs):
  52. month = [[]]
  53. week = 0
  54. for day in calendar.Calendar().itermonthdays(self.year, self.month):
  55. current = False
  56. if day:
  57. date = datetime(year=self.year, month=self.month, day=day,
  58. tzinfo=utc)
  59. occurrences = Event.objects.get_occurrences(date, date)
  60. if date.date() == now().date():
  61. current = True
  62. else:
  63. occurrences = []
  64. month[week].append((day, occurrences, current))
  65. if len(month[week]) == 7:
  66. month.append([])
  67. week += 1
  68. ctx = {'month': month, 'date': date}
  69. return ctx
  70. class WeekView(TemplateView):
  71. """View to return all occurrences of an event for one week."""
  72. template_name = 'calendarium/calendar_week.html'
  73. def dispatch(self, request, *args, **kwargs):
  74. self.week = int(kwargs.get('week'))
  75. self.year = int(kwargs.get('year'))
  76. if self.week not in range(1, 53):
  77. raise Http404
  78. if request.method == 'POST':
  79. if request.POST.get('next'):
  80. date = monday_of_week(self.year, self.week) + timedelta(days=7)
  81. return HttpResponseRedirect(reverse('calendar_week', kwargs={
  82. 'year': date.year, 'week': date.date().isocalendar()[1]}))
  83. elif request.POST.get('previous'):
  84. date = monday_of_week(self.year, self.week) - timedelta(days=7)
  85. return HttpResponseRedirect(reverse('calendar_week', kwargs={
  86. 'year': date.year, 'week': date.date().isocalendar()[1]}))
  87. elif request.POST.get('today'):
  88. return HttpResponseRedirect(reverse('calendar_week', kwargs={
  89. 'year': now().year,
  90. 'week': now().date().isocalendar()[1]}))
  91. if request.is_ajax():
  92. self.template_name = 'calendarium/partials/calendar_week.html'
  93. return super(WeekView, self).dispatch(request, *args, **kwargs)
  94. def get_context_data(self, **kwargs):
  95. date = monday_of_week(self.year, self.week)
  96. week = []
  97. day = 0
  98. while day < 7:
  99. current = False
  100. occurrences = Event.objects.get_occurrences(date, date)
  101. if date.date() == now().date():
  102. current = True
  103. week.append((date, occurrences, current))
  104. day += 1
  105. date = date + timedelta(days=1)
  106. ctx = {'week': week, 'date': date, 'week_nr': self.week}
  107. return ctx
  108. class DayView(TemplateView):
  109. """View to return all occurrences of an event for one day."""
  110. template_name = 'calendarium/calendar_day.html'
  111. def dispatch(self, request, *args, **kwargs):
  112. self.day = int(kwargs.get('day'))
  113. self.month = int(kwargs.get('month'))
  114. self.year = int(kwargs.get('year'))
  115. try:
  116. self.date = datetime(year=self.year, month=self.month,
  117. day=self.day, tzinfo=utc)
  118. except ValueError:
  119. raise Http404
  120. if request.method == 'POST':
  121. if request.POST.get('next'):
  122. date = self.date + timedelta(days=1)
  123. return HttpResponseRedirect(reverse('calendar_day', kwargs={
  124. 'year': date.year, 'month': date.month, 'day': date.day}))
  125. elif request.POST.get('previous'):
  126. date = self.date - timedelta(days=1)
  127. return HttpResponseRedirect(reverse('calendar_day', kwargs={
  128. 'year': date.year, 'month': date.month, 'day': date.day}))
  129. elif request.POST.get('today'):
  130. return HttpResponseRedirect(reverse('calendar_day', kwargs={
  131. 'year': now().year, 'month': now().month,
  132. 'day': now().day}))
  133. if request.is_ajax():
  134. self.template_name = 'calendarium/partials/calendar_day.html'
  135. return super(DayView, self).dispatch(request, *args, **kwargs)
  136. def get_context_data(self, **kwargs):
  137. occurrences = Event.objects.get_occurrences(self.date, self.date)
  138. ctx = {'date': self.date, 'occurrences': occurrences}
  139. return ctx
  140. class EventDetailView(DetailView):
  141. """View to return information of an event."""
  142. model = Event
  143. class EventMixin(object):
  144. """Mixin to handle event-related functions."""
  145. model = Event
  146. @method_decorator(permission_required('calendarium.add_event'))
  147. def dispatch(self, request, *args, **kwargs):
  148. return super(EventMixin, self).dispatch(request, *args, **kwargs)
  149. class EventUpdateView(EventMixin, UpdateView):
  150. """View to update information of an event."""
  151. pass
  152. class EventCreateView(EventMixin, CreateView):
  153. """View to create an event."""
  154. pass
  155. class EventDeleteView(EventMixin, DeleteView):
  156. """View to delete an event."""
  157. pass
  158. class OccurrenceViewMixin(object):
  159. """Mixin to avoid repeating code for the Occurrence view classes."""
  160. form_class = OccurrenceForm
  161. def dispatch(self, request, *args, **kwargs):
  162. try:
  163. self.event = Event.objects.get(pk=kwargs.get('pk'))
  164. except Event.DoesNotExist:
  165. raise Http404
  166. year = int(kwargs.get('year'))
  167. month = int(kwargs.get('month'))
  168. day = int(kwargs.get('day'))
  169. try:
  170. date = datetime(year, month, day, tzinfo=utc)
  171. except TypeError:
  172. raise Http404
  173. # this should retrieve the one single occurrence, that has a
  174. # matching start date
  175. try:
  176. occ = Occurrence.objects.get(
  177. start__year=year, start__month=month, start__day=day)
  178. except Occurrence.DoesNotExist:
  179. occ_gen = self.event.get_occurrences(self.event.start)
  180. occ = occ_gen.next()
  181. while occ.start.date() < date.date():
  182. occ = occ_gen.next()
  183. if occ.start.date() == date.date():
  184. self.occurrence = occ
  185. else:
  186. raise Http404
  187. self.object = self.occurrence
  188. return super(OccurrenceViewMixin, self).dispatch(
  189. request, *args, **kwargs)
  190. def get_object(self):
  191. return self.occurrence
  192. def get_form_kwargs(self):
  193. kwargs = super(OccurrenceViewMixin, self).get_form_kwargs()
  194. kwargs.update({'initial': model_to_dict(self.occurrence)})
  195. return kwargs
  196. class OccurrenceDeleteView(OccurrenceViewMixin, DeleteView):
  197. """View to delete an occurrence of an event."""
  198. def delete(self, request, *args, **kwargs):
  199. self.object = self.get_object()
  200. decision = self.request.POST.get('decision')
  201. self.object.delete_period(decision)
  202. return HttpResponseRedirect(self.get_success_url())
  203. def get_context_data(self, object):
  204. ctx = super(OccurrenceDeleteView, self).get_context_data()
  205. ctx.update({
  206. 'decisions': OCCURRENCE_DECISIONS,
  207. 'object': self.object
  208. })
  209. return ctx
  210. class OccurrenceDetailView(OccurrenceViewMixin, DetailView):
  211. """View to show information of an occurrence of an event."""
  212. pass
  213. class OccurrenceUpdateView(OccurrenceViewMixin, UpdateView):
  214. """View to edit an occurrence of an event."""
  215. pass