Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging events from two calendars... #42

Open
skoontastic opened this issue Aug 3, 2021 · 4 comments
Open

Merging events from two calendars... #42

skoontastic opened this issue Aug 3, 2021 · 4 comments

Comments

@skoontastic
Copy link

I've been loving Joyous Calendar and Wagtail so much. It's just great software.

I have a main CalendarPage at the root of my site where I'd like to keep events that should display on all other calendars on the site. How would I reach back up to that calendar to display those events on a calendar that exists down the page tree? I'm using a custom class based on CalendarPage as my sub-calendars, so I tried to get the top-level CalendarPage and the merge the events, but I get a "Models aren't loaded yet." error.

Any ideas on this problem?

@linuxsoftware
Copy link
Owner

So, if I understand correctly your site is structured something like this?

Home-Calendar
+--- Sub-Calendar1
|    +--- Event1
|    +--- Event2
+--- Sub-Calendar2
     +--- Event3
     +--- Event4

Where: Event1 and Event2 should appear in Sub-Calendar1; Event3 and Event4 should appear in Sub-Calendar2; And all the events 1,2,3,4 should appear in Home-Calendar?

Joyous was designed to support just this. You don't need to "reach up" to merge in events, instead the Calendars "reach down" to pull in events. (Hope that makes sense.)

  • The CalendarPage class will search for all the events in the site, no matter what their parent. So it (or something derieved from it) can be used for Home-Calendar.
  • The SpecificCalendarPage class searches only for those events which are children of itself. So it (or something derieved from it) can be used for the Sub-Calendars.
    Normally SpecificCalendarPage is disabled. To enable it you'll need to add SpecificCalendarPage.is_creatable = True in your models.py, or define is_creatable as True in your derieved class.

Or derive your own version of CalendarPage with some other kind of event selection.

Hope that helps.

@skoontastic
Copy link
Author

Sorry, I didn't explain myself very well. You have the structure correct, but I want to reach up so that Sub-Calendar1 and Sub-Calendar2 show their respective child events and the events from Home-Calendar. I'm actually using a derived CalendarPage for the "sub calendars" already, which I tried to use to pull in the Home-Calendar events, which is what brought up the "Models aren't loaded yet" error.

I'll make it more concrete. This is for a school district website. The top level calendar is for "All-district" events. Then under that there are individual school calendars:

District-Calendar
+---High School Calendar
|      +---Event1
|      +---Event2
+---Middle School Calendar
|      +---Event3
|      +---Event4

So each school calendar should show its events as well as any all-district events.

Thanks for the quick reply and for making some sweet software!

@linuxsoftware
Copy link
Owner

Thanks for the clarification. I guess I was just looking for the question I already had an answer for :-).

I think your approach in subclassing the school calendars is the correct one (more suggestions on that further down). I can't say why you are getting the "Models aren't loaded yet" error. You'll have seen it suggests that you are trying to use models before all the applications have loaded. If you can share the stack trace, I might be able to help further.

For ease of implementation, would the following structure still work for you?

HomePage (render the District-Calendar content)
+---District-Calendar (slug=district-calendar)
|      +---Event0
+---High School Calendar
|      +---Event1
|      +---Event2
+---Middle School Calendar
|      +---Event3
|      +---Event4

This would make it easier to identify what is an all-district event (e.g. Event0) and what events are specific to a school. The site could look the same to viewers, but editors would need to know where too look for the all-district events.

None of the code below is tested (will be buggy), but this is my idea of how the sub-class could be implemented. If I get time I will try and get a real example working.

It is an interesting exercise thinking how to extend Joyous like this. Thanks! I can see some possibilities for future changes to make this kind of thing simpler.

class MergedCalendarPage(ProxyPageMixin, CalendarPage):
    """
    MergedCalendarPage displays the events which are its children or the
    children of the merged page
    """
    class Meta(ProxyPageMixin.Meta):
        verbose_name = "merged calendar page"
        verbose_name_plural = "merged calendar pages"

    MERGE_IN_SLUG = "district-calendar"

    @classmethod
    def _allowAnotherAt(cls, parent):
        return True

    def _getEventsByDay(self, request, firstDay, lastDay):
        merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
        evods = []
        myEvods = getAllEventsByDay(request, firstDay, lastDay,
                                    home=self, holidays=self.holidays)
        mergeEvods = getAllEventsByDay(request, firstDay, lastDay,
                                       home=merged, holidays=self.holidays)
        for myEvod, mergeEvod in zip(myEvods, mergeEvods):
            day = myEvod.date
            days_events = myEvod.days_events + mergeEvod.days_events
            continuing_events = myEvod.continuing_events + mergeEvod.continuing_events
            def sortByTime(thisEvent):
                fromTime = thisEvent.page._getFromTime(atDate=day)
                if fromTime is None:
                    fromTime = dt.time.max
                return fromTime
            days_events.sort(key=sortByTime)
            evods.append(EventsOnDay(day, myEvods.holiday, days_events, continuing_events))
        return evods

    def _getEventsByWeek(self, request, year, month):
        return _getEventsByWeek(year, month,
                                partial(self._getEventsByDay, request))

    def _getUpcomingEvents(self, request):
        merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
        myEvents = getAllUpcomingEvents(request, home=self, holidays=self.holidays)
        mergeEvents = getAllUpcomingEvents(request, home=merged, holidays=self.holidays)
        events = sorted(myEvents + mergeEvents, key=_getUpcomingSort())
        return events

    def _getPastEvents(self, request):
        merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
        myEvents = getAllPastEvents(request, home=self, holidays=self.holidays)
        mergeEvents = getAllPastEvents(request, home=merged, holidays=self.holidays)
        events = sorted(myEvents + mergeEvents,
                        key=attrgetter('page._past_datetime_from'), reverse=True)
        return events

    def _getEventFromUid(self, request, uid):
        merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
        event = getEventFromUid(request, uid) # might raise exception
        if event.get_ancestors().filter(id__in=[self.id, merged.id]).exists():
            # only return event if it is a descendant
            return event

    def _getAllEvents(self, request):
        merged = Page.objects.get(slug=self.MERGE_IN_SLUG)
        myEvents = getAllEvents(request, home=self, holidays=self.holidays)
        mergeEvents = getAllEvents(request, home=merged, holidays=self.holidays)
        events = myEvents + mergeEvents
        return events

class HomePage(Page):
    """HomePage displays the District-Calendar."""
    subpage_types = ['ls.joyous.SpecificCalendarPage']
    MERGE_IN_SLUG = "district-calendar"

    def route(self, request, path_components):
        subpage = Page.objects.get(slug=self.MERGE_IN_SLUG)
        try:
             return subpage.specific.route(request, path_components)
        except Http404:
            pass
        return super().route(request, path_components)

@skoontastic
Copy link
Author

Awesome, I will dig into this and let you know what happens. Hopefully it can be useful to you to expand the project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants