def test_noexpand_start(self): # now+future events res = self.fmt( get_events(self.portal, expand=False, start=self.now, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u'Long Event', '2013-04-25 10:00:00', '2013-06-04 10:00:00'), (u'Now Event', '2013-05-05 10:00:00', '2013-05-05 11:00:00'), (u'Tomorrow event', '2013-05-06 10:00:00', '2013-05-06 23:59:59'), # Past Recur next occurrence: '2013-05-09 11:00:00' # Past Recur brain.start: '2013-04-25 11:00:00' (u'Past Recur', '2013-04-25 11:00:00', '2013-04-25 12:00:00'), (u'Future Event', '2013-05-15 10:00:00', '2013-05-15 11:00:00') ] self.assertEqual(res, expect, self.diff(res, expect)) # limited now+future events res = self.fmt( get_events(self.portal, expand=False, start=self.now, limit=3, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def test_recurrence_indexing(self): tz = pytz.timezone("Europe/Vienna") e1 = createContentInContainer( self.portal, 'plone.app.event.dx.event', title=u'event1', start=tz.localize(datetime(2011, 11, 11, 11, 0)), end=tz.localize(datetime(2011, 11, 11, 12, 0)), ) # When editing via behaviors, the attributes should also be available # on the context itself. IEventRecurrence(e1).recurrence = 'RRULE:FREQ=DAILY;COUNT=4' self.assertTrue(e1.recurrence == IEventRecurrence(e1).recurrence) e1.reindexObject() # get_events, no expanded occurrences result = get_events(self.portal) self.assertEqual(len(result), 1) # Get all the occurrences result = get_events( self.portal, start=tz.localize(datetime(2011, 11, 11, 11, 0)), ret_mode=base.RET_MODE_OBJECTS, expand=True ) self.assertEqual(len(result), 4)
def test_recurrence_indexing(self): tz = pytz.timezone("Europe/Vienna") e1 = createContentInContainer( self.portal, 'plone.app.event.dx.event', title='event1', start=tz.localize(datetime(2011, 11, 11, 11, 0)), end=tz.localize(datetime(2011, 11, 11, 12, 0)), ) # When editing via behaviors, the attributes should also be available # on the context itself. IEventRecurrence(e1).recurrence = 'RRULE:FREQ=DAILY;COUNT=4' self.assertTrue(e1.recurrence == IEventRecurrence(e1).recurrence) e1.reindexObject() # get_events, no expanded occurrences result = get_events(self.portal) self.assertEqual(len(result), 1) # Get all the occurrences result = get_events(self.portal, start=tz.localize(datetime(2011, 11, 11, 11, 0)), ret_mode=base.RET_MODE_OBJECTS, expand=True) self.assertEqual(len(result), 4)
def test_get_event_limit(self): """Test pull-request #93. The limit on the query has to be removed, because: - In the index, for each occurrence an index entry is created with reference to the originating event object (not an occurrence object - such doesn't exist). - The event object's start and end dates are the very first occurrence. Every other occurence is not stored anywhere but created on the fly from a recurrence rule. - Sorting on start sorts on the very first occurrence - this is where the problem originates. When doing a range search for events from now on and sorting for the start date, an event in the past might be sorted before tomorrow's event even if the next occurrence is somewhere in the future. Now, when limiting the result set with the catalog's sort_limit before expanding the recurrence to occurrences, tomorrow's event might fall out and the past event might be in. So limiting the result set can only be done after expanding the occurrences. Then we really have the correct order. """ factory = self.event_factory factory( container=self.portal, content_id='past_recur', title=u'Past Event recurring', start=self.past, end=self.past + self.duration, location=u"Dornbirn", recurrence='RRULE:FREQ=WEEKLY;COUNT=4', ) tomorrow = factory( container=self.portal, content_id='tomorrow', title=u'Tomorrow event', start=self.tomorrow, end=self.tomorrow + self.duration, open_end=True, location=u"Dornbirn", ) tomorrow.reindexObject() limit = get_events(self.portal, start=self.now, expand=True, ret_mode=RET_MODE_ACCESSORS, limit=3) all_ = get_events(self.portal, start=self.now, expand=True, ret_mode=RET_MODE_ACCESSORS) self.assertEqual([e.url for e in limit], [e.url for e in all_[:3]])
def test_get_event_limit(self): """Test pull-request #93. The limit on the query has to be removed, because: - In the index, for each occurrence an index entry is created with reference to the originating event object (not an occurrence object - such doesn't exist). - The event object's start and end dates are the very first occurrence. Every other occurence is not stored anywhere but created on the fly from a recurrence rule. - Sorting on start sorts on the very first occurrence - this is where the problem originates. When doing a range search for events from now on and sorting for the start date, an event in the past might be sorted before tomorrow's event even if the next occurrence is somewhere in the future. Now, when limiting the result set with the catalog's sort_limit before expanding the recurrence to occurrences, tomorrow's event might fall out and the past event might be in. So limiting the result set can only be done after expanding the occurrences. Then we really have the correct order. """ factory = self.event_factory factory( container=self.portal, content_id='past_recur', title=u'Past Event recurring', start=self.past, end=self.past + self.duration, location=u"Dornbirn", recurrence='RRULE:FREQ=WEEKLY;COUNT=4', ) # data_postprocessing normalization is not needed, as we values are set # correctly in the first place. tomorrow = factory( container=self.portal, content_id='tomorrow', title=u'Tomorrow event', start=self.tomorrow, end=self.tomorrow + self.duration, open_end=True, location=u"Dornbirn", ) # Normalize values and reindex, what normally the form would do # (especially, end time isn't set like open_end settings requests to. data_postprocessing_context(tomorrow) tomorrow.reindexObject() limit = get_events(self.portal, start=self.now, expand=True, ret_mode=RET_MODE_ACCESSORS, limit=3) all_ = get_events(self.portal, start=self.now, expand=True, ret_mode=RET_MODE_ACCESSORS) self.assertEqual([e.url for e in limit], [e.url for e in all_[:3]])
def test_get_occurrences(self): res = get_events(self.portal, ret_mode=3, expand=True) self.assertTrue(len(res) == 9) res = get_events(self.portal, start=self.now, ret_mode=3, expand=True) self.assertTrue(len(res) == 9) res = get_events(self.portal, ret_mode=3, expand=True, limit=5) self.assertTrue(len(res) == 5) self.assertTrue(IEventAccessor.providedBy(res[0]))
def test_get_event_limit(self): """Test pull-request #93. The limit on the query has to be removed, because: - In the index, for each occurrence an index entry is created with reference to the originating event object (not an occurrence object - such doesn't exist). - The event object's start and end dates are the very first occurrence. Every other occurence is not stored anywhere but created on the fly from a recurrence rule. - Sorting on start sorts on the very first occurrence - this is where the problem originates. When doing a range search for events from now on and sorting for the start date, an event in the past might be sorted before tomorrow's event even if the next occurrence is somewhere in the future. Now, when limiting the result set with the catalog's sort_limit before expanding the recurrence to occurrences, tomorrow's event might fall out and the past event might be in. So limiting the result set can only be done after expanding the occurrences. Then we really have the correct order. """ factory = self.event_factory() factory( container=self.portal, content_id='past_recur1', title=u'Past Event recurring 1', start=self.past, end=self.past + self.duration, location=u"Dornbirn", timezone=TEST_TIMEZONE, recurrence='RRULE:FREQ=WEEKLY;COUNT=4', ) factory( container=self.portal, content_id='tomorrow', title=u'Tomorrow event', start=self.tomorrow, end=self.tomorrow + self.duration, open_end=True, location=u"Dornbirn", timezone=TEST_TIMEZONE, ) limit = get_events(self.portal, start=self.now, expand=True, ret_mode=RET_MODE_ACCESSORS, limit=3) all_ = get_events(self.portal, start=self.now, expand=True, ret_mode=RET_MODE_ACCESSORS) self.assertEqual([e.url for e in limit], [e.url for e in all_[:3]]) self.portal.manage_delObjects(['past_recur1', 'tomorrow'])
def test_get_occurrences(self): res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, expand=True) self.assertEqual(len(res), 9) res = get_events(self.portal, start=self.now, ret_mode=RET_MODE_ACCESSORS, expand=True) self.assertEqual(len(res), 8) res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, expand=True, limit=5) self.assertEqual(len(res), 5) self.assertTrue(IEventAccessor.providedBy(res[0]))
def test_noexpand_end(self): # past+now events res = self.fmt(get_events(self.portal, expand=False, end=self.now, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u"Past Event", "2013-04-25 00:00:00", "2013-04-25 23:59:59"), (u"Long Event", "2013-04-25 10:00:00", "2013-06-04 10:00:00"), (u"Past Recur", "2013-04-25 11:00:00", "2013-04-25 12:00:00"), (u"Now Event", "2013-05-05 10:00:00", "2013-05-05 11:00:00"), ] self.assertEqual(res, expect, self.diff(res, expect)) # limited past+now events res = self.fmt(get_events(self.portal, expand=False, end=self.now, limit=3, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def test_noexpand_start_end(self): # only now events res = self.fmt(get_events(self.portal, expand=False, start=self.now, end=self.now, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u"Long Event", "2013-04-25 10:00:00", "2013-06-04 10:00:00"), (u"Now Event", "2013-05-05 10:00:00", "2013-05-05 11:00:00"), ] self.assertEqual(res, expect, self.diff(res, expect)) # limited now events res = self.fmt( get_events(self.portal, expand=False, start=self.now, end=self.now, limit=3, ret_mode=RET_MODE_ACCESSORS) ) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def test_expand_start_limit(self): # limited now+future occurrences res = self.fmt(get_events(self.portal, expand=True, start=self.now, limit=3, ret_mode=RET_MODE_ACCESSORS)) expect = self.occ[1:2] + self.occ[6:8] # includes ongoing long event self.assertEqual(res, expect, self.diff(res, expect))
def _get_events(self, ret_mode=3): context = self.context kw = {} if self.path: kw['path'] = self.path elif self.settings.current_folder_only: kw['path'] = '/'.join(context.getPhysicalPath()) #kw['b_start'] = self.b_start #kw['b_size'] = self.b_size if self.tags: kw['Subject'] = {'query': self.tags, 'operator': 'and'} if self.searchable_text: kw['SearchableText'] = self.searchable_text start, end = self._start_end sort = 'start' sort_reverse = False if self.mode in ('past', 'all'): sort_reverse = True return get_events(context, start=start, end=end, sort=sort, sort_reverse=sort_reverse, ret_mode=ret_mode, expand=True, **kw)
def _get_events(self, ret_mode=RET_MODE_ACCESSORS, expand=True): context = self.context kw = {} if self.uid: # In this case, restrict search for single event kw['UID'] = self.uid else: if self.path: kw['path'] = self.path else: # Search current and subsequent folders kw['path'] = '/'.join(context.getPhysicalPath()) if self.tags: kw['Subject'] = {'query': self.tags, 'operator': 'and'} if self.searchable_text: kw['SearchableText'] = self.searchable_text # kw['b_start'] = self.b_start # kw['b_size'] = self.b_size start, end = self._start_end sort = 'start' sort_reverse = False if self.mode in ('past', 'all'): sort_reverse = True return get_events(context, start=start, end=end, sort=sort, sort_reverse=sort_reverse, ret_mode=ret_mode, expand=expand, **kw)
def test_expand_all_limit(self): # limited occurrences res = self.fmt(get_events(self.portal, expand=True, limit=3, ret_mode=RET_MODE_ACCESSORS)) expect = self.occ[:3] self.assertEqual(res, expect, self.diff(res, expect))
def test_noexpand_all(self): # all events res = self.fmt(get_events(self.portal, expand=False, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u"Past Event", "2013-04-25 00:00:00", "2013-04-25 23:59:59"), (u"Long Event", "2013-04-25 10:00:00", "2013-06-04 10:00:00"), (u"Past Recur", "2013-04-25 11:00:00", "2013-04-25 12:00:00"), (u"Now Event", "2013-05-05 10:00:00", "2013-05-05 11:00:00"), (u"Tomorrow event", "2013-05-06 10:00:00", "2013-05-06 23:59:59"), (u"Future Event", "2013-05-15 10:00:00", "2013-05-15 11:00:00"), ] self.assertEqual(res, expect, self.diff(res, expect)) # limited events res = self.fmt(get_events(self.portal, expand=False, limit=3, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def get_all_events(self, batch=True): # Fall back to default language for local events kw = {} default_lang = api.portal.get_tool( "portal_languages").getDefaultLanguage() if ITranslatable.providedBy(self.context): if default_lang != self.context.Language(): portal = getSite() trans = ITranslationManager(self.context).get_translation( default_lang) root = getNavigationRootObject(trans, portal) kw['path'] = '/'.join(root.getPhysicalPath()) kw['Language'] = [default_lang, ''] start, end = self._start_end sort = 'start' sort_reverse = False if self.mode in ('past', 'all'): sort_reverse = True expand = True local_events = get_events( self.context, start=start, end=end, sort=sort, sort_reverse=sort_reverse, ret_mode=RET_MODE_ACCESSORS, expand=expand, **kw) remote_events = self._remote_events() reverse = self.mode == 'past' all_events = sorted(local_events + remote_events, key=lambda x: x.start, reverse=reverse) if batch: b_start = self.b_start b_size = self.b_size res = Batch(all_events, size=b_size, start=b_start, orphan=self.orphan) else: res = all_events return res
def test_recurrence_indexing(self): utc = pytz.utc self.portal.invokeFactory( 'plone.app.event.dx.event', 'event1', start=datetime(2011, 11, 11, 11, 0, tzinfo=utc), end=datetime(2011, 11, 11, 12, 0, tzinfo=utc), timezone='UTC', whole_day=False ) e1 = self.portal['event1'] e1rec = IEventRecurrence(e1) e1rec.recurrence = 'RRULE:FREQ=DAILY;COUNT=4' e1.reindexObject() # test, if the recurrence attribute is available on the context. # DRI needs that for indexing. self.assertTrue(e1.recurrence == e1rec.recurrence) # test, if the occurrences are indexed by DRI result = get_events( e1, start=datetime(2011, 11, 12, 11, 0, tzinfo=utc) ) self.assertTrue(len(result) == 1)
def test_recurrence_indexing(self): utc = pytz.utc self.portal.invokeFactory( 'plone.app.event.dx.event', 'event1', start=datetime(2011, 11, 11, 11, 0, tzinfo=utc), end=datetime(2011, 11, 11, 12, 0, tzinfo=utc), timezone='UTC', whole_day=False ) e1 = self.portal['event1'] e1rec = IEventRecurrence(e1) e1rec.recurrence = 'RRULE:FREQ=DAILY;COUNT=4' e1.reindexObject() # test, if the recurrence attribute is available on the context. # DRI needs that for indexing. self.assertTrue(e1.recurrence == e1rec.recurrence) # test, if the occurrences are indexed by DRI result = get_events( e1, start=datetime(2011, 11, 12, 11, 0, tzinfo=utc) ) self.assertTrue(len(result) == 1) self.portal.manage_delObjects(['event1'])
def _get_events(self, ret_mode=RET_MODE_ACCESSORS, expand=True): context = self.context kw = {} if self.path: kw['path'] = self.path elif self.settings.current_folder_only: kw['path'] = '/'.join(context.getPhysicalPath()) #kw['b_start'] = self.b_start #kw['b_size'] = self.b_size if self.tags: kw['Subject'] = {'query': self.tags, 'operator': 'and'} if self.searchable_text: kw['SearchableText'] = self.searchable_text start, end = self._start_end sort = 'start' sort_reverse = False if self.mode in ('past', 'all'): sort_reverse = True return get_events(context, start=start, end=end, sort=sort, sort_reverse=sort_reverse, ret_mode=ret_mode, expand=expand, **kw)
def test_construct_calendar(self): res = get_events(self.portal, ret_mode=2, expand=True) cal = construct_calendar(res) # keys are date-strings. # Should be more than one, but we can't exactly say how much. This # depends on the date, the test is run. E.g. on last day of month, only # long, past and now without recurrences are returned, others are in # next month. self.assertTrue(len(cal.keys()) > 1)
def test_noexpand_start(self): # now+future events res = self.fmt(get_events(self.portal, expand=False, start=self.now, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u"Long Event", "2013-04-25 10:00:00", "2013-06-04 10:00:00"), (u"Now Event", "2013-05-05 10:00:00", "2013-05-05 11:00:00"), (u"Tomorrow event", "2013-05-06 10:00:00", "2013-05-06 23:59:59"), # Past Recur next occurrence: '2013-05-09 11:00:00' # Past Recur brain.start: '2013-04-25 11:00:00' (u"Past Recur", "2013-04-25 11:00:00", "2013-04-25 12:00:00"), (u"Future Event", "2013-05-15 10:00:00", "2013-05-15 11:00:00"), ] self.assertEqual(res, expect, self.diff(res, expect)) # limited now+future events res = self.fmt(get_events(self.portal, expand=False, start=self.now, limit=3, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def calendar_from_collection(context): """Container/Event adapter. Returns an icalendar.Calendar object from a Collection. """ context = aq_inner(context) result = get_events(context) return construct_icalendar(context, result)
def test_expand_end_noongoing(self): # past events res = self.fmt(get_events(self.portal, expand=False, end=self.now, ongoing=False, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u'Past Event', '2013-04-25 00:00:00', '2013-04-25 23:59:59'), (u'Past Recur', '2013-04-25 11:00:00', '2013-04-25 12:00:00')] self.assertEqual(res, expect, self.diff(res, expect)) # limited past+now events res = self.fmt(get_events(self.portal, expand=False, end=self.now, limit=3, ongoing=False, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def test_noexpand_end(self): # past+now events res = self.fmt(get_events(self.portal, expand=False, end=self.now, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u'Past Event', '2013-04-25 00:00:00', '2013-04-25 23:59:59'), (u'Long Event', '2013-04-25 10:00:00', '2013-06-04 10:00:00'), (u'Past Recur', '2013-04-25 11:00:00', '2013-04-25 12:00:00'), (u'Now Event', '2013-05-05 10:00:00', '2013-05-05 11:00:00')] self.assertEqual(res, expect, self.diff(res, expect)) # limited past+now events res = self.fmt(get_events(self.portal, expand=False, end=self.now, limit=3, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def test_noexpand_all(self): # all events res = self.fmt(get_events(self.portal, expand=False, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u'Past Event', '2013-04-25 00:00:00', '2013-04-25 23:59:59'), (u'Long Event', '2013-04-25 10:00:00', '2013-06-04 10:00:00'), (u'Past Recur', '2013-04-25 11:00:00', '2013-04-25 12:00:00'), (u'Now Event', '2013-05-05 10:00:00', '2013-05-05 11:00:00'), (u'Tomorrow event', '2013-05-06 10:00:00', '2013-05-06 23:59:59'), (u'Future Event', '2013-05-15 10:00:00', '2013-05-15 11:00:00')] self.assertEqual(res, expect, self.diff(res, expect)) # limited events res = self.fmt(get_events(self.portal, expand=False, limit=3, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def test_noexpand_start_end(self): # only now events res = self.fmt(get_events(self.portal, expand=False, start=self.now, end=self.now, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u'Long Event', '2013-04-25 10:00:00', '2013-06-04 10:00:00'), (u'Now Event', '2013-05-05 10:00:00', '2013-05-05 11:00:00')] self.assertEqual(res, expect, self.diff(res, expect)) # limited now events res = self.fmt(get_events(self.portal, expand=False, start=self.now, end=self.now, limit=3, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def calendar_from_container(context): """Container adapter. Returns an icalendar.Calendar object from a Containerish context like a Folder. """ context = aq_inner(context) path = '/'.join(context.getPhysicalPath()) result = get_events(context, path=path) return construct_icalendar(context, result)
def test_expand_start_end_noongoing(self): # only today res = self.fmt(get_events(self.portal, expand=False, start=self.now, end=self.tomorrow, # NB ongoing=False, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u'Now Event', '2013-05-05 10:00:00', '2013-05-05 11:00:00')] self.assertEqual(res, expect, self.diff(res, expect)) # limited today res = self.fmt(get_events(self.portal, expand=False, start=self.now, end=self.tomorrow, # NB limit=3, ongoing=False, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def reply_events(self): """ use plone.app.event query for a better recurrences management """ ( start, end, fullobjects, b_size, b_start, query, sort_reverse, sort, limit, ) = self.generate_query_for_events() brains = get_events( start=start, end=end, context=self.context, sort=sort, sort_reverse=sort_reverse, limit=limit, **query, ) batch = HypermediaBatch(self.request, brains) results = {} results["@id"] = batch.canonical_url results["items_total"] = batch.items_total links = batch.links if links: results["batching"] = links results["items"] = [] for brain in batch: result = None if fullobjects: try: result = getMultiAdapter( (brain.getObject(), self.request), ISerializeToJson)(include_items=False) except KeyError: # Guard in case the brain returned refers to an object that # doesn't exists because it failed to uncatalog itself or # the catalog has stale cataloged objects for some reason logger.warning( "Brain getObject error: {} doesn't exist anymore". format( # noqa brain.getPath())) else: result = getMultiAdapter((brain, self.request), ISerializeToJsonSummary)() if result: results["items"].append(result) return results
def events(self): context = aq_inner(self.context) data = self.data kw = {} if data.search_base: kw["path"] = {"query": "%s%s" % ("/".join(self.portal.getPhysicalPath()), data.search_base)} if data.state: kw["review_state"] = data.state return get_events(context, start=localized_now(context), ret_mode=3, expand=True, limit=data.count, **kw)
def events(self): context = aq_inner(self.context) portal = api.portal.get() container = portal["termine"] kw = {} kw["path"] = dict(query="/".join(container.getPhysicalPath()), depth=1) kw["review_state"] = "published" items = get_events( context, start=localized_now(context), ret_mode=RET_MODE_ACCESSORS, expand=True, limit=3, **kw ) return items
def _get_events(self, ret_mode=3): context = self.context kw = {} if not self._all: kw['path'] = '/'.join(context.getPhysicalPath()) #kw['b_start'] = self.b_start #kw['b_size'] = self.b_size start, end = self._start_end return get_events(context, start=start, end=end, ret_mode=ret_mode, expand=True, **kw)
def events(self): context = aq_inner(self.context) data = self.data query = {} if data.state: query['review_state'] = data.state events = [] query.update(self.request.get('contentFilter', {})) search_base = self.search_base if ICollection and ICollection.providedBy(search_base): # Whatever sorting is defined, we're overriding it. query = queryparser.parseFormquery( search_base, search_base.query, sort_on='start', sort_order=None ) start = None if 'start' in query: start = query['start'] else: start = localized_now(context) end = None if 'end' in query: end = query['end'] start, end = _prepare_range(search_base, start, end) query.update(start_end_query(start, end)) events = search_base.results( batch=False, brains=True, custom_query=query, limit=data.count ) events = expand_events( events, ret_mode=RET_MODE_ACCESSORS, start=start, end=end, sort='start', sort_reverse=False ) events = events[:data.count] # limit expanded else: search_base_path = self.search_base_path if search_base_path: query['path'] = {'query': search_base_path} events = get_events( context, start=localized_now(context), ret_mode=RET_MODE_ACCESSORS, expand=True, limit=data.count, **query ) eventlist=[] for ev in events: hasimage = bool(getattr(ev.context, 'image', None)) eventlist.append((ev, hasimage)) return eventlist
def events(self): context = aq_inner(self.context) data = self.data query = {} if data.state: query['review_state'] = data.state events = [] query.update(self.request.get('contentFilter', {})) search_base = self.search_base if ICollection and ICollection.providedBy(search_base): # Whatever sorting is defined, we're overriding it. query = queryparser.parseFormquery(search_base, search_base.query, sort_on='start', sort_order=None) start = None if 'start' in query: start = query['start'] else: start = localized_now(context) end = None if 'end' in query: end = query['end'] start, end = _prepare_range(search_base, start, end) query.update(start_end_query(start, end)) events = search_base.results(batch=False, brains=True, custom_query=query, limit=data.count) events = expand_events(events, ret_mode=RET_MODE_ACCESSORS, start=start, end=end, sort='start', sort_reverse=False) events = events[:data.count] # limit expanded else: search_base_path = self.search_base_path if search_base_path: query['path'] = {'query': search_base_path} events = get_events(context, start=localized_now(context), ret_mode=RET_MODE_ACCESSORS, expand=True, limit=data.count, **query) return events
def test_construct_calendar(self): res = get_events(self.portal, ret_mode=RET_MODE_OBJECTS, expand=True) cal = construct_calendar(res) # keys are date-strings. def _num_events(values): num = 0 for val in values: num += len(val) return num # The long_event occurs on every day in the resulting calendar data # structure. self.assertEqual(_num_events(cal.values()), 48) # Test with range # # Completly outside range and start, end given as datetime cal = construct_calendar( res, start=datetime(2000, 1, 1, 10, 0), end=datetime(2000, 1, 2, 10, 0) ) self.assertEqual(_num_events(cal.values()), 0) # Within range cal = construct_calendar( res, start=date(2013, 5, 1), end=date(2013, 5, 31) ) self.assertEqual(_num_events(cal.values()), 35) # First day must also be set in the calendar self.assertTrue('2013-05-01' in cal.keys()) # invalid start def _invalid_start(): return construct_calendar( res, start='invalid', end=datetime(2000, 1, 2, 10, 0) ) self.assertRaises(AssertionError, _invalid_start) # invalid end def _invalid_end(): return construct_calendar( res, start=datetime(2000, 1, 1, 10, 0), end='invalid' ) self.assertRaises(AssertionError, _invalid_end)
def _query_future_events(self): """Get all future events from this folder.""" now = localized_now() path = '/'.join(self.context.getPhysicalPath()) future_events = get_events(context=self.context, path=path, start=now, ret_mode=RET_MODE_OBJECTS, expand=True, sort_on='start') return future_events
def test_expand_start_noongoing(self): # now+future events res = self.fmt(get_events(self.portal, expand=False, start=self.now, ongoing=False, ret_mode=RET_MODE_ACCESSORS)) expect = [ (u'Now Event', '2013-05-05 10:00:00', '2013-05-05 11:00:00'), (u'Tomorrow event', '2013-05-06 10:00:00', '2013-05-06 23:59:59'), # Past Recur next occurrence: '2013-05-09 11:00:00' # Past Recur brain.start: '2013-04-25 11:00:00' (u'Past Recur', '2013-04-25 11:00:00', '2013-04-25 12:00:00'), (u'Future Event', '2013-05-15 10:00:00', '2013-05-15 11:00:00')] self.assertEqual(res, expect, self.diff(res, expect)) # limited now+future events res = self.fmt(get_events(self.portal, expand=False, start=self.now, limit=3, ongoing=False, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, expect[:3], self.diff(res, expect[:3]))
def events(self): context = aq_inner(self.context) data = self.data kw = {} if data.search_base: kw['path'] = {'query': '%s%s' % ( '/'.join(self.portal.getPhysicalPath()), data.search_base)} if data.state: kw['review_state'] = data.state return get_events(context, start=localized_now(context), ret_mode=3, expand=True, limit=data.count, **kw)
def published_events_expanded(self): """ Return expanded ongoing events, i.e. taking into account their occurrences in case they are recurrent events. """ return [self.event_to_view_obj(event) for event in get_events( self.context, ret_mode=2, start=localized_now(), expand=True, sort='start', limit=self.data.count, review_state=self.data.state)]
def events(self): context = aq_inner(self.context) data = self.data kw = {} search_base_path = self.search_base_path() if search_base_path: kw['path'] = {'query': search_base_path} if data.state: kw['review_state'] = data.state return get_events(context, start=localized_now(context), ret_mode=RET_MODE_ACCESSORS, expand=True, limit=data.count, **kw)
def get_all_events(self, batch=True): # Fall back to default language for local events kw = {} default_lang = api.portal.get_tool( "portal_languages").getDefaultLanguage() if ITranslatable.providedBy(self.context): if default_lang != self.context.Language(): portal = getSite() trans = ITranslationManager( self.context).get_translation(default_lang) root = getNavigationRootObject(trans, portal) kw['path'] = '/'.join(root.getPhysicalPath()) kw['Language'] = [default_lang, ''] start, end = self._start_end sort = 'start' sort_reverse = False if self.mode in ('past', 'all'): sort_reverse = True expand = True local_events = get_events(self.context, start=start, end=end, sort=sort, review_state='published', sort_reverse=sort_reverse, ret_mode=RET_MODE_ACCESSORS, expand=expand, **kw) remote_events = self._remote_events() reverse = self.mode == 'past' all_events = sorted(local_events + remote_events, key=lambda x: x.start, reverse=reverse) if batch: b_start = self.b_start b_size = self.b_size res = Batch(all_events, size=b_size, start=b_start, orphan=self.orphan) else: res = all_events return res
def events(self): context = aq_inner(self.context) data = self.data kw = {} if data.search_base: kw['path'] = { 'query': '%s%s' % ('/'.join(self.portal.getPhysicalPath()), data.search_base) } if data.state: kw['review_state'] = data.state return get_events(context, start=localized_now(context), ret_mode=RET_MODE_ACCESSORS, expand=True, limit=data.count, **kw)
def all_events(self): events = get_events(self.context, ret_mode=RET_MODE_ACCESSORS, expand=True, start=DateTime(self.request.get('start')), end=DateTime(self.request.get('end'))) for event in events: duration = event.end - event.start yield {"id": "UID_%s" % (event.uid), "title": event.title, "location": event.location, "start": rfc822_dt(event.start), "end": rfc822_dt(event.end), "url": event.url, "editable": False, "allDay": (event.whole_day or duration > timedelta(seconds=86390)), "className": '', "description": event.description}
def test_get_events(self): # whole range res = get_events(self.portal) self.assertEqual(len(res), 4) res = get_events(self.portal, start=self.past, end=self.future) self.assertEqual(len(res), 4) res = get_events(self.portal, end=self.future) self.assertEqual(len(res), 4) res = get_events(self.portal, start=self.past) self.assertEqual(len(res), 4) # Limit res = get_events(self.portal, limit=2) self.assertEqual(len(res), 2) # Return objects res = get_events(self.portal, ret_mode=RET_MODE_OBJECTS) self.assertTrue(IEvent.providedBy(res[0])) # Return IEventAccessor res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS) self.assertTrue(IEventAccessor.providedBy(res[0])) # Test sorting self.assertTrue(res[0].start < res[-1].start) # Test reversed sorting res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, sort_reverse=True) self.assertTrue(res[0].start > res[-1].start) # Test sort_on res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, sort="start") self.assertEqual( [it.title for it in res][2:], [u'Now Event', u'Future Event'] ) res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, sort="end") self.assertEqual( [it.title for it in res], [u'Past Event', u'Now Event', u'Future Event', u'Long Event'] ) # Test expansion res = get_events(self.portal, ret_mode=RET_MODE_OBJECTS, expand=True) self.assertEqual(len(res), 8) res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, expand=True) self.assertEqual(len(res), 8) # Test sorting self.assertTrue(res[0].start < res[-1].start) res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, expand=True, sort_reverse=True) # Test sorting self.assertTrue(res[0].start > res[-1].start) # only on now-date res = get_events(self.portal, start=self.now, end=self.now) self.assertEqual(len(res), 2) # only on now-date as date # NOTE: converting self.now to python datetime to allow testing also # with dates as Zope DateTime objects. res = get_events(self.portal, start=pydt(self.now).date(), end=pydt(self.now).date()) self.assertEqual(len(res), 2) # only on past date res = get_events(self.portal, start=self.past, end=self.past) self.assertEqual(len(res), 2) # one recurrence occurrence in far future res = get_events(self.portal, start=self.far, end=self.far) self.assertEqual(len(res), 1) # from now on res = get_events(self.portal, start=self.now) self.assertEqual(len(res), 3) # until now res = get_events(self.portal, end=self.now) self.assertEqual(len(res), 3) # in subfolder path = '/'.join(self.portal.sub.getPhysicalPath()) res = get_events(self.portal, path=path) self.assertEqual(len(res), 1)
def cal_data(self): """Calendar iterator over weeks and days of the month to display. """ context = aq_inner(self.context) today = localized_today(context) year, month = self.year_month_display() monthdates = [dat for dat in self.cal.itermonthdates(year, month)] start = monthdates[0] end = monthdates[-1] data = self.data query = {} if data.state: query['review_state'] = data.state events = [] query.update(self.request.get('contentFilter', {})) search_base = self.search_base if ICollection and ICollection.providedBy(search_base): # Whatever sorting is defined, we're overriding it. query = queryparser.parseFormquery( search_base, search_base.query, sort_on='start', sort_order=None ) # restrict start/end with those from query, if given. if 'start' in query and query['start'] > start: start = query['start'] if 'end' in query and query['end'] < end: end = query['end'] start, end = _prepare_range(search_base, start, end) query.update(start_end_query(start, end)) events = search_base.results( batch=False, brains=True, custom_query=query ) events = expand_events( events, ret_mode=RET_MODE_OBJECTS, start=start, end=end, sort='start', sort_reverse=False ) else: search_base_path = self.search_base_path if search_base_path: query['path'] = {'query': search_base_path} events = get_events(context, start=start, end=end, ret_mode=RET_MODE_OBJECTS, expand=True, **query) #today += datetime.timedelta(days=1) cal_dict = construct_calendar(events, start=today, end=end) # [[day1week1, day2week1, ... day7week1], [day1week2, ...]] caldata = [[]] for dat in monthdates: if len(caldata[-1]) == 7: caldata.append([]) date_events = None isodat = dat.isoformat() if isodat in cal_dict: date_events = cal_dict[isodat] events_string_list = [] if date_events: for occ in date_events: accessor = IEventAccessor(occ) location = accessor.location whole_day = accessor.whole_day time = accessor.start.time().strftime('%H:%M') # TODO: make 24/12 hr format configurable events_string_list.append( u'{0}{1}{2}{3}'.format( accessor.title, u' {0}'.format(time) if not whole_day else u'', u', ' if not whole_day and location else u'', u' {0}'.format(location) if location else u'' ) ) caldata[-1].append( {'date': dat, 'day': dat.day, 'prev_month': dat.month < month, 'next_month': dat.month > month, 'today': dat.year == today.year and dat.month == today.month and dat.day == today.day, 'date_string': u"%s-%s-%s" % (dat.year, dat.month, dat.day), 'events_string': u' | '.join(events_string_list), 'events': date_events}) return caldata
def _get_occs(self): date = guess_date_from(self.date) if date: start, end = start_end_from_mode('day', date, self.context) query = {} query['review_state'] = self.data.state search_base_path = self.search_base_path if search_base_path: query['path'] = {'query': search_base_path} list_events = [] events = get_events(self.context, start=start, end=end, sort='start', sort_reverse=False, ret_mode=RET_MODE_OBJECTS, expand=True, **query) today = datetime.datetime.today().date() for occ in events: if IOccurrence.providedBy(occ): occurrence_id = occ.id event = aq_parent(occ) occ_data = ITicketOccurrenceData(event) occs = occ_data.ticket_occurrences(occurrence_id) if occs: occurrence_ticket = occs[0] item_stock = get_item_stock(occurrence_ticket) if item_stock: stock = item_stock.available else: stock = 0 is_today = occ.start.date() == today new_event = { "start": occ.start, "uid": occurrence_ticket.UID(), "stock": stock, "is_today": is_today } list_events.append(new_event) elif IBuyableEvent.providedBy(occ): occ_data = ITicketOccurrenceData(occ) occs = occ_data.tickets if occs: occurrence_ticket = occs[0] item_stock = get_item_stock(occurrence_ticket) if item_stock: stock = item_stock.available else: stock = 0 is_today = occ.start.date() == today new_event = { "start": occ.start, "uid": occurrence_ticket.UID(), "stock": stock, "is_today": is_today } list_events.append(new_event) else: print 'NOT AVAILABLE' return list_events else: return []
def cal_data(self): """Calendar iterator over weeks and days of the month to display. """ context = aq_inner(self.context) today = localized_today(context) year, month = self.year_month_display() monthdates = [dat for dat in self.cal.itermonthdates(year, month)] data = self.data query_kw = {} if data.search_base: portal = getToolByName(context, 'portal_url').getPortalObject() query_kw['path'] = { 'query': '%s%s' % ('/'.join(portal.getPhysicalPath()), data.search_base) } if data.state: query_kw['review_state'] = data.state start = monthdates[0] end = monthdates[-1] events = get_events(context, start=start, end=end, ret_mode=2, expand=True, **query_kw) cal_dict = construct_calendar(events, start=start, end=end) # [[day1week1, day2week1, ... day7week1], [day1week2, ...]] caldata = [[]] for dat in monthdates: if len(caldata[-1]) == 7: caldata.append([]) date_events = None isodat = dat.isoformat() if isodat in cal_dict: date_events = cal_dict[isodat] events_string = u"" if date_events: for occ in date_events: accessor = IEventAccessor(occ) location = accessor.location whole_day = accessor.whole_day time = accessor.start.time().strftime('%H:%M') # TODO: make 24/12 hr format configurable base = u'<a href="%s"><span class="title">%s</span>'\ u'%s%s%s</a>' events_string += base % ( accessor.url, accessor.title, not whole_day and u' %s' % time or u'', not whole_day and location and u', ' or u'', location and u' %s' % location or u'') caldata[-1].append( {'date': dat, 'day': dat.day, 'prev_month': dat.month < month, 'next_month': dat.month > month, 'today': dat.year == today.year and\ dat.month == today.month and\ dat.day == today.day, 'date_string': u"%s-%s-%s" % (dat.year, dat.month, dat.day), 'events_string': events_string, 'events': date_events}) return caldata
def test_expand_all(self): # all occurrences, sorted by start res = self.fmt(get_events(self.portal, expand=True, ret_mode=RET_MODE_ACCESSORS)) self.assertEqual(res, self.occ)