AEM Cloud Service - Configure file upload max size per asset type, restrict upload from UI

Goal

AEM Cloud Version : 2021.4.5226.20210427T070726Z-210325 (April 27, 2021)

Maximum asset size for uploads from AEM UI can be configured by overlaying /libs/dam/gui/content/assets/jcr:content/actions/secondary/create/items/fileupload@sizeLimit in /apps, however if the requirement is to configure limit per asset type (eg. jpg, png, mp4 etc.) the following extension could be useful....

Demo | Package Install | Github


Error shown in UI


Custom Configuration Nav



Configure Limit

                                 https://author-pxxxx-exxxx.adobeaemcloud.com/apps/eaem-cs-restrict-assets-size/dam-tools/eaem-dam-config.html/conf/global/settings/dam/eaem-dam-config


Limit Saved in CRX


Solution

1) Create a custom widget /apps/eaem-cs-restrict-assets-size/dam-tools/textfield/textfield.jsp to read the values from config resource /conf/global/settings/dam/eaem-dam-config

<%@include file="/libs/granite/ui/global.jsp" %>

<%@page session="false"
        import="com.adobe.granite.ui.components.AttrBuilder,
                  com.adobe.granite.ui.components.Config,
                  com.adobe.granite.ui.components.Tag" %>
<%
    Config cfg = cmp.getConfig();

    String CONFIG_RES = "/conf/global/settings/dam/eaem-dam-config";
    Resource configRes = resourceResolver.getResource(CONFIG_RES);

    String name = cfg.get("name", String.class);
    String value = "";

    if(configRes != null){
        value = configRes.getValueMap().get(name, String.class);
    }

    if(value == null){
        value = cfg.get("defaultValue", String.class);
    }

    if(value == null){
        value = "";
    }

    Tag tag = cmp.consumeTag();

    AttrBuilder attrs = tag.getAttrs();
    cmp.populateCommonAttrs(attrs);

    attrs.add("name", name);

    String fieldLabel = cfg.get("fieldLabel", String.class);
    String fieldDesc = cfg.get("fieldDescription", String.class);
%>

<div class="coral-Form-fieldwrapper">
    <label class="coral-Form-fieldlabel"><%=fieldLabel%></label>
    <input is="coral-textfield" name="<%=name%>" value="<%=value%>" style="width: 100%;">
    <coral-icon class="coral-Form-fieldinfo" icon="infoCircle" size="S"></coral-icon>
    <coral-tooltip target="_prev" placement="left" class="coral3-Tooltip" variant="info" role="tooltip" style="display: none;">
        <coral-tooltip-content><%=fieldDesc%></coral-tooltip-content>
    </coral-tooltip>
</div>


2) Create the tools navigation /apps/cq/core/content/nav/tools/eaem-dam-tools/eaem-dam-config

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
          jcr:description="EAEM Custom Configuration"
          jcr:primaryType="nt:unstructured"
          jcr:title="EAEM Configuration"
          href="/apps/eaem-cs-restrict-assets-size/dam-tools/eaem-dam-config.html/conf/global/settings/dam/eaem-dam-config"
          icon="asset"
          id="eaem-dam-config"
          size="XL"/>


3) Create the configuration page /apps/eaem-cs-restrict-assets-size/dam-tools/eaem-dam-config saving max upload limits to /conf/global/settings/dam/eaem-dam-config accessed using Tools > EAEM Configuration > EAEM Configuration or https://author-pxxxxx-exxxxx.adobeaemcloud.com/apps/eaem-cs-restrict-assets-size/dam-tools/eaem-dam-config.html/conf/global/settings/dam/eaem-dam-config

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/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="cq:Page">
    <jcr:content
        jcr:mixinTypes="[sling:VanityPath]"
        jcr:primaryType="nt:unstructured"
        jcr:title="EAEM DAM Configuration"
        sling:resourceType="granite/ui/components/coral/foundation/page">
        <head jcr:primaryType="nt:unstructured">
            <favicon
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/page/favicon"/>
            <viewport
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/admin/page/viewport"/>
            <clientlibs
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/includeclientlibs"
                categories="[coralui3,granite.ui.coral.foundation,granite.ui.shell,dam.gui.admin.coral]"/>
        </head>
        <body
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/page/body">
            <items jcr:primaryType="nt:unstructured">
                <content
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/coral/foundation/form"
                    action="/conf/global/settings/dam/eaem-dam-config"
                    foundationForm="{Boolean}true"
                    maximized="{Boolean}true"
                    method="post"
                    novalidate="{Boolean}true"
                    style="vertical">
                    <successresponse
                        jcr:primaryType="nt:unstructured"
                        jcr:title="Success"
                        sling:resourceType="granite/ui/components/coral/foundation/form/responses/openprompt"
                        open="/assets.html"
                        redirect="/apps/eaem-cs-restrict-assets-size/dam-tools/eaem-dam-config.html/conf/global/settings/dam/eaem-dam-config"
                        text="Configuration saved"/>
                    <items jcr:primaryType="nt:unstructured">
                        <type
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/coral/foundation/form/hidden"
                            name="./jcr:primaryType"
                            value="nt:unstructured"/>
                        <wizard
                            jcr:primaryType="nt:unstructured"
                            jcr:title="Configuration"
                            sling:resourceType="granite/ui/components/coral/foundation/wizard">
                            <items jcr:primaryType="nt:unstructured">
                                <area
                                    jcr:primaryType="nt:unstructured"
                                    jcr:title="Configure Thumbnails"
                                    sling:resourceType="granite/ui/components/coral/foundation/container"
                                    maximized="{Boolean}true">
                                    <items jcr:primaryType="nt:unstructured">
                                        <columns
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
                                            margin="{Boolean}true">
                                            <items jcr:primaryType="nt:unstructured">
                                                <column
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/container">
                                                    <items jcr:primaryType="nt:unstructured">
                                                        <png-size
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="/apps/eaem-cs-restrict-assets-size/dam-tools/textfield"
                                                                fieldDescription="Enter the max size allowed for PNG upload, in bytes..."
                                                                fieldLabel="PNG upload max size allowed"
                                                                name="./pngSize"/>
                                                        <jpg-size
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="/apps/eaem-cs-restrict-assets-size/dam-tools/textfield"
                                                            fieldDescription="Enter the max size allowed for JPG upload, in bytes..."
                                                            fieldLabel="JPG upload max size allowed"
                                                            name="./jpgSize"/>
                                                        <mp4-size
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="/apps/eaem-cs-restrict-assets-size/dam-tools/textfield"
                                                            fieldDescription="Enter the max size allowed for MP4 upload, in bytes..."
                                                            fieldLabel="MP4 upload max size allowed"
                                                            name="./mp4Size"/>
                                                    </items>
                                                </column>
                                            </items>
                                        </columns>
                                    </items>
                                    <parentConfig jcr:primaryType="nt:unstructured">
                                        <prev
                                            granite:class="foundation-wizard-control"
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/anchorbutton"
                                            href="/aem/start.html"
                                            text="Cancel">
                                            <granite:data
                                                jcr:primaryType="nt:unstructured"
                                                foundation-wizard-control-action="cancel"/>
                                        </prev>
                                        <next
                                            granite:class="foundation-wizard-control"
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/button"
                                            text="Save"
                                            type="submit"
                                            variant="primary">
                                            <granite:data
                                                jcr:primaryType="nt:unstructured"
                                                foundation-wizard-control-action="next"/>
                                        </next>
                                    </parentConfig>
                                </area>
                            </items>
                        </wizard>
                    </items>
                </content>
            </items>
        </body>
    </jcr:content>
</jcr:root>

4) Create a clientlib /apps/eaem-cs-restrict-assets-size/supported-file-sizes with categories=dam.gui.coral.fileupload and dependencies=eaem.lodash

(function ($, $document) {
    "use strict";

    var _ = window._,
        CONFIG_PATH = "/conf/global/settings/dam/eaem-dam-config.json",
        allowedSizes = {},
        ENDS_WITH_SIZE = "Size";

    loadAllowedSizes();

    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 errorMessage = "";

        _.each(files, function(file){
            var fileErrorMessage = checkWithinSize(file);

            if(!fileErrorMessage){
                return;
            }

            errorMessage = errorMessage + fileErrorMessage;
        });

        if(errorMessage){
            showAlert(errorMessage);
        }else{
            _origOnInputChange.call(this, event);
        }
    };

    window.DamFileUpload.prototype._confirmUpload = function (event) {
        var errorMessage = "";

        this.fileUpload.uploadQueue.forEach(function(item) {
            var fileErrorMessage = checkWithinSize(item);

            if(!fileErrorMessage){
                return;
            }

            errorMessage = errorMessage + fileErrorMessage;
        });

        if(errorMessage){
            showAlert(errorMessage);
        }else{
            _origConfirmUpload.call(this, event);
        }
    };

    function checkWithinSize(file){
        var fileName = file.name, errorMessage = "";

        if(!fileName.includes(".")){
            return;
        }

        var ext = fileName.substring(fileName.lastIndexOf(".") + 1);

        _.each(allowedSizes, function(allowedSize, fileType){
            if(fileType !== ext){
                return;
            }

            if(file.size > allowedSize){
                errorMessage = "<b>" + fileName + "</b> size <b>" + formatBytes(file.size, 2)
                    + "</b> is more than allowed <b>" + formatBytes(allowedSize, 2) + "</b>";
            }
        });

        return errorMessage;
    }

    function loadAllowedSizes(){
        $.ajax(CONFIG_PATH).done(function(data){
            if(_.isEmpty(data)){
                return;
            }

            _.each(data, function(value, key){
                if(!key.endsWith(ENDS_WITH_SIZE)){
                    return;
                }

                allowedSizes[key.substring(0, key.lastIndexOf(ENDS_WITH_SIZE))] = parseInt(value);
            })
        })
    }

    function formatBytes(bytes, decimals) {
        if (bytes === 0){
            return '0 Bytes';
        }

        const k = 1024;
        const dm = decimals < 0 ? 0 : decimals;
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));

        return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
    }

    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)));


1 comment:

  1. Will this work with aem 6.5 or possibly with some changes?

    ReplyDelete