Any ideas how I would hide or show a dialog tab panel depending on which user group the user belongs to?
I tried to do this through the CRX content explorers (ACL's). But I'm not getting much luck with it.
Cheers
Any ideas how I would hide or show a dialog tab panel depending on which user group the user belongs to?
I tried to do this through the CRX content explorers (ACL's). But I'm not getting much luck with it.
Cheers
As noted by anthonyh, the ACL approach is the way to go (if such a behavior is really necessary).
For example, to hide the "image" tab of the base page component:
/libs/foundation/components/page/dialog/items/tabs/items/image
deny jcr:read
for author
Note that in case of tabs included with xtype=cqinclude
you have to set it on the include itself, not the included definition. Because at runtime it would complain over the missing target of the include and not render the dialog at all.
This can be accomplished with a custom servlet and a dialog event listener.
The listener function makes a request to the servlet, passing the current user ID and the desired group. The dialog tab can then be hidden based on the servlet response.
Here is an example dialog.xml for a CQ5 component:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Dialog"
xtype="dialog">
<listeners jcr:primaryType="nt:unstructured"
loadcontent="function(dialog) {
var url = '/bin/member.json';
// check if current user belongs to administrators group
url = CQ.HTTP.addParameter(url, 'userId', CQ.User.getUserID());
url = CQ.HTTP.addParameter(url, 'groupId', 'administrators');
var result = CQ.HTTP.eval(url);
if (!result.isMember) {
// hide "tab2" if user is not an administrator
dialog.findByType('tabpanel')[0].hideTabStripItem(1);
}
}" />
<items jcr:primaryType="cq:WidgetCollection">
<tab1 jcr:primaryType="cq:Widget" title="Text" xtype="panel">
<items jcr:primaryType="cq:WidgetCollection">
...
</items>
</tab1>
<tab2 jcr:primaryType="cq:Widget" title="Image" xtype="panel">
<items jcr:primaryType="cq:WidgetCollection">
...
</items>
</tab2>
</items>
</jcr:root>
And here is the corresponding servlet:
import java.io.IOException;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonGenerator.Feature;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.security.Group;
import com.day.cq.security.User;
import com.day.cq.security.UserManager;
import com.google.common.collect.ImmutableMap;
@Component(immediate = true)
@Service
@Properties({
@Property(name = "service.description", value = "Group Member servlet checks if a user is a member of a group."),
@Property(name = "sling.servlet.paths", value = "/bin/member")
})
public class GroupMemberServlet extends SlingAllMethodsServlet {
/** Required. */
private static final long serialVersionUID = 1L;
/** Logger */
private static final Logger LOG = LoggerFactory.getLogger(GroupMemberServlet.class);
private static final JsonFactory FACTORY = new JsonFactory().disable(Feature.AUTO_CLOSE_TARGET);
private static final ObjectMapper MAPPER = new ObjectMapper();
@Override
protected void doGet(final SlingHttpServletRequest request, final SlingHttpServletResponse response) {
final UserManager userManager = request.getResourceResolver().adaptTo(UserManager.class);
final String userId = request.getRequestParameter("userId").getString();
final String groupId = request.getRequestParameter("groupId").getString();
final Group group = (Group) userManager.get(groupId);
final User user = (User) userManager.get(userId);
writeJsonResponse(response, ImmutableMap.of("isMember", group.isMember(user)));
}
private void writeJsonResponse(final SlingHttpServletResponse response, final Object object) {
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
try {
final JsonGenerator generator = FACTORY.createJsonGenerator(response.getWriter());
MAPPER.writeValue(generator, object);
} catch (final JsonGenerationException jge) {
LOG.error("error generating JSON response", jge);
} catch (final JsonMappingException jme) {
LOG.error("error mapping JSON response", jme);
} catch (final IOException ioe) {
LOG.error("error writing JSON response", ioe);
}
}
}
One question spring to mind...Why do you want to limit control of an authoring dialog and remove a tab?
There's no reason why ACLs wouldn't work for this. Did you set them to be restrictive enough for the tab? Were you testing with a non-admin user? I would be cautious using something so code-heavy to solve an access issue.
Personally if ACLs don't work as well as desired I'd explore creating an new widget based on the tabpanel xtype rather than a code solution which may end up as being specific to one version of CQ5.
My Answer: Use ACLs.
Please have a look at these vaguely related official documents - same principle but different objective:
http://dev.day.com/content/kb/home/cq5/CQ5SystemAdministration/CQ53HowToHideCQNavigationButtons.html
and
http://dev.day.com/docs/en/cq/current/administering/security.html