Channel Filtering
Default filtering
HST supports pluggable filtering on the channels that are visible below the [view] button for a document or in the Experience manager for a logged in CMS user. By default, the ContentReadChannelFilter and PrivilegeBasedChannelFilter are always present and are always applied, also see Access Channels. It filters out all channels that the current CMS user is not allowed to see in the Channel Manager. For example, if there are three channels with the content roots
/content: /documents: /intranet: /extranet: /management:
and the logged-in CMS user has read access to the content of 'intranet' and 'extranet', then he won't see the Channel that has 'management' as content root in the Experience manager application.
Customize filtering
Channel filtering can be customized by adding extra channel filters to the built in channel filters. To add a custom channel filter you need to:
- Create a filter that implements java.util.function.BiPredicate<Session,Channel>
- Add a Spring bean for your custom filter to customChannelFilters
Built-in Channel Filters
As examples, we show the default ContentReadChannelFilter and PrivilegeBasedChannelFilter since they serve as good examples. The provided Session in the #test method is the Session of the currently logged-in CMS user.
public class ContentReadChannelFilter implements BiPredicate<Session, Channel> { private static final Logger log = LoggerFactory.getLogger(ContentReadChannelFilter.class); @Override public boolean test(final Session userSession, final Channel channel) { try { if (userSession.nodeExists(channel.getContentRoot())) { log.debug("Predicate passed for channel '{}' because user '{}' has read access on '{}'", new String[]{channel.toString(), userSession.getUserID(), channel.getContentRoot()}); return true; } log.info("Skipping channel '{}' for user '{}' because she has no read access on '{}'", new String[]{channel.toString(), userSession.getUserID(), channel.getContentRoot()}); return false; } catch (RepositoryException e) { log.warn("Exception while trying to check channel content root '{}'. Skip that channel:", channel.getContentRoot(), e); return false; } } }
public class PrivilegeBasedChannelFilter implements BiPredicate<Session, Channel> { private static final Logger log = LoggerFactory.getLogger(ContentReadChannelFilter.class); @Override public boolean test(final Session userSession, final Channel channel) { try { final Privilege privilege = userSession.getAccessControlManager().privilegeFromName("hippo:channel-viewer"); return userSession.getAccessControlManager().hasPrivileges(channel.getHstConfigPath(), new Privilege[]{privilege}); } catch (RepositoryException e) { log.warn("Exception while checking privilege 'hippo:channel-viewer' for channel '{}'. Skip that channel:", channel.getHstConfigPath(), e); return false; } } }
Example of adding a custom filter
Assume (contrived example) you want to add a channel filter such that a channel is only shown in the Experience manager application, if the CMS user his locale is the same as the locale of the channel, you can achieve that through the following steps:
Create ChannelLocaleBasedFilter
public class ChannelLocaleBasedFilter implements BiPredicate<Session, Channel> { private static final Logger log = LoggerFactory.getLogger(ChannelNodeBasedFilter.class); @Override public boolean test(final Session cmsSession, final Channel channel) { try { if (channel.getLocale() == null) { // no specific locale return true; } final HstRequestContext requestContext = RequestContextProvider.get(); if (requestContext == null { // invoked by background thread, no filtering return true; } final HttpSession session = requestContext.getServletRequest().getSession(); final CmsSessionContext cmsSessionContext = CmsSessionContext.getContext(session); final Locale userLocale = cmsSessionContext.getLocale(); if (userLocale.getLanguage().equals(new Locale(channel.getLocale()).getLanguage())) { // matching locale return true; } else { return false; } } catch (Exception e) { log.warn("Exception while trying to check channel content root '{}'. Skip that channel:", channel.getContentRoot(), e); return false; } } }
Add the ChannelLocaleBasedFilter to the customFilters
Below
site/components/src/main/resources/META-INF/hst-assembly/overrides
, add the following bean to an XML Spring configuration file (for example to custom-channel-filters.xml):
<!-- Custom channel filters be added here. --> <bean id="customChannelFilters" class="org.springframework.beans.factory.config.ListFactoryBean"> <property name="sourceList"> <list> <bean id="channelNodeBasedFilter" class="org.example.filter.ChannelLocaleBasedFilter"/> </list> </property> </bean>
Access the HstRequestContext in a Channel Filter
In a Channel Filter #test method you can access the HstRequestContext via
HstRequestContext hstRequestContext = RequestContextProvider.get();
If using it, always make sure to do a null check on the hstRequestContext object since the Channel Filters can also be applied to background threads which do not have an HstRequestContext. The hstRequestContext is the request context for the CMS request. When getting the JCR Session via the request context, you'll get the JCR Session for the currently logged-in CMS user.