AEM Cloud Service Version : 2021.1.4738.20210107T143101Z-201217 (Jan 7, 2021)
Goal
Adding the following extension would restrict users from uploading duplicates files (files with same name). The check is done repository wide /content/dam
Demo | Package Install | Github
Solution
1) Create a service user configuration in repo init script ui.config\src\main\content\jcr_root\apps\eaem-cs-upload-unique-assets\osgiconfig\config.author\org.apache.sling.jcr.repoinit.RepositoryInitializer-eaem.config this is for querying and returning duplicates as JSON (in next steps).
scripts=[
"
create service user eaem-service-user with path system/cq:services/experience-aem
set principal ACL for eaem-service-user
allow jcr:read on /apps
allow jcr:read on /content/dam
end
"
]
2) Adding the above repo init script in code repo and installing on AEM CS creates a service user in /home/users/system/cq:services/experience-aem
3) Add the service user to bundle mapping in ui.config\src\main\content\jcr_root\apps\eaem-cs-upload-unique-assets\osgiconfig\config.author\org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-eaem.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
user.mapping="[eaem-cs-upload-unique-assets.core:eaem-service-user=[eaem-service-user]]"/>
4) Create a servlet apps.experienceaem.assets.core.servlets.FindAssetDuplicates to return the duplicates
package apps.experienceaem.assets.core.servlets;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Session;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Component(
name = "Experience AEM find duplicates servlet",
immediate = true,
service = Servlet.class,
property = {
"sling.servlet.methods=GET",
"sling.servlet.paths=/bin/experience-aem/duplicates"
}
)
public class FindAssetDuplicates extends SlingAllMethodsServlet {
private static final Logger log = LoggerFactory.getLogger(FindAssetDuplicates.class);
private static final String EAEM_SERVICE_USER = "eaem-service-user";
@Reference
private ResourceResolverFactory factory;
@Reference
private QueryBuilder builder;
@Override
protected final void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws
ServletException, IOException {
try {
String fileNames[] = request.getParameterValues("fileName");
JSONArray duplicates = new JSONArray();
response.setContentType("application/json");
if(ArrayUtils.isEmpty(fileNames)){
duplicates.write(response.getWriter());
return;
}
ResourceResolver resourceResolver = getServiceResourceResolver(factory);
Query query = builder.createQuery(PredicateGroup.create(getQueryPredicateMap(fileNames)),
resourceResolver.adaptTo(Session.class));
SearchResult result = query.getResult();
for (Hit hit : result.getHits()) {
duplicates.put(hit.getPath());
}
duplicates.write(response.getWriter());
} catch (Exception e) {
log.error("Could not execute duplicates check", e);
response.setStatus(SlingHttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
public ResourceResolver getServiceResourceResolver(ResourceResolverFactory resourceResolverFactory) {
Map<String, Object> subServiceUser = new HashMap<>();
subServiceUser.put(ResourceResolverFactory.SUBSERVICE, EAEM_SERVICE_USER);
try {
return resourceResolverFactory.getServiceResourceResolver(subServiceUser);
} catch (LoginException ex) {
log.error("Could not login as SubService user {}, exiting SearchService service.", "eaem-service-user", ex);
return null;
}
}
private Map<String, String> getQueryPredicateMap(String[] fileNames) {
Map<String, String> map = new HashMap<>();
map.put("path", "/content/dam");
map.put("group.p.or", "true");
for(int index = 0; index < fileNames.length; index++){
map.put("group." + index + "_nodename", fileNames[index]);
}
return map;
}
}
5) Create a client library /apps/eaem-cs-upload-unique-assets/clientlibs/unique-names with categories =dam.gui.coral.fileupload and dependencies=eaem.lodash and following script
(function ($, $document) {
"use strict";
var _ = window._;
var _origConfirmUpload = window.DamFileUpload.prototype._confirmUpload,
_origOnInputChange = window.Dam.ChunkFileUpload.prototype._onInputChange;
window.Dam.ChunkFileUpload.prototype._onInputChange = function(event){
var files = event.target.files;
if(!files && event.dataTransfer && event.dataTransfer.files){
files = event.dataTransfer.files;
}
if(_.isEmpty(files)){
_origOnInputChange.call(this, event);
return;
}
var validFiles = [];
_.each(files, function(file) {
validFiles.push(file.name);
});
var existInDAMFiles = checkFilesExist(validFiles);
if(!_.isEmpty(existInDAMFiles)){
showAlert("Following files exist : BR BR" + existInDAMFiles.join("BR") + "</b>");
return;
}
_origOnInputChange.call(this, event);
};
window.DamFileUpload.prototype._confirmUpload = function (event) {
var existInDAMFiles = checkFilesExist(this.fileUpload.uploadQueue.map(hit => hit.path));
if(!_.isEmpty(existInDAMFiles)){
showAlert("Following files exist : BR BR" + existInDAMFiles.join("BR") + "</b>");
return;
}
_origConfirmUpload.call(this, event);
var uploadDialog = this.uploadDialog;
_.defer(function(){
$(uploadDialog).find("input").attr("disabled", "disabled");
},0)
};
function checkFilesExist(fileNames){
var existingFiles = [],
url = "/bin/experience-aem/duplicates?";
_.each(fileNames, function(fileName, index){
url = url + "fileName=" + fileName + "&";
});
$.ajax( { url : url, async : false, contentType:"application/json" }).done(function(data){
existingFiles = data;
}).fail(function() {
showAlert("Error occured while checking for duplicates", "Error");
});
return existingFiles;
}
function showAlert(message, title, callback){
var fui = $(window).adaptTo("foundation-ui"),
options = [{
id: "ok",
text: "OK",
primary: true
}];
message = message || "Unknown Error";
title = title || "Error";
fui.prompt(title, message, "warning", options, callback);
}
}(jQuery, jQuery(document)));