diff --git a/icekit_events/plugins/event_content_listing/__init__.py b/icekit_events/plugins/event_content_listing/__init__.py new file mode 100644 index 0000000..dd48ee4 --- /dev/null +++ b/icekit_events/plugins/event_content_listing/__init__.py @@ -0,0 +1 @@ +default_app_config = '%s.apps.AppConfig' % __name__ diff --git a/icekit_events/plugins/event_content_listing/abstract_models.py b/icekit_events/plugins/event_content_listing/abstract_models.py new file mode 100644 index 0000000..65587ed --- /dev/null +++ b/icekit_events/plugins/event_content_listing/abstract_models.py @@ -0,0 +1,76 @@ +from datetime import timedelta + +from django.db import models +from django.db.models import Q +from django.utils.encoding import python_2_unicode_compatible +from django.utils.translation import ugettext_lazy as _ + +from timezone import timezone as djtz # django-timezone + +from icekit_events.models import EventType, Occurrence +from icekit.plugins.content_listing.abstract_models import \ + AbstractContentListingItem + + +@python_2_unicode_compatible +class AbstractEventContentListingItem(AbstractContentListingItem): + """ + An embedded listing of event content items. + """ + limit_to_types = models.ManyToManyField( + EventType, + help_text="Leave empty to show all events.", + blank=True, + db_table="ik_event_listing_types", + ) + from_date = models.DateTimeField( + blank=True, null=True, + help_text="Only show events with occurrences that end after this" + " date and time.", + ) + to_date = models.DateTimeField( + blank=True, null=True, + help_text="Only show events with occurrences that start before this" + " date and time.", + ) + from_days_ago = models.IntegerField( + blank=True, null=True, + help_text="Only show events with occurrences after this number of" + " days into the past. Set this to zero to show only events" + " with future occurrences.", + ) + to_days_ahead = models.IntegerField( + blank=True, null=True, + help_text="Only show events with occurrences before this number of" + " days into the future. Set this to zero to show only events" + " with past occurrences.", + ) + + class Meta: + abstract = True + verbose_name = _('Event Content Listing') + + def __str__(self): + return 'Event Content Listing of %s' % self.content_type + + def get_items(self): + qs = Occurrence.objects.visible().distinct() + if self.limit_to_types.count(): + types = self.limit_to_types.all() + qs = qs.filter( + Q(event__primary_type__in=types) | + Q(event__secondary_types__in=types) + ) + # Apply `from_date` and `to_date` limits + qs = qs.overlapping(self.from_date, self.to_date) + # Apply `from_days_ago` and `to_days_ahead` limits + today = djtz.now().date() + from_date = to_date = None + if self.from_days_ago is not None: + from_date = today - timedelta(days=self.from_days_ago) + if self.to_days_ahead is not None: + to_date = today + timedelta(days=self.to_days_ahead) + qs = qs.overlapping(from_date, to_date) + if self.limit: + qs = qs[:self.limit] + return qs diff --git a/icekit_events/plugins/event_content_listing/apps.py b/icekit_events/plugins/event_content_listing/apps.py new file mode 100644 index 0000000..4853fda --- /dev/null +++ b/icekit_events/plugins/event_content_listing/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class AppConfig(AppConfig): + name = '.'.join(__name__.split('.')[:-1]) + label = "ik_event_listing" + verbose_name = "Event Content Listing" diff --git a/icekit_events/plugins/event_content_listing/content_plugins.py b/icekit_events/plugins/event_content_listing/content_plugins.py new file mode 100644 index 0000000..b78d122 --- /dev/null +++ b/icekit_events/plugins/event_content_listing/content_plugins.py @@ -0,0 +1,17 @@ +""" +Definition of the plugin. +""" +from django.utils.translation import ugettext_lazy as _ + +from fluent_contents.extensions import ContentPlugin, plugin_pool + +from . import forms, models + + +@plugin_pool.register +class EventContentListingPlugin(ContentPlugin): + model = models.EventContentListingItem + category = _('Assets') + render_template = 'icekit_events/plugins/event_content_listing/default.html' + form = forms.EventContentListingAdminForm + cache_output = False diff --git a/icekit_events/plugins/event_content_listing/forms.py b/icekit_events/plugins/event_content_listing/forms.py new file mode 100644 index 0000000..c15a71e --- /dev/null +++ b/icekit_events/plugins/event_content_listing/forms.py @@ -0,0 +1,25 @@ +from icekit.plugins.content_listing.forms import ContentListingAdminForm + +from icekit_events.models import EventBase + +from .models import EventContentListingItem + + +class EventContentListingAdminForm(ContentListingAdminForm): + # TODO Improve admin experience: + # - horizontal filter for `limit_to_types` choice + # - verbose_name for Content Type + # - default (required) value for No Items Message. + + class Meta: + model = EventContentListingItem + fields = '__all__' + + def filter_content_types(self, content_type_qs): + """ Filter the content types selectable to only event subclasses """ + valid_ct_ids = [] + for ct in content_type_qs: + model = ct.model_class() + if model and issubclass(model, EventBase): + valid_ct_ids.append(ct.id) + return content_type_qs.filter(pk__in=valid_ct_ids) diff --git a/icekit_events/plugins/event_content_listing/migrations/0001_initial.py b/icekit_events/plugins/event_content_listing/migrations/0001_initial.py new file mode 100644 index 0000000..5eca7b0 --- /dev/null +++ b/icekit_events/plugins/event_content_listing/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fluent_contents', '0001_initial'), + ('contenttypes', '0002_remove_content_type_name'), + ] + + operations = [ + migrations.CreateModel( + name='EventContentListingItem', + fields=[ + ('contentitem_ptr', models.OneToOneField(serialize=False, primary_key=True, to='fluent_contents.ContentItem', parent_link=True, auto_created=True)), + ('limit', models.IntegerField(null=True, help_text=b'How many items to show? No limit is applied if this field is not set', blank=True)), + ('content_type', models.ForeignKey(help_text=b'Content type of items to show in a listing', to='contenttypes.ContentType')), + ], + options={ + 'db_table': 'contentitem_ik_event_listing_eventcontentlistingitem', + 'abstract': False, + 'verbose_name': 'Event Content Listing', + }, + bases=('fluent_contents.contentitem',), + ), + ] diff --git a/icekit_events/plugins/event_content_listing/migrations/0002_auto_20170222_1136.py b/icekit_events/plugins/event_content_listing/migrations/0002_auto_20170222_1136.py new file mode 100644 index 0000000..74f8baf --- /dev/null +++ b/icekit_events/plugins/event_content_listing/migrations/0002_auto_20170222_1136.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('icekit_events', '0016_auto_20161208_0030'), + ('ik_event_listing', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='eventcontentlistingitem', + name='from_date', + field=models.DateTimeField(help_text=b'Only show events with occurrences that end after this date and time.', null=True, blank=True), + ), + migrations.AddField( + model_name='eventcontentlistingitem', + name='from_days_ago', + field=models.IntegerField(help_text=b'Only show events with occurrences after this number of days into the past. Set this to zero to show only events with future occurrences.', null=True, blank=True), + ), + migrations.AddField( + model_name='eventcontentlistingitem', + name='limit_to_types', + field=models.ManyToManyField(help_text=b'Leave empty to show all events.', to='icekit_events.EventType', db_table=b'ik_event_listing_types', blank=True), + ), + migrations.AddField( + model_name='eventcontentlistingitem', + name='to_date', + field=models.DateTimeField(help_text=b'Only show events with occurrences that start before this date and time.', null=True, blank=True), + ), + migrations.AddField( + model_name='eventcontentlistingitem', + name='to_days_ahead', + field=models.IntegerField(help_text=b'Only show events with occurrences before this number of days into the future. Set this to zero to show only events with past occurrences.', null=True, blank=True), + ), + ] diff --git a/icekit_events/plugins/event_content_listing/migrations/0003_eventcontentlistingitem_no_items_message.py b/icekit_events/plugins/event_content_listing/migrations/0003_eventcontentlistingitem_no_items_message.py new file mode 100644 index 0000000..0e38ddd --- /dev/null +++ b/icekit_events/plugins/event_content_listing/migrations/0003_eventcontentlistingitem_no_items_message.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ik_event_listing', '0002_auto_20170222_1136'), + ] + + operations = [ + migrations.AddField( + model_name='eventcontentlistingitem', + name='no_items_message', + field=models.CharField(blank=True, help_text=b'Message to show if there are not items in listing.', null=True, max_length=255), + ), + ] diff --git a/icekit_events/plugins/event_content_listing/migrations/__init__.py b/icekit_events/plugins/event_content_listing/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/icekit_events/plugins/event_content_listing/models.py b/icekit_events/plugins/event_content_listing/models.py new file mode 100644 index 0000000..813a35d --- /dev/null +++ b/icekit_events/plugins/event_content_listing/models.py @@ -0,0 +1,8 @@ +from .abstract_models import AbstractEventContentListingItem + + +class EventContentListingItem(AbstractEventContentListingItem): + """ + An embedded listing of event content items. + """ + pass diff --git a/icekit_events/plugins/event_content_listing/templates/icekit_events/plugins/event_content_listing/_event.html b/icekit_events/plugins/event_content_listing/templates/icekit_events/plugins/event_content_listing/_event.html new file mode 100644 index 0000000..7e07654 --- /dev/null +++ b/icekit_events/plugins/event_content_listing/templates/icekit_events/plugins/event_content_listing/_event.html @@ -0,0 +1,4 @@ +