-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Merlin Buczek
committed
May 31, 2019
1 parent
9975f22
commit d4ebe07
Showing
13 changed files
with
429 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
Oops, something went wrong.