Sunday 4 November 2018

AEM - Restrict Component Editing and Allowed Only for Certain Users


Disable Component Editing via dialog except few users

In AEM majorly content is created using component's dialog. Sometimes few type of contents is meant to be edited only by certain authors and are not suppose to modify or create by other authors.
In this case how can we protect these type of components should not be updated by non-authorised users.

In AEM when a component in a web page is rendered, an HTML element can be generated, wrapping the rendered component within itself. This primarily serves two purposes:

  • A component can only be edited when it is wrapped with an HTML element.
  • The wrapping element is used to apply HTML classes that provide:
    • layout information
    • styling information
More info about Decoration Tag available at Decoration Tag
If  cq:noDecoration {boolean}, This property added to a component and a true value forces AEM not to generate any wrapper elements over the component.This property set the decoration tag based on boolean value.
But decoration property can also be set programatically, [JAVA API]


In Java code if we check current user against the allowed group(s) and if user member of allowed group we will set decoration tag otherwise not.This will serve our purpose for this use case.


JAVA Code

package com.aem.community.core.models;

import java.util.Iterator;

import javax.annotation.PostConstruct;

import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.wcm.api.components.ComponentContext;
import com.day.cq.wcm.commons.WCMUtils;

@Model(adaptables = { SlingHttpServletRequest.class,
Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class DisableEditModel {

Logger logger = LoggerFactory.getLogger(this.getClass());

@SlingObject
private SlingHttpServletRequest request;
private final String GROUP ="my-approver";

@PostConstruct
protected void init() {
try {
boolean decoration=false;
User currentUser = request.getResourceResolver().adaptTo(User.class);
if(currentUser.isAdmin())
return;
Iterator<Group> currentUserGroups = currentUser.memberOf();

while (currentUserGroups.hasNext()) {
Group grp = (Group) currentUserGroups.next();
if(grp.getID().equals(GROUP)) {
decoration =true;
return;
}
}

ComponentContext cc = WCMUtils.getComponentContext(request);
cc.setDecorate(decoration);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.info(e.getMessage());
}
}

}



HTL Code

<sly data-sly-use.disableEdit="com.aem.community.core.models.DisableEditModel"></sly>
<div>Disabled Dialog Editing </div>






Sunday 2 September 2018

AEM - Content Fragment with Component

Browse and use Content fragment inside custom component

AEM introduced Content Fragment with 6.2 and now almost everyone knows about Content Fragments and How to create and use it.

But we are restricted to use Content Fragments inside page only via Content Fragment components (WCM core content fragment and foundation Content Fragment components)

What if we need to use Content Fragments like other assets e.g. images using PathField or PathBrowser in the component.

There is a possibility to achieve this and Content Fragment can be browsed and used from any component. Content Fragments variations can also be added from the component.

Content Fragment(without variation)

  • In the component dialog create a PathField to browse Content Fragment.
  • In HTL, use JAVA API to read HTML content from content fragments master variation node's jcr:data property. 


Example :

Component Dailog:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="CF Test Dialog"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<heading
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldLabel="Heading"
name="./heading"
required="{Boolean}true"/>
<cf-field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldDescription="Browse CF"
fieldLabel="Browse CF"
name="./cfdata"
rootPath="/content/dam"/>
</items>
</column>
</items>
</content>
</jcr:root>


HTL:

<h2>Content Fragment Test Component</h2>
<h3>${properties.heading}</h3>
<div data-sly-use.cf="${'com.aem.community.core.components.ContentFragmentContent' @ cfInput=properties.cfdata}">
${cf.content @ context='html'}
</div>

JAVA:

Above com.aem.community.core.components.ContentFragmentContent java code is available at GitHub



Content Fragment(with variation)

  • In the component dialog create a PathField to browse Content Fragment.
  • Create dropdown with options to populate content fragment variation
  • Create hidden field item to store content fragment variation value on dialog submit. this value will be used to set preselected variation option in dropdown when dialog will be loaded again.
  • In HTL, use JAVA API to read HTML content from content fragments master or selected variation node's jcr:data property. 
  • Create clientlibs with category 'cq.authoring.dialog' , add Javascript to populate dropdown option for component variations, variations can be retrieve by making ajax call to browsed Content Fragment with  cfm.info selectors and with json extension e.g. http://localhost:4502/content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/arctic-surfing-in-lofoten.cfm.info.json?ck=0.8366689055424192&_=1535814701363 . Below is the response of above request, variations can be read and dialog variations dropdown options can be created. 
{"name":"arctic-surfing-in-lofoten","title":"Arctic Surfing in Lofoten","description":"Surfing in Northern Norway","path":"/content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/arctic-surfing-in-lofoten","elements":[{"name":"main","title":"Main","contentType":"text/html"}],"variations":[{"name":"master","title":"Master","description":"Represents the original content fragment"},{"name":"teaser","title":"Teaser","description":""}]}

sample javascript created for demo at cf-variation-handler.js


Example :

Component Dailog:


<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="CF Test Dialog"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<heading
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldLabel="Heading"
name="./heading"
required="{Boolean}true"/>
<cf-field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldDescription="Browse CF"
fieldLabel="Browse CF"
name="./cfdata"
rootPath="/content/dam"/>
<variation
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
emptyText="Select"
fieldLabel="Variation"
name="./variation"/>
<varhidden
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/hidden"
name="./selectVariation"/>
</items>
</column>
</items>
</content>
</jcr:root>



HTL:

<h2>Content Fragment Test Component</h2>
<h3>${properties.heading}</h3>
<div data-sly-use.cf="${'com.aem.community.core.components.ContentFragmentContent' @ cfInput=properties.cfdata, variation=properties.variation}">
${cf.content @ context='html'}
</div>

JAVA:

Same java code is compatible with both ContentFragmentContent.java







AEMaaCS - Core Component's Children Editor

If you are using core components, you should be familiar with the children-editor for Tabs, Accordion, and Carousel. These components are th...

About Me

My photo
https://www.linkedin.com/in/arunpatidar26/ https://experienceleaguecommunities.adobe.com/t5/user/viewprofilepage/user-id/6786635 https://community.adobe.com/t5/user/viewprofilepage/user-id/12372253 https://forums.adobe.com/people/Arun+Patidar