def set_content_filter(context, event): """Set the content filter dictionary on the request, built from request parameters to narrow the results of the collection. """ req = event.request if 'collectionfilter' not in req.form or 'contentFilter' in req: return # We leave collectionfilter=1 in req.form so that it gets put into batch links content_filter = make_query(req.form) event.request['contentFilter'] = content_filter
def set_content_filter(context, event): """Set the content filter dictionary on the request, built from request parameters to narrow the results of the collection. """ req = event.request if 'collectionfilter' not in req.form: return del req.form['collectionfilter'] content_filter = make_query(req.form) event.request['contentFilter'] = content_filter
def locations(self): custom_query = {} # Additional query to filter the collection collection = uuidToObject(self.settings.target_collection) if not collection: return None # Recursively transform all to unicode request_params = safe_decode(self.top_request.form or {}) # Get all collection results with additional filter # defined by urlquery custom_query = base_query(request_params) custom_query = make_query(custom_query) return ICollection(collection).results(batch=False, brains=True, custom_query=custom_query)
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 test_and_filter_type(self): self.assertEqual(len(self.collection.results()), 3) result = get_filter_items(self.collection_uid, "Subject", cache_enabled=False) self.assertEqual(len(result), 4) self.assertEqual(get_data_by_val(result, "all")["count"], 3) self.assertEqual(get_data_by_val(result, "all")["selected"], True) self.assertEqual(get_data_by_val(result, u"Süper")["count"], 2) self.assertEqual(get_data_by_val(result, u"Evänt")["count"], 1) self.assertEqual(get_data_by_val(result, u"Dokumänt")["count"], 2) # Test url self.assertEqual(qs(result, u"Süper"), {"Subject": u"Süper"}) catalog_results = ICollection(self.collection).results( batch=False, brains=True, custom_query=make_query(qs(result, u"Süper"))) self.assertEqual(len(catalog_results), 2) result = get_filter_items( self.collection_uid, "Subject", request_params={"Subject": u"Süper"}, filter_type="and", cache_enabled=False, ) self.assertEqual(len(result), 4) self.assertEqual(get_data_by_val(result, "all")["count"], 3) # TODO: I'm not sure these counts are correct. It should represent how many results you will get if you click # so should be smaller than this but I guess you need to turn on narrow down for that? self.assertEqual(get_data_by_val(result, u"Süper")["count"], 2) self.assertEqual(get_data_by_val(result, u"Evänt")["count"], 1) self.assertEqual(get_data_by_val(result, u"Dokumänt")["count"], 2) self.assertEqual(get_data_by_val(result, u"Süper")["selected"], True) self.assertEqual(qs(result, u"Süper"), {}) self.assertEqual( qs(result, u"Dokumänt"), { "Subject_op": "and", "Subject": [u"Süper", u"Dokumänt"] }, ) self.assertEqual(qs(result, u"Evänt"), { "Subject_op": "and", "Subject": [u"Süper", u"Evänt"] }) # Narrow down by 2 catalog_results = ICollection(self.collection).results( batch=False, brains=True, custom_query=make_query(qs(result, u"Dokumänt"))) self.assertEqual(len(catalog_results), 1) result = get_filter_items( self.collection_uid, "Subject", request_params={"Subject": [u"Süper", u"Dokumänt"]}, filter_type="and", cache_enabled=False, ) self.assertEqual(len(result), 4) self.assertEqual(get_data_by_val(result, "all")["count"], 3) self.assertEqual(get_data_by_val(result, u"Süper")["count"], 2) self.assertEqual(get_data_by_val(result, u"Evänt")["count"], 1) self.assertEqual(get_data_by_val(result, u"Dokumänt")["count"], 2) self.assertEqual(get_data_by_val(result, u"Süper")["selected"], True) self.assertEqual( get_data_by_val(result, u"Dokumänt")["selected"], True) self.assertEqual(qs(result, u"Süper"), {"Subject": u"Dokumänt"}) self.assertEqual(qs(result, u"Dokumänt"), {"Subject": u"Süper"}) self.assertEqual( qs(result, u"Evänt"), { "Subject": [u"Süper", u"Dokumänt", u"Evänt"], "Subject_op": "and" }, ) # Clicking on Event we should get 0 results as none will be in common catalog_results = ICollection(self.collection).results( batch=False, brains=True, custom_query=make_query(qs(result, u"Evänt"))) self.assertEqual(len(catalog_results), 0)
def test_and_filter_type(self): self.assertEqual(len(self.collection.results()), 3) result = get_filter_items(self.collection_uid, 'Subject', cache_enabled=False) self.assertEqual(len(result), 4) self.assertEqual(get_data_by_val(result, 'all')['count'], 3) self.assertEqual(get_data_by_val(result, 'all')['selected'], True) self.assertEqual(get_data_by_val(result, u'Süper')['count'], 2) self.assertEqual(get_data_by_val(result, u'Evänt')['count'], 1) self.assertEqual(get_data_by_val(result, u'Dokumänt')['count'], 2) # Test url self.assertEqual(qs(result, u'Süper'), {'Subject': u'Süper'}) catalog_results = ICollection(self.collection).results( batch=False, brains=True, custom_query=make_query(qs(result, u'Süper'))) self.assertEqual(len(catalog_results), 2) result = get_filter_items(self.collection_uid, 'Subject', request_params={'Subject': u'Süper'}, filter_type="and", cache_enabled=False) self.assertEqual(len(result), 4) self.assertEqual(get_data_by_val(result, 'all')['count'], 3) # TODO: I'm not sure these counts are correct. It should represent how many results you will get if you click so should be smaller than this # but I guess you need to turn on narrow down for that? self.assertEqual(get_data_by_val(result, u'Süper')['count'], 2) self.assertEqual(get_data_by_val(result, u'Evänt')['count'], 1) self.assertEqual(get_data_by_val(result, u'Dokumänt')['count'], 2) self.assertEqual(get_data_by_val(result, u'Süper')['selected'], True) self.assertEqual(qs(result, u'Süper'), {}) self.assertEqual(qs(result, u'Dokumänt'), { 'Subject_op': 'and', 'Subject': [u'Süper', u'Dokumänt'] }) self.assertEqual(qs(result, u'Evänt'), { 'Subject_op': 'and', 'Subject': [u'Süper', u'Evänt'] }) # Narrow down by 2 catalog_results = ICollection(self.collection).results( batch=False, brains=True, custom_query=make_query(qs(result, u'Dokumänt'))) self.assertEqual(len(catalog_results), 1) result = get_filter_items( self.collection_uid, 'Subject', request_params={'Subject': [u'Süper', u'Dokumänt']}, filter_type="and", cache_enabled=False) self.assertEqual(len(result), 4) self.assertEqual(get_data_by_val(result, 'all')['count'], 3) self.assertEqual(get_data_by_val(result, u'Süper')['count'], 2) self.assertEqual(get_data_by_val(result, u'Evänt')['count'], 1) self.assertEqual(get_data_by_val(result, u'Dokumänt')['count'], 2) self.assertEqual(get_data_by_val(result, u'Süper')['selected'], True) self.assertEqual( get_data_by_val(result, u'Dokumänt')['selected'], True) self.assertEqual(qs(result, u'Süper'), {'Subject': u'Dokumänt'}) self.assertEqual(qs(result, u'Dokumänt'), {'Subject': u'Süper'}) self.assertEqual(qs(result, u'Evänt'), { 'Subject': [u'Süper', u'Dokumänt', u'Evänt'], 'Subject_op': 'and' }) # Clicking on Event we should get 0 results as none will be in common catalog_results = ICollection(self.collection).results( batch=False, brains=True, custom_query=make_query(qs(result, u'Evänt'))) self.assertEqual(len(catalog_results), 0)
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, content_selector="", reverse=False, ): 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() option_url = "/".join([it for it in [collection_url, view_name] if it]) collection = ICollectionish(collection).selectContent(content_selector) if ( collection is None or not collection.content_selector ): # e.g. when no listing tile return None # Recursively transform all to unicode request_params = safe_decode(request_params) # Things break if sort_order is not a str if six.PY2 and "sort_order" in request_params: request_params["sort_order"] = str(request_params["sort_order"]) # 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)) # Additive filtering is about adding other filter values of the same index. extra_ignores = [] if narrow_down else [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 = collection.results(custom_query, request_params) 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 = collection.results(count_query, request_params) if not catalog_results: return None # Attribute name for getting filter value from brain metadata_attr = groupby_criteria[group_by]["metadata"] # Value blacklist value_blacklist = groupby_criteria[group_by].get("value_blacklist", None) or [] # Allow value_blacklist to be callables for runtime-evaluation value_blacklist = ( value_blacklist() if callable(value_blacklist) else value_blacklist ) # 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) val = val() if callable(val) else 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) or filter_value in value_blacklist ): continue if type(filter_value) == int: # if indexed value is an integer, convert to string filter_value = str(filter_value) if filter_value in grouped_results: # Add counter, if filter value is already present grouped_results[filter_value]["count"] += 1 continue url = _build_url( collection_url=option_url, urlquery=urlquery, filter_value=filter_value, current_idx_value=current_idx_value, idx=idx, filter_type=filter_type, ) grouped_results[filter_value] = _build_option( filter_value=filter_value, url=url, current_idx_value=current_idx_value, groupby_options=groupby_criteria[group_by], ) # 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: # TODO: catalog_results_fullcount is possibly undefined catalog_results = catalog_results_fullcount ret = [ { "title": translate( _("subject_all", default=u"All"), context=getRequest(), target_language=plone.api.portal.get_current_language(), ), "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) if reverse: grouped_results = reversed(grouped_results) ret += grouped_results return ret