Exemplo n.º 1
0
def expand_events(events,
                  ret_mode,
                  start=None,
                  end=None,
                  sort=None,
                  sort_reverse=None):
    """Expand to the recurrence occurrences of a given set of events.

    :param events: IEvent based objects or IEventAccessor object wrapper.

    :param ret_mode: Return type of search results. These options are
                     available:

                         * 2 (objects): Return results as IEvent and/or
                                        IOccurrence objects.
                         * 3 (accessors): Return results as IEventAccessor
                                          wrapper objects.
                     Option "1" (brains) is not supported.

    :type ret_mode: integer [2|3]

    :param start: Date, from which on events should be expanded.
    :type start: Python datetime.

    :param end: Date, until which events should be expanded.
    :type end: Python datetime

    :param sort: Object or IEventAccessor Attribute to sort on.
    :type sort: string

    :param sort_reverse: Change the order of the sorting.
    :type sort_reverse: boolean
    """
    assert (ret_mode is not RET_MODE_BRAINS)

    exp_result = []
    for it in events:
        obj = it.getObject() if getattr(it, 'getObject', False) else it
        if IEventRecurrence.providedBy(obj):
            occurrences = [
                _obj_or_acc(occ, ret_mode)
                for occ in IRecurrenceSupport(obj).occurrences(start, end)
            ]
        elif IEvent.providedBy(obj):
            occurrences = [_obj_or_acc(obj, ret_mode)]
        else:
            # No IEvent based object. Could come from a collection.
            continue
        exp_result += occurrences
    if sort:
        exp_result.sort(key=lambda x: _get_compare_attr(x, sort))
    if sort_reverse:
        exp_result.reverse()
    return exp_result
Exemplo n.º 2
0
    def test_implementsInterfaces(self):
        """Test if an ATEvent object implements all relevant interfaces.

        """
        self.assertTrue(IEvent.providedBy(self.obj))
        self.assertTrue(IEventRecurrence.providedBy(self.obj))
        self.assertTrue(IATEvent.providedBy(self.obj))
        self.assertTrue(IATEventRecurrence.providedBy(self.obj))

        self.assertTrue(IATEvent_ATCT.providedBy(self.obj))
        self.assertTrue(verifyObject(IATEvent_ATCT, self.obj))
Exemplo n.º 3
0
def expand_events(events, ret_mode,
                  start=None, end=None,
                  sort=None, sort_reverse=None):
    """Expand to the recurrence occurrences of a given set of events.

    :param events: IEvent based objects or IEventAccessor object wrapper.

    :param ret_mode: Return type of search results. These options are
                     available:

                         * 2 (objects): Return results as IEvent and/or
                                        IOccurrence objects.
                         * 3 (accessors): Return results as IEventAccessor
                                          wrapper objects.
                     Option "1" (brains) is not supported.

    :type ret_mode: integer [2|3]

    :param start: Date, from which on events should be expanded.
    :type start: Python datetime.

    :param end: Date, until which events should be expanded.
    :type end: Python datetime

    :param sort: Object or IEventAccessor Attribute to sort on.
    :type sort: string

    :param sort_reverse: Change the order of the sorting.
    :type sort_reverse: boolean
    """
    assert(ret_mode is not RET_MODE_BRAINS)

    exp_result = []
    for it in events:
        obj = it.getObject() if getattr(it, 'getObject', False) else it
        if IEventRecurrence.providedBy(obj):
            occurrences = [_obj_or_acc(occ, ret_mode) for occ in
                           IRecurrenceSupport(obj).occurrences(start, end)]
        elif IEvent.providedBy(obj):
            occurrences = [_obj_or_acc(obj, ret_mode)]
        else:
            # No IEvent based object. Could come from a collection.
            continue
        exp_result += occurrences
    if sort:
        exp_result.sort(key=lambda x: _get_compare_attr(x, sort))
    if sort_reverse:
        exp_result.reverse()
    return exp_result
Exemplo n.º 4
0
def get_occurrences_by_date(context, range_start=None, range_end=None, **kw):
    """Return a dictionary with dates in a given timeframe as keys and the
    actual occurrences for that date for building calendars.

    :param context: [required] A context object.
    :type context: Content object
    :param range_start: Date, from which on events should be searched.
    :type range_start: Python datetime.
    :param range_end: Date, until which events should be searched.
    :type range_end: Python datetime
    :returns: Dictionary with dates keys and occurrences as values.
    :rtype: dict

    """
    range_start, range_end = _prepare_range(context, range_start, range_end)

    events = get_portal_events(context, range_start, range_end, **kw)
    events_by_date = {}
    for event in events:
        obj = event.getObject()

        if IEventRecurrence.providedBy(obj):
            occurrences = IRecurrenceSupport(obj).occurrences(
                range_start, range_end)
        else:
            occurrences = [obj]

        for occ in occurrences:
            accessor = IEventAccessor(occ)
            start_str = datetime.strftime(accessor.start, '%Y-%m-%d')
            # TODO: add span_events parameter to include dates btw. start
            # and end also. for events lasting longer than a day...
            if start_str not in events_by_date:
                events_by_date[start_str] = [occ]
            else:
                events_by_date[start_str].append(occ)
    return events_by_date
Exemplo n.º 5
0
def get_events(context, start=None, end=None, limit=None,
               ret_mode=1, expand=False,
               sort='start', sort_reverse=False, **kw):
    """Return all events as catalog brains, possibly within a given
    timeframe.

    :param context: [required] A context object.
    :type context: Content object

    :param start: Date, from which on events should be searched.
    :type start: Python datetime.

    :param end: Date, until which events should be searched.
    :type end: Python datetime

    :param limit: Number of items to be returned.
    :type limit: integer

    :param ret_mode: Return type of search results. These options are
                     available:
                         * 1 (brains): Return results as catalog brains.
                         * 2 (objects): Return results as IEvent and/or
                                        IOccurrence objects.
                         * 3 (accessors): Return results as IEventAccessor
                                          wrapper objects.
    :type ret_mode: integer [1|2|3]

    :param expand: Expand the results to all occurrences (within a timeframe,
                   if given). With this option set to True, the resultset also
                   includes the event's recurrence occurrences and is sorted by
                   the start date.
                   Only available in ret_mode 2 (objects) and 3 (accessors).
    :type expand: boolean

    :param sort: Catalog index id to sort on. Not available with expand=True.
    :type sort: string

    :param sort_reverse: Change the order of the sorting.
    :type sort_reverse: boolean

    :returns: Portal events, matching the search criteria.
    :rtype: catalog brains

    """
    start, end = _prepare_range(context, start, end)

    query = {}
    query['object_provides'] = IEvent.__identifier__

    if 'path' not in kw:
        # limit to the current navigation root, usually (not always) site
        portal = getSite()
        navroot = getNavigationRootObject(context, portal)
        query['path'] = '/'.join(navroot.getPhysicalPath())
    else:
        query['path'] = kw['path']

    if start:
        # All events from start date ongoing:
        # The minimum end date of events is the date from which we search.
        query['end'] = {'query': start, 'range': 'min'}
    if end:
        # All events until end date:
        # The maximum start date must be the date until we search.
        query['start'] = {'query': end, 'range': 'max'}

    # Sorting
    # In expand mode we sort after calculation of recurrences again. But we
    # need to leave this sorting here in place, since no sort definition could
    # lead to arbitrary results when limiting with sort_limit.
    query['sort_on'] = sort
    if sort_reverse:
        query['sort_order'] = 'reverse'

    # XXX Passing the limit to the catalog can cause events that should be in
    # the results to be missing from the results.
    #if limit:
    #    query['sort_limit'] = limit

    query.update(kw)

    cat = getToolByName(context, 'portal_catalog')
    result = cat(**query)

    # Helper functions
    def _obj_or_acc(obj, ret_mode):
        if ret_mode == 2:
            return obj
        elif ret_mode == 3:
            return IEventAccessor(obj)

    def _get_compare_attr(obj, attr):
        val = getattr(obj, attr, None)
        if safe_callable(val):
            val = val()
        if isinstance(val, DateTime):
            val = pydt(val)
        return val

    if ret_mode in (2, 3) and expand == False:
        result = [_obj_or_acc(it.getObject(), ret_mode) for it in result]
    elif ret_mode in (2, 3) and expand == True:
        exp_result = []
        for it in result:
            obj = it.getObject()
            if IEventRecurrence.providedBy(obj):
                occurrences = [_obj_or_acc(occ, ret_mode) for occ in
                               IRecurrenceSupport(obj).occurrences(start, end)]
            else:
                occurrences = [_obj_or_acc(obj, ret_mode)]
            exp_result += occurrences
        if sort:
            # support AT and DX without wrapped by IEventAccessor (mainly for
            # sorting after "start" or "end").
            exp_result.sort(key=lambda x: _get_compare_attr(x, sort))
        if sort_reverse:
            exp_result.reverse()
        result = exp_result

    if limit:
        # Expanded events as well as catalog search results (which might not
        # exactly be limited by the query) must be limited again.
        result = result[:limit]

    return result
Exemplo n.º 6
0
def get_events(context,
               start=None,
               end=None,
               limit=None,
               ret_mode=1,
               expand=False,
               sort='start',
               sort_reverse=False,
               **kw):
    """Return all events as catalog brains, possibly within a given
    timeframe.

    :param context: [required] A context object.
    :type context: Content object

    :param start: Date, from which on events should be searched.
    :type start: Python datetime.

    :param end: Date, until which events should be searched.
    :type end: Python datetime

    :param limit: Number of items to be returned.
    :type limit: integer

    :param ret_mode: Return type of search results. These options are
                     available:
                         * 1 (brains): Return results as catalog brains.
                         * 2 (objects): Return results as IEvent and/or
                                        IOccurrence objects.
                         * 3 (accessors): Return results as IEventAccessor
                                          wrapper objects.
    :type ret_mode: integer [1|2|3]

    :param expand: Expand the results to all occurrences (within a timeframe,
                   if given). With this option set to True, the resultset also
                   includes the event's recurrence occurrences and is sorted by
                   the start date.
                   Only available in ret_mode 2 (objects) and 3 (accessors).
    :type expand: boolean

    :param sort: Catalog index id to sort on. Not available with expand=True.
    :type sort: string

    :param sort_reverse: Change the order of the sorting.
    :type sort_reverse: boolean

    :returns: Portal events, matching the search criteria.
    :rtype: catalog brains

    """
    start, end = _prepare_range(context, start, end)

    query = {}
    query['object_provides'] = IEvent.__identifier__

    if 'path' not in kw:
        # limit to the current navigation root, usually (not always) site
        portal = getSite()
        navroot = getNavigationRootObject(context, portal)
        query['path'] = '/'.join(navroot.getPhysicalPath())
    else:
        query['path'] = kw['path']

    if start:
        # All events from start date ongoing:
        # The minimum end date of events is the date from which we search.
        query['end'] = {'query': start, 'range': 'min'}
    if end:
        # All events until end date:
        # The maximum start date must be the date until we search.
        query['start'] = {'query': end, 'range': 'max'}

    # Sorting
    # In expand mode we sort after calculation of recurrences again. But we
    # need to leave this sorting here in place, since no sort definition could
    # lead to arbitrary results when limiting with sort_limit.
    query['sort_on'] = sort
    if sort_reverse:
        query['sort_order'] = 'reverse'

    if limit:
        query['sort_limit'] = limit

    query.update(kw)

    cat = getToolByName(context, 'portal_catalog')
    result = cat(**query)

    # Helper functions
    def _obj_or_acc(obj, ret_mode):
        if ret_mode == 2:
            return obj
        elif ret_mode == 3:
            return IEventAccessor(obj)

    def _get_compare_attr(obj, attr):
        val = getattr(obj, attr, None)
        if safe_callable(val):
            val = val()
        if isinstance(val, DateTime):
            val = pydt(val)
        return val

    if ret_mode in (2, 3) and expand == False:
        result = [_obj_or_acc(it.getObject(), ret_mode) for it in result]
    elif ret_mode in (2, 3) and expand == True:
        exp_result = []
        for it in result:
            obj = it.getObject()
            if IEventRecurrence.providedBy(obj):
                occurrences = [
                    _obj_or_acc(occ, ret_mode)
                    for occ in IRecurrenceSupport(obj).occurrences(start, end)
                ]
            else:
                occurrences = [_obj_or_acc(obj, ret_mode)]
            exp_result += occurrences
        if sort:
            # support AT and DX without wrapped by IEventAccessor (mainly for
            # sorting after "start" or "end").
            exp_result.sort(key=lambda x: _get_compare_attr(x, sort))
        if sort_reverse:
            exp_result.reverse()
        result = exp_result

    if limit:
        # Expanded events as well as catalog search results (which might not
        # exactly be limited by the query) must be limited again.
        result = result[:limit]

    return result