Skip to content

Commit

Permalink
Events Init
Browse files Browse the repository at this point in the history
  • Loading branch information
Merlin Buczek committed May 31, 2019
1 parent 9975f22 commit d4ebe07
Show file tree
Hide file tree
Showing 13 changed files with 429 additions and 0 deletions.
Empty file added mpicms/events/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions mpicms/events/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class EventAppConfig(AppConfig):
name = "mpicms.events"
verbose_name = "Events"
71 changes: 71 additions & 0 deletions mpicms/events/date_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from datetime import datetime
from isoweek import Week

from .utils import date_to_datetime, add_months


class TimePeriod:
TIME_PERIODS = {
'year': get_year_range,
'week': get_week_range,
'month': get_month_range,
'day': get_day_range,
}

def __init__(self, start_date):
pass

def get_year_range(start_date):
"""
Get the start and end datetimes for the year
:param start_date: period start_date
:type start_date: datetime.datetime()
:return: tuple start_datetime, end_datetime
"""
start_date = datetime(start_date.year, 1, 1)
end_date = date_to_datetime(add_months(start_date, 12), 'max')
return start_date, end_date


def get_month_range(start_date):
"""
Get the start and end datetimes for the month
:param start_date: period start_date
:type start_date: datetime.datetime()
:return: tuple start_datetime, end_datetime
"""
start_date = datetime(start_date.year, start_date.month, 1)
end_date = date_to_datetime(
add_months(start_date.date(), 1),
'max'
)
return start_date, end_date


def get_week_range(start_date):
"""
Get the start and end datetimes for the week
:param start_date: period start_date
:type start_date: datetime.datetime()
:return: tuple start_datetime, end_datetime
"""
period = Week(start_date.year, start_date.date().isocalendar()[1])
start_date = date_to_datetime(period.monday())
end_date = date_to_datetime(period.sunday(), 'max')
return start_date, end_date


def get_day_range(start_date):
"""
Get the start and end datetimes for the day
:param start_date: period start_date
:type start_date: datetime.datetime()
:return: tuple start_datetime, end_datetime
"""
start_date = date_to_datetime(start_date.date(), 'min')
end_date = date_to_datetime(start_date.date(), 'max')
return start_date, end_date
28 changes: 28 additions & 0 deletions mpicms/events/managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from wagtail.core.models import PageManager


class DatedEventManager(PageManager):
@staticmethod
def _get_min_time(dt):
"""
Makes clock to 00:00:00
:param dt: datetime
:return: datetime
"""
return dt.replace(hour=0, minute=0, second=0)

def in_date_range(self, start, end):
"""
Get event dates that appear between the start and end dates
:return: Filtered django model queryset
"""
start = self._get_min_time(start)
end = self._get_min_time(end)
return self.filter(start_date__gte=start, start_date__lte=end)

def live(self):
"""
Get event dates associated with live event series
:return: Filtered django model queryset
"""
return self.filter(live=True)
Empty file.
94 changes: 94 additions & 0 deletions mpicms/events/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from django.db import models
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, MultiFieldPanel
from wagtail.core.blocks import CharBlock, TextBlock, BlockQuoteBlock
from wagtail.core.fields import StreamField
from wagtail.core.models import Page
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.edit_handlers import ImageChooserPanel

from .mixins import AbstractEvent, AbstractPaginatedIndex
# from .utils import _DATE_FORMAT_RE

import datetime
import re
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db import models
from django.utils import timezone
from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel
from wagtail.core.models import Page

from .date_filters import get_day_range, get_month_range, get_week_range, get_year_range
from .managers import DatedEventManager
from .utils import date_to_datetime


class Event(Page):
start_date = models.DateTimeField()
end_date = models.DateTimeField(blank=True, null=True)
objects = DatedEventManager()
description = models.TextField(max_length=400, help_text='Briefly describe your event', null=False, blank=True)
body = RichTextField(_("content"), blank=True)

parent_page_types = ['events.EventIndex']
subpage_types = []

content_panels = Page.content_panels + [
FieldPanel('description'),
MultiFieldPanel(
[
FieldPanel('start_date'),
FieldPanel('end_date'),
],
heading="Event Start / End Dates"
),
FieldPanel('body', classname="full"),
]

def clean(self):
"""Clean the model fields, if end_date is before start_date raise a ValidationError."""
super().clean()

if self.end_date and self.end_date < self.start_date:
raise ValidationError({'end_date': 'The end date cannot be before the start date.'})

class Meta(object): # noqa
ordering = ['start_date']


class EventIndex(Page):
parent_page_types = []
subpage_types = ['events.Event']

PAGINATE_BY = 3

def get_context(self, request, *args, **kwargs):
"""
Adds child pages to the context and paginates them.
"""
context = super().get_context(request, *args, **kwargs)
children = self.get_children().type(Event)

# Period
period = request.GET.get('scope', None)
start_date = request.GET.get('start_date', '')
if period:
self.get_start_end(period, start_date)
children.filter(start_date__gte=start_date).filter(end_date__lte=end_date)

# Pagination
paginator = Paginator(queryset, PAGINATE_BY)
page_num = request.GET.get('page', 1) or 1

try:
queryset = paginator.page(page_num)
except PageNotAnInteger:
queryset = paginator.page(1)
except EmptyPage:
queryset = paginator.page(paginator.num_pages)

context.update(
children=queryset,
paginator=paginator
)
return context
Empty file.
64 changes: 64 additions & 0 deletions mpicms/events/templatetags/wagtail_events_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from urllib.parse import urlencode

from django import template


register = template.Library()


@register.simple_tag(takes_context=True)
def querystring(context, *args, **kwargs):
"""
Display all GET values (except page) encoded as url params
:param context: template context
:return: string|encoded params as urlstring
"""
try:
params = context['request'].GET.dict()
except (KeyError, AttributeError):
params = {}
else:
for value in args:
params.pop(value, None)
for key, value in kwargs.items():
params[key] = value
return urlencode(params)


def _patch(context, key, data):
"""
Patch the GET value
:param context: template context dict
:param key: item name
:param data: item value
:return: patched url params
"""
getvars = dict(context['request'].GET)
getvars[key] = [data]
return '?{0}'.format(urlencode(getvars, doseq=True))


@register.simple_tag(takes_context=True)
def patch_scope(context, scope):
"""
Prepare scope for agenda
:param context:
:param scope:
:return:
"""
return _patch(context, 'scope', scope)


@register.simple_tag(takes_context=True)
def patch_start_date(context, date):
"""
Prepare `start_date` url for agenda
:param context: template context dict
:param date: start_date
:return:
"""
return _patch(context, 'start_date', date.strftime('%Y.%m.%d'))
17 changes: 17 additions & 0 deletions mpicms/events/translation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from modeltranslation.translator import TranslationOptions
from modeltranslation.decorators import register

from .models import Event, EventIndex


@register(Event)
class EventPageTR(TranslationOptions):
fields = (
'description',
'body'
)


@register(EventIndex)
class EventIndexPageTR(TranslationOptions):
pass
69 changes: 69 additions & 0 deletions mpicms/events/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import calendar
import datetime

from django.utils import timezone


DATE_FORMAT_RE = r'^([0-9]){4}\.([0-9]){2}\.([0-9]){2}$'


def get_start_end(period, start_date):
if re.match(cls.DATE_FORMAT_RE, start_date):
date_params = [int(i) for i in start_date.split('.')]
start_date = date_to_datetime(datetime.date(*date_params))
else:
start_date = timezone.now().replace(
hour=0,
minute=0,
second=0,
microsecond=0,
)

# Clean the start and end dates to conform to the requested period
start_date, end_date = cls.TIME_PERIODS[period.lower()](start_date)
return start_date, end_date


def date_to_datetime(date, time_choice='min'):
"""
Convert date to datetime.
:param date: date to convert
:param time_choice: max or min
:return: datetime
"""
choice = getattr(datetime.datetime, 'min' if time_choice == 'min' else 'max').time()
return timezone.make_aware(
datetime.datetime.combine(date, choice),
timezone.get_current_timezone(),
)


def add_months(date, months):
"""
Add months to the date.
:param date:
:param months:
:return:
"""
month = date.month - 1 + months
year = int(date.year + month / 12)
month = month % 12 + 1
day = min(date.day, calendar.monthrange(year, month)[1])
return datetime.date(year, month, day)


def remove_months(date, months):
"""
Add months to the date.
:param date:
:param months:
:return:
"""
month = date.month - 1 - months
year = int(date.year + month / 12)
month = month % 12 + 1
day = min(date.day, calendar.monthrange(year, month)[1])
return datetime.date(year, month, day)
15 changes: 15 additions & 0 deletions mpicms/templates/events/components/paginator.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% load wagtail_events_tags %}

<div>
{% if page.has_previous %}
<a href="?{% querystring 'page' page=page.previous_page_number %}">previous</a>
{% endif %}

<span>
Page {{ page.number }} of {{ page.paginator.num_pages }}.
</span>

{% if page.has_next %}
<a href="?{% querystring 'page' page=page.next_page_number %}">next</a>
{% endif %}
</div>
Loading

0 comments on commit d4ebe07

Please sign in to comment.