Add an Audience Filter PLUS Security
This How-to applies to: Any version.
Summary
Add a new attribute, Audience, to the News component to indicate who is allowed to see this item. This is a required field, so every item in the component will have an Audience. Then create associated security roles. And finally change the user display to show only those items that match a given users' roles.
Add the new Audience attribute
Note: if the Audience selection options are the same as what you've already created for another component, you can skip steps 1 and 2 below. You do not need to re-create these scripts/methods. You can share the existing ones. For example, if you add Audience to News and Events, both those components can use the same selection options.
- Create selection options for property sheets.
Use the ZMI to go to the /Common folder (this is a good place
for scripts that may be used in multiple places on your site)
and add "Script (Python)".
id = selectAudience
Parameter list = leave blank
Body:
values= ['ptla','lse','mej']
Since these selection options are going to have associated security roles, they must have no spaces. For example, "LegalAid" is ok, but "Legal Aid" is not ok.
return values - Create selection options for add and edit forms.
Again, go to the /Common folder and this time add "DTML-Method".
id = selectAudienceDropdown
Body:
<dtml-if name="readonly">
<dtml-in audience><dtml-var "_['sequence-item']"><br /></dtml-in>
<dtml-else>
<dtml-if name="audience">
<select name="audience:list" multiple size="10">
<dtml-in "selectAudience()">
<option value='<dtml-var "_['sequence-item']">'
<dtml-try>
<dtml-if expr="_['sequence-item'] in audience"> selected</dtml-if>
</dtml-try>>
&dtml-sequence-item;</option>
</dtml-in>
</select>
<dtml-else>
<select name="audience:list" multiple size="10">
<dtml-in "selectAudience()">
<option value='<dtml-var "_['sequence-item']">'>&dtml-sequence-item;</option>
</dtml-in>
</select>
</dtml-if audience>
</dtml-if readonly>Note that the above code automatically gets the Audience selection options from the python script you created in step 1. It is possible to instead manually list the selection options. This would be necessary if you want to display something different than the option value. For example:
<dtml-if name="readonly">
<dtml-var "audience">
<dtml-else>
<dtml-if name="audience">
<select name='audience'>
<option value="ptla" <dtml-if "audience=='ptla'">selected </dtml-if>>ptla</option>
<option value="lse" <dtml-if "audience=='lse'">selected </dtml-if>>lse</option>
<option value="mej" <dtml-if "audience=='mej'">selected </dtml-if>>MEJP</option>
</select>
<dtml-else>
<select name='audience'>
<option value="ptla">ptla</option>
<option value="lse">lse</option>
<option value="mej">mej</option>
</select>
</dtml-if audience>
</dtml-if readonly>Note here that we display 'MEJP' even though the actual value is 'mej'. In most cases your names will match and so you'll be able to use the first code example above. However, if you're tying into a role that's already being used on your site but the role's name doesn't really match what it means anymore, you can keep the role name but display a different description in the dropdown.
- Add the new Audience attribute to the component product.
- Use the ZMI to go to Control_Panel/Products/News/News
- Click on the PropertySheets tab and then select Basic
- Add property: name=audience, type=multiple selection, value=selectAudience. Note that the value 'selectAudience' exactly matches the ID of the python script from step 1 above.
- Update the catalog. This step makes the new Audience attribute usable
to other parts of the site.
- Go to Data/News/Catalog
- Go to the Metadata tab and add (using the form at the bottom) audience.
- Go to the Indexes tab and add audience (type = keyword).
- Go back to the Indexes tab, check the box next to audience, and click Reindex.
- Add the new Audience attribute to admin views.
- Use the ZMI to go to Home/Admin/News/newsFields and add the
following code wherever you want the new Audience attribute to appear:
<tr valign="top">
<td><font class="label">Audience:</font></td>
<td><font class="datatext"><dtml-var selectAudienceDropdown></font></td>
</tr> - Go to Home/Admin/EventCalendar/calendarReqFields and add the
following code. This makes the required * appear.
context.addReqField(context.REQUEST, 'audience')
- Go to Home/Admin/EventCalendar/calendarValFields and add the
following code. This produces an error if the field is left blank.
It also restricts the audience value length to 30, but that usually
applies to free-form text fields. Just make sure the length specified
here is long enough to handle your longest selection option.
context.valNotEmpty(REQUEST, 'audience', 30)
- Use the ZMI to go to Home/Admin/News/newsFields and add the
following code wherever you want the new Audience attribute to appear:
- Optional. Create a new Admin view to manage the Audience
selection options.
- Use the ZMI to go to /Home/Admin/Docs (your Admin Menu).
- Add a new DTML-document:
id = Audience
title = Advocate Website Audience Roles<dtml-var standard_html_header>
<h2><dtml-var title_or_id></h2>
<p>The Audience Roles on the Advocate Website allow you to customize
who sees what. You can change the roles by following the instructions
below. One caution - it's not advised to delete roles unless you are
sure that all content previously assigned to that audience has been
moved to another audience.
Otherwise, content will "drop-off" and be viewed by no one.</p>
<ol>
<li>Go to the <a href="/manage" target="_blank">root folder</a> and
click on the <em>Security</em> tab.</li>
<li>Use the form at the very bottom of the page to add/delete roles. Roles
should have NO spaces.</li>
<li>Edit <a href="/Common/selectAudience/manage" target="_blank">selectAudience</a>
by following the format of existing roles. The roles are separated by
commas and enclosed in single quotes. The role name here must exactly
match the role in step 1 above.</li>
<li>Edit <a href="/Common/selectAudienceDropdown/manage"
target="_blank">selectAudienceDropdown</a>
again by following the format of existing roles. Each role is in this file
in <em>two</em> places - be sure to change both places. Most
references to the role must again exactly match the role in step 1
above (i.e., no spaces). The only exception is just before the </option>
command. This is the display value and can have spaces.</li>
<li>Now give this new role to users by editing
<a href="/acl_users/manage" target="_blank">acl_users</a>. You may
assign a user multiple roles. For example, when the user registers themself,
they get role <em>RegisteredUser</em>.
You can add extra roles using Ctrl-Click.</li>
</ol>
<dtml-var standard_html_footer> - Finally, add a link to your Admin Menu for the new Audience
Admin page. Use the ZMI to edit /Home/Admin/Docs/TOC and
add the following link.
<a href="Audience">Change Audience Roles</a>
- Optional. Add the new Audience attribute to the default
user view (the page on which they see all the details of a news item).
Use the ZMI to go to Control_Panel/Products/News/News/index_html and add the
following code wherever you want the new Audience attribute to appear:
<tr valign="top">
<td><font class="label">Audience:</font></td>
<td><font class="datatext"><dtml-var selectAudienceDropdown></font></td>
</tr> - Add a filter to the user view so users see only those items
they're supposed to see. Use the ZMI to go to /Home/PrivateWeb/News/index_html.
Look for the <dtml-in ...> code, which probably looks something like this:
<dtml-in expr="Data.News.Catalog(newsPrivateWeb=['on',1],newsDisplay=['on',1],
Make the following three changes:
newsPostStartDate=_.DateTime(), newsPostStartDate_usage='range:max',
newsPostEndDate=_.DateTime() - 1, newsPostEndDate_usage='range:min')"
sort=newsCreationDate>- add a <dtml-let ...> prior to the <dtml-in ...>.
- close the <dtml-let ...> immediately after the close of the <dtml-in ...>.
- add the audience filter to the existing <dtml-in ...>
<dtml-let user_roles="AUTHENTICATED_USER.getRoles()">
Repeat this step for any other DTML-Methods or DTML-Documents that display news items. For example, many sites have a recent_news that displays news items on the home page.
<dtml-in expr="Data.News.Catalog(newsPrivateWeb=['on',1],newsDisplay=['on',1],
audience=user_roles,
newsPostStartDate=_.DateTime(), newsPostStartDate_usage='range:max',
newsPostEndDate=_.DateTime() - 1, newsPostEndDate_usage='range:min')"
sort=newsCreationDate>
...
</dtml-in>
</dtml-let> - Add security roles that match the Audience selection options.
- Use the ZMI to go to the root folder.
- Go to the Security tab.
- Scroll all the way down and use the form at the bottom to add a role for each Audience selection option. The roles must exactly match the selection options, including capitalization. Roles cannot have spaces.
- Finally, assign roles to users. Use the ZMI to go to the acl_users folder. Click any user's name to view their roles. They probably already have RegisteredUser, which gives them access to the PrivateWeb. Hold-down the Ctrl key to assign additional roles.
Q. What happens to the News items that are pre-existing,
since before you made these changes?
A. They have no value chosen in the multiple selection list. Therefore, they all disappear from the user view.
Here is some helpful testing code from Andrew Cameron in VT.
<!--#comment-->Display user info<!--#/comment-->
You are the user named <!--#var expr="AUTHENTICATED_USER.getUserName()"-->.<P>
<!--#if "AUTHENTICATED_USER.getRoles()"-->
You have the following roles:
<!--#in "AUTHENTICATED_USER.getRoles()"-->
<LI><!--#var sequence-item-->
<!--#/in-->
<!--#else-->
You have no roles defined.
<!--#/if-->
<P>
see also:
-
Add an Audience Filter
- These instructions allow you to add an "audience" attribute to any component and then use that audience to control what users see in different parts of your website. This was originally developed for Maine which houses multiple mini-sites. The example below adds Audience to the Event Calendar. Although each component is unique in some way, the basic steps should be transferable.