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 events(self, ret_mode=RET_MODE_ACCESSORS, expand=True, batch=True): res = [] if self.is_collection: ctx = self.default_context # Whatever sorting is defined, we're overriding it. sort_on = 'start' sort_order = None if self.mode in ('past', 'all'): sort_order = 'reverse' query = queryparser.parseFormquery( ctx, ctx.query, sort_on=sort_on, sort_order=sort_order) custom_query = self.request.get('contentFilter', {}) if 'start' not in query or 'end' not in query: # ... else don't show the navigation bar start, end = self._start_end start, end = _prepare_range(ctx, start, end) custom_query.update(start_end_query(start, end)) # BAM ... inject our filter viewlet values fc_adapter = ICollectionFilter(ctx) res = fc_adapter.filtered_result(pquery=query, batch=False, custom_query=custom_query) if res is None: # ORIGINAL res = ctx.results(batch=False, brains=True, custom_query=custom_query) if expand: # get start and end values from the query to ensure limited # listing for occurrences _filter_start = self.request.get('_filter_start') if _filter_start: # check for pickadate day filtering fs = DateTime(_filter_start).earliestTime() fe = DateTime(_filter_start).latestTime() start, end = self._expand_events_start_end( dict(query=[fs, fe], range='minmax'), None) else: start, end = self._expand_events_start_end( query.get('start') or custom_query.get('start'), query.get('end') or custom_query.get('end')) res = expand_events( res, ret_mode, start=start, end=end, sort=sort_on, sort_reverse=True if sort_order else False) else: res = self._get_events(ret_mode, expand=expand) if batch: b_start = self.b_start b_size = self.b_size res = Batch(res, size=b_size, start=b_start, orphan=self.orphan) return res
def results(self, custom_query, request_params): # Support for the Event Listing view from plone.app.event collection_layout = self.context.getLayout() default_view = self.context.restrictedTraverse(collection_layout) if isinstance(default_view, EventListing): mode = request_params.get("mode", "future") date = request_params.get("date", None) date = guess_date_from(date) if date else None start, end = start_end_from_mode(mode, date, self.collection) start, end = _prepare_range(self.collection, start, end) custom_query.update(start_end_query(start, end)) # TODO: expand events. better yet, let collection.results # do that return self.collection.results( batch=False, brains=True, custom_query=custom_query )
def events(self, ret_mode=RET_MODE_ACCESSORS, expand=False, batch=True): res = [] if self.is_collection: ctx = self.default_context # Whatever sorting is defined, we're overriding it. sort_on = 'start' sort_order = None if self.mode in ('past', 'all'): sort_order = 'reverse' query = queryparser.parseFormquery(ctx, ctx.query, sort_on=sort_on, sort_order=sort_order) custom_query = self.request.get('contentFilter', {}) if 'start' not in query or 'end' not in query: # ... else don't show the navigation bar start, end = self._start_end start, end = _prepare_range(ctx, start, end) custom_query.update(start_end_query(start, end)) res = ctx.results(batch=False, brains=True, custom_query=custom_query) if expand: # get start and end values from the query to ensure limited # listing for occurrences start, end = self._expand_events_start_end( query.get('start') or custom_query.get('start'), query.get('end') or custom_query.get('end')) # import pdb; pdb.set_trace() res = expand_events(res, ret_mode, start=start, end=end, sort=sort_on, sort_reverse=True if sort_order else False) else: res = self._get_events(ret_mode, expand=expand) if batch: b_start = self.b_start b_size = self.b_size res = Batch(res, size=b_size, start=b_start, orphan=self.orphan) return res
def events(self, ret_mode=RET_MODE_ACCESSORS, expand=False, batch=True): res = [] if self.is_collection: ctx = self.default_context # Whatever sorting is defined, we're overriding it. sort_on = 'start' sort_order = None if self.mode in ('past', 'all'): sort_order = 'reverse' query = queryparser.parseFormquery( ctx, ctx.query, sort_on=sort_on, sort_order=sort_order ) custom_query = self.request.get('contentFilter', {}) if 'start' not in query or 'end' not in query: # ... else don't show the navigation bar start, end = self._start_end start, end = _prepare_range(ctx, start, end) custom_query.update(start_end_query(start, end)) res = ctx.results( batch=False, brains=True, custom_query=custom_query ) if expand: # get start and end values from the query to ensure limited # listing for occurrences start, end = self._expand_events_start_end( query.get('start') or custom_query.get('start'), query.get('end') or custom_query.get('end') ) # import pdb; pdb.set_trace() res = expand_events( res, ret_mode, start=start, end=end, sort=sort_on, sort_reverse=True if sort_order else False ) else: res = self._get_events(ret_mode, expand=expand) if batch: b_start = self.b_start b_size = self.b_size res = Batch(res, size=b_size, start=b_start, orphan=self.orphan) return res
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 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) 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"" events_title = 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_title += accessor.title events_string += base % ( accessor.url, accessor.title, u' %s' % time if not whole_day else u'', u', ' if not whole_day and location else u'', u' %s' % 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': events_string, 'events_title': events_title, 'events': date_events}) return caldata
def get_filter_items(target_collection, group_by, filter_type=DEFAULT_FILTER_TYPE, narrow_down=False, show_count=False, view_name='', cache_enabled=True, request_params=None): request_params = request_params or {} custom_query = {} # Additional query to filter the collection collection = uuidToObject(target_collection) if not collection or not group_by: return None collection_url = collection.absolute_url() # Recursively transform all to unicode request_params = safe_decode(request_params) # Support for the Event Listing view from plone.app.event collection_layout = collection.getLayout() default_view = collection.restrictedTraverse(collection_layout) if isinstance(default_view, EventListing): mode = request_params.get('mode', 'future') date = request_params.get('date', None) date = guess_date_from(date) if date else None start, end = start_end_from_mode(mode, date, collection) start, end = _prepare_range(collection, start, end) custom_query.update(start_end_query(start, end)) # TODO: expand events. better yet, let collection.results # do that # Get index in question and the current filter value of this index, if set. groupby_criteria = getUtility(IGroupByCriteria).groupby idx = groupby_criteria[group_by]['index'] current_idx_value = safe_iterable(request_params.get(idx)) extra_ignores = [] if not narrow_down: # Additive filtering is about adding other filter values of the same # index. extra_ignores = [idx, idx + '_op'] urlquery = base_query(request_params, extra_ignores) # Get all collection results with additional filter defined by urlquery custom_query.update(urlquery) custom_query = make_query(custom_query) catalog_results = ICollection(collection).results( batch=False, brains=True, custom_query=custom_query) if narrow_down and show_count: # we need the extra_ignores to get a true count # even when narrow_down filters the display of indexed values # count_query allows us to do that true count count_query = {} count_urlquery = base_query(request_params, [idx, idx + '_op']) count_query.update(count_urlquery) catalog_results_fullcount = ICollection(collection).results( batch=False, brains=True, custom_query=count_query) if not catalog_results: return None # Attribute name for getting filter value from brain metadata_attr = groupby_criteria[group_by]['metadata'] # Optional modifier to set title from filter value display_modifier = groupby_criteria[group_by].get('display_modifier', None) # CSS modifier to set class on filter item css_modifier = groupby_criteria[group_by].get('css_modifier', None) # Value blacklist value_blacklist = groupby_criteria[group_by].get('value_blacklist', None) # Allow value_blacklist to be callables for runtime-evaluation value_blacklist = value_blacklist() if callable( value_blacklist) else value_blacklist # noqa # fallback to title sorted values sort_key_function = groupby_criteria[group_by].get( 'sort_key_function', lambda it: it['title'].lower()) grouped_results = {} for brain in catalog_results: # Get filter value val = getattr(brain, metadata_attr, None) if callable(val): val = val() # decode it to unicode val = safe_decode(val) # Make sure it's iterable, as it's the case for e.g. the subject index. val = safe_iterable(val) for filter_value in val: if filter_value is None or isinstance(filter_value, Missing): continue if value_blacklist and filter_value in value_blacklist: # Do not include blacklisted continue if filter_value in grouped_results: # Add counter, if filter value is already present grouped_results[filter_value]['count'] += 1 continue # Set title from filter value with modifications, # e.g. uuid to title title = filter_value if filter_value is not EMPTY_MARKER and callable(display_modifier): title = safe_decode(display_modifier(filter_value)) # Build filter url query _urlquery = urlquery.copy() # Allow deselection if filter_value in current_idx_value: _urlquery[idx] = [ it for it in current_idx_value if it != filter_value ] elif filter_type != 'single': # additive filter behavior _urlquery[idx] = current_idx_value + [filter_value] _urlquery[idx + '_op'] = filter_type # additive operator else: _urlquery[idx] = filter_value query_param = urlencode(safe_encode(_urlquery), doseq=True) url = '/'.join([ it for it in [ collection_url, view_name, '?' + query_param if query_param else None ] if it ]) # Set selected state selected = filter_value in current_idx_value css_class = 'filterItem {0}{1} {2}'.format( 'filter-' + idnormalizer.normalize(filter_value), ' selected' if selected else '', css_modifier(filter_value) if css_modifier else '', ) grouped_results[filter_value] = { 'title': title, 'url': url, 'value': filter_value, 'css_class': css_class, 'count': 1, 'selected': selected } # Entry to clear all filters urlquery_all = { k: v for k, v in list(urlquery.items()) if k not in (idx, idx + '_op') } if narrow_down and show_count: catalog_results = catalog_results_fullcount ret = [{ 'title': translate(_('subject_all', default=u'All'), context=getRequest()), 'url': u'{0}/?{1}'.format(collection_url, urlencode(safe_encode(urlquery_all), doseq=True)), 'value': 'all', 'css_class': 'filterItem filter-all', 'count': len(catalog_results), 'selected': idx not in request_params }] grouped_results = list(grouped_results.values()) if callable(sort_key_function): grouped_results = sorted(grouped_results, key=sort_key_function) ret += grouped_results return ret
def get_events(context, start=None, end=None, limit=None, ret_mode=RET_MODE_BRAINS, 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. :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, event objects or IEventAccessor object wrapper, depending on ret_mode. """ start, end = _prepare_range(context, start, end) query = {} query['object_provides'] = IEvent.__identifier__ query['object_provides'] = 'Products.ATContentTypes.interfaces.event.IATEvent' query.update(start_end_query(start, end)) 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'] # 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' # cannot limit before resorting or expansion, see below query.update(kw) cat = getToolByName(context, 'portal_catalog') result = cat(**query) # unfiltered catalog results are already sorted correctly on brain.start # filtering on start/end requires a resort, see docstring below and # p.a.event.tests.test_base_module.TestGetEventsDX.test_get_event_sort if sort in ('start', 'end'): result = filter_and_resort(context, result, start, end, sort, sort_reverse) # Limiting a start/end-sorted result set is possible here # and provides an important optimization BEFORE costly expansion if limit: result = result[:limit] if ret_mode in (RET_MODE_OBJECTS, RET_MODE_ACCESSORS): if expand is False: result = [_obj_or_acc(it.getObject(), ret_mode) for it in result] else: result = expand_events(result, ret_mode, start, end, sort, sort_reverse) # Limiting a non-start-sorted result set can only happen here if limit: result = result[:limit] return result
def _results(self, collection, request_params): ret = [] if collection: collection_layout = collection.getLayout() default_view = collection.restrictedTraverse(collection_layout) results = [] custom_query = {} if isinstance(default_view, EventListing): mode = request_params.get('mode', 'future') date = request_params.get('date', None) date = guess_date_from(date) if date else None start, end = start_end_from_mode(mode, date, collection) start, end = _prepare_range(collection, start, end) custom_query.update(start_end_query(start, end)) # TODO: expand events. better yet, let collection.results # do that idx = GROUPBY_CRITERIA[self.data.group_by]['index'] urlquery = {} urlquery.update(request_params) for it in (idx, 'b_start', 'b_size', 'batch', 'sort_on', 'limit'): # Remove problematic url parameters # And make sure to not filter by previously selected terms from # this index. This narrows down too much (except for dedicated # facetted searches - TODO) if it in urlquery: del urlquery[it] custom_query.update(urlquery) results = collection.results( batch=False, custom_query=custom_query ) if results: ret.append(dict( title=_('subject_all', default=u'All'), url=u'{0}/?{1}'.format( self.collection.absolute_url(), urlencode(urlquery) ), count=len(results), selected=idx not in request_params )) attr = GROUPBY_CRITERIA[self.data.group_by]['metadata'] mod = GROUPBY_CRITERIA[self.data.group_by]['display_modifier'] grouped_results = {} for item in results: val = getattr(item, attr, None) if callable(val): val = val() if not getattr(val, '__iter__', False): val = [val] for crit in val: if crit not in grouped_results: urlquery[idx] = crit title = _(safe_decode( mod(crit) if mod and crit is not EMPTY_MARKER else crit )) # mod modifies for displaying (e.g. uuid to title) # noqa url = u'{0}/?{1}'.format( self.collection.absolute_url(), urlencode(safe_encode(urlquery)) # need to be utf-8 encoded # noqa ) selected = safe_decode(request_params.get(idx)) == safe_decode(crit) # noqa sort_key = crit if crit else 'zzzzzz' crit_dict = { 'sort_key': sort_key.lower(), 'count': 1, 'title': title, 'url': url, 'selected': selected } grouped_results[crit] = crit_dict else: grouped_results[crit]['count'] += 1 ret += sorted( grouped_results.values(), key=lambda it: it['sort_key'] ) return ret
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) 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_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