Implementing the Send-As-Email DocLIb Action - Alfresco Content Services - 23.4 - 23.4 - Ready - Alfresco - external

Alfresco Content Services

Platform
Alfresco
Product
Alfresco Content Services
Release
23.4
License
  1. Add a new Surf Extension Module file and define the Send-As-Email action

    Call the file add-doclib-actions-extension-modules.xml and save it in the aio/aio-share-jar/src/main/resources/alfresco/web-extension/site-data/extensions directory (note. it is important to give this file a unique name when several Share JARs are installed, otherwise the last one wins).

    Then define the Send-As-Email DocLib action as follows:

    <extension>
        <modules>
            <module>
                <id>Add Document Library Actions (Send-as-Email, Call WS, Show Msg, Go to Google)</id>
                <version>1.0</version>
                <auto-deploy>true</auto-deploy>
                <configurations>
                    <config evaluator="string-compare" condition="DocLibActions">
                        <actions>
                            <action id="alfresco.tutorials.doclib.action.sendAsEmail"
                                    icon="email"
                                    type="javascript"
                                    label="alfresco.tutorials.doclib.action.sendAsEmail.label">
                                <param name="function">onActionFormDialog</param>
                                <param name="itemKind">action</param>
                                <param name="itemId">send-as-email</param> <!-- Repository action id = Spring Bean id -->
                                <param name="mode">create</param>
                                <param name="destination">{node.nodeRef}</param>
                                <param name="successMessage">alfresco.tutorials.doclib.action.sendAsEmail.msg.success</param>
                                <param name="failureMessage">alfresco.tutorials.doclib.action.sendAsEmail.msg.failure</param>
                                <evaluator negate="true">alfresco.tutorials.evaluator.isEmailed</evaluator>
                            </action>
                        </actions>
                    </config>
                </configurations>
            </module>
        </modules>
    </extension>
    

    The different attributes and sub-elements for the action element have the following meaning:

    Name Description
    id The global identifier for this action. It’s used when you refer to this action in other parts of the configuration, such as when defining where it should be visible.
    icon Share looks for an icon that starts with this name and ends with -16.png. So it will look for email-16.png in our case. Content Services expects the image file to be located in the /components/documentlibrary/actions directory. If not set, the id is used.
    type Sets the type of action; this can be either javascript (as in our example) if you want the action to execute some Java Script code, link if you want to invoke some external URL, or pagelink if you want to invoke a URL within the Share web application. More details around the different types:link - accepts a href parameter that will be passed a nodeRef token for substitution, used for external links.pagelink - accepts a page parameter that will be passed a nodeRef token for substitution, used for Share links.javascript - accepts a function parameter with a JavaScript function that will get the current folder item as first argument.
    label Points to a property name in a resource file. The value of this property will be displayed in the UI as the action’s label. In our case the resource file is aio/aio-share-jar/src/main/resources/alfresco/web-extension/messages/aio-share-jar.properties
    param There can be one or more parameters set for an action. In case of a javascript action they will be passed into the Java Script code, there is one special parameter with the name function that sets the Java Script function that should be called when the action is executed. In case of a link action the parameters would typically be used to specify href and target. In case of a pagelink action a page parameter is used to specify a relative URL within the Share web application.
    evaluator Spring Bean id for an evaluator that is called by the system to find out if the action should be visible or not in the UI. An evaluator extends the org.alfresco.web.evaluator.BaseEvaluator class. You can negate the result of calling the evaluator by setting the negate attribute to true. In our case we do not want to show the Send-As-Email action if it has already been invoked on a content file.

    When the Send-As-Email action is invoked we want it to do the following:

    1. Display a form where the end-user can type in the values for the email address, email subject, and email body text.
    2. When the form is submitted it should automatically call a custom repository action with the information collected via the form.

    We achieve this by using the out-of-the-box JavaScript function called onActionFormDialog. The following table explains the parameters used with this function:

    Name Description
    itemKind The “kind” of item that the form is for, and that should be invoked when the form is submitted. For example, node, task, type, action (that is, repository action), mbean. In our case we are going to show a form that collects values for parameters used when invoking a repository action, so we specify itemKind as action.If you need multiple forms for the same itemKind and itemId then you can also add an extra parameter called formId. It is the form configuration to lookup, refers to the id attribute of the form element. If omitted the default form is used, that is, the form element without an id attribute.
    itemId The identifier for the item the form is for, this will be different for each “kind” of item, for an action it would be the Spring bean ID for the repository action definition, for a node it would be a NodeRef etc. In our case it is set to send-as-email, which matches a Spring Bean ID in the aio/aio-platform-jar/src/main/resources/alfresco/module/aio-platform-jar/context/service-context.xml context file.
    mode Mode the current form is in, can be view, edit or create, defaults to edit. In our case we are using the create mode as we want the form to be empty so we can collect new email information.
    destination Provides a destination for any new items created by the form. When present a hidden field is generated with a name of alf_destination. Note. This parameter is necessary even if the action is not creating any new items/nodes.
    successMessage A message to display when the DocLib action is executed successfully. It actually points to a property name in a resource file. In our case the resource file is aio/aio-share-jar/src/main/resources/alfresco/web-extension/messages/aio-share-jar.properties
    failureMessage A message to display when the DocLib action execution failed. It actually points to a property name in a resource file. In our case the resource file is aio/aio-share-jar/src/main/resources/alfresco/web-extension/messages/aio-share-jar.properties
  2. Add an i18n resource file that will contain all the labels and messages for the Send-As-Email action.

    We can use the existing aio/aio-share-jar/src/main/resources/alfresco/web-extension/messages/aio-share-jar.properties file for this. Add the following properties to it:

    alfresco.tutorials.doclib.action.sendAsEmail.label=Send as Email
    alfresco.tutorials.doclib.action.sendAsEmail.msg.success='{0}' successfully sent in email to {1}.
    alfresco.tutorials.doclib.action.sendAsEmail.msg.failure=Couldn't send '{0}' in email to {1}.
    
  3. Define where in the user interface the Send-As-Email action should be displayed.

    This is also done in the add-doclib-actions-extension-modules.xml file in a new section called actionGroups:

    <extension>
        <modules>
            <module>
                <id>Add Document Library Actions (Send-as-Email, Call WS, Show Msg, Go to Google)</id>
                <version>1.0</version>
                <auto-deploy>true</auto-deploy>
                <configurations>
                    <config evaluator="string-compare" condition="DocLibActions">
                        <actions>
                         ...
                        </actions>
    
                         <actionGroups>
                            <actionGroup id="document-browse">
                                <action index="400" id="alfresco.tutorials.doclib.action.sendAsEmail" />
                            </actionGroup>
                            <actionGroup id="document-details">
                                <action index="400" id="alfresco.tutorials.doclib.action.sendAsEmail" />
                            </actionGroup>
                        </actionGroups>
                    </config>
                </configurations>
            </module>
        </modules>
    </extension>
    

    In this sub-section we configure in what document library views the action should be visible and where in the list of actions it should be displayed (ordering). To refer to the action we use the id that was specified when the action was defined. The following table shows available actionGroups:

    Action Group Id Default usage
    document-browse Action is visible for documents on the Browse page
    document-details Action is visible for document on the Document Details page
    folder-browse Action is visible for folders on the Browse page
    folder-details Action is visible for folder on the Folder Details page
    document-link-browse Action is visible for links to documents on the Browse page
    document-link-details Action is visible for link to document on the Document Details page
    folder-link-browse Action is visible for links to folders on the Browse page
    folder-link-details Action is visible for link to folder on the Folder Details page

    The index argument is specifying the order of this action in the list of actions. The higher the number the lower it will be displayed in the action list. By having a look in the share-documentlibrary-config.xml configuration file located in the alfresco/tomcat/webapps/share/WEB-INF/classes/alfresco directory of your Content Services installation, you can find out that the highest index for document-browse actions is 360 and for document-details actions 390. So if we set our index for the Send-As-Email action to 400 it should end up last in both of these action lists.

    If you want more examples of how Document Library actions can be defined and configured, have a look in the share-documentlibrary-config.xml file and the DocLibActions section.

  4. Add a custom icon for the Send-As-Email action.

    The icons for all the Document Library actions are stored in the tomcat/webapps/share/components/documentlibrary/actions directory in your Content Services installation. The system will try and load any custom Document Library action icons from this directory. Icons are loaded via the resource Servlet and action icons related to the Document Library are loaded with the http://localhost:8080/share/res/components/documentlibrary/actions/<icon>-16-png URL. This article is not about how to create a 16x16 icon in PNG format so copy one from the SDK sample source. In fact, copy all the icons that we need for all actions in this tutorial from this folder and put them in the aio/aio-share-jar/src/main/resources/META-INF/resources/aio-share-jar/components/documentlibrary/actions directory of your project (you might have to create this directory path).

  5. Add an Evaluator for the Send-As-Email action.

    For demonstration purpose the send-as-email repository action is implemented so it sets the cm:emailed aspect on the document after it has been sent in an email. This will then be checked by this evaluator, which will disable the Send-As-Email DocLib action if the document has the cm:emailed aspect already applied.

    There are three parts to setting up an evaluator for a Document Library action:

    1. Configure it with the element in the action configuration (We have already done this)
    2. Create a Java class that extends the org.alfresco.web.evaluator.BaseEvaluator class
    3. Define a spring bean with an id matching the configuration element’s value and then set the class for the Spring bean to the one implemented in step 2

    Create a new Java class called CheckIfDocIsEmailedEvaluator in the aio/aio-share-jar/src/main/java/org/alfresco/tutorial/doclibaction/evaluator package (you will have to create the package path). Then implement the Java class like this:

    package org.alfresco.tutorial.doclibaction.evaluator;
    
    import org.alfresco.web.evaluator.BaseEvaluator;
    import org.json.simple.JSONArray;
    import org.json.simple.JSONObject;
    
    publicclassCheckIfDocIsEmailedEvaluatorextendsBaseEvaluator {
        privatestaticfinal String ASPECT_EMAILED = "cm:emailed";
    
        @Override
        publicbooleanevaluate(JSONObject jsonObject) {
            try {
                JSONArray nodeAspects = getNodeAspects(jsonObject);
                if (nodeAspects == null) {
                    returnfalse;
                } else {
                    if (nodeAspects.contains(ASPECT_EMAILED)) {
                        returntrue;
                    } else {
                        returnfalse;
                    }
                }
            } catch (Exception err) {
                thrownew RuntimeException("JSONException whilst running action evaluator: " + err.getMessage());
            }
        }
    }
    

    The evaluate method gets a JSON object passed in from which you can get all the information you need about the node that the action is being applied to. Here we use the getNodeAspects method to get all the aspects that have been applied to the node (for more methods look in the BaseEvaluator class). Then we just check if the cm:emailed aspect has been applied to the node (that is, file).

    Next thing we need to do is define a Spring Bean for this evaluator, this is done in the aio-share-jar-slingshot-application-context.xml file located in the aio/aio-share-jar/src/main/resources/alfresco/web-extension. directory. Define the bean as follows:

    <beanid="alfresco.tutorials.evaluator.isEmailed"class="org.alfresco.tutorial.doclibaction.evaluator.CheckIfDocIsEmailedEvaluator" />
    

    Note here that the id has to match what was specified for the <evaluator> element in the action definition.

    It is not always necessary to create evaluators from scratch. There are a number of predefined evaluators (that is, out of the box evaluators ready to use):

    • Has aspect
    • Is mimetype
    • Property not Null
    • Site preset
    • Site / No Site
    • Container Type
    • Node Type
    • Always false
    • Value-based
    • Metadata value
    • Is Browser (type)
    • Is Portlet mode

    See the slingshot-documentlibrary-context.xml file located in the alfresco/tomcat/webapps/share/WEB-INF/classes/alfresco directory of your Content Services installation for more information about out-of-the-box evaluators.

  6. Add a Status Indicator for the Send-As-Email action.

    Sometimes you might want to know if a document has been emailed without going in and checking if the cm:emailed aspects has been applied. This can be achieved by adding a so called status indicator. An indicator is displayed in the Document Library browse view and builds on the work we have already done with the evaluator.

    There are four parts to setting up an indicator for a Document Library action:

    • Make sure you got an <evaluator> element in the action configuration (We have already done this) and that this evaluator has been implemented (We have already done this)
    • Add an indicator configuration to the DocumentLibrary section configuration
    • Add i18n label to the resource property file
    • Add an image to be used as indicator to the components/documentlibrary/indicators directory

    The indicator configuration is also done in the add-doclib-actions-extension-modules.xml file and points to the evaluator previously implemented. It looks like this in the new DocumentLibrary section:

    <extension>
        <modules>
            <module>
                <id>Add Document Library Actions (Send-as-Email, Call WS, Show Msg, Go to Google)</id>
                <version>1.0</version>
                <auto-deploy>true</auto-deploy>
                <configurations>
                    <config evaluator="string-compare" condition="DocumentLibrary">
                        <indicators>
                            <indicator id="alfresco.tutorials.indicator.isEmailed"
                                       icon="email-16.png"
                                       index="100"
                                       label="alfresco.tutorials.indicator.isEmailed.label">
                                <evaluator>alfresco.tutorials.evaluator.isEmailed</evaluator>
                            </indicator>
                        </indicators>
                    </config>
    
                    <config evaluator="string-compare" condition="DocLibActions">
                    ...
                    </config>
    
                </configurations>
            </module>
        </modules>
    </extension>
    

    The different attributes and sub-elements for the indicator element have the following meaning:

    Name Description
    id The global identifier for this indicator.
    icon The name of the icon to display as the status indicator. Content Services expects the image file to be located in the /components/documentlibrary/indicators directory. If not specified, “id” is used. Note. In this case Content Services does not assume *-16.png format but you have to specify the complete file name.
    index Is used to order the indicator in the UI when there are several indicators displayed for a document. If we look in the share-documentlibrary-config.xml (in the tomcat/webapps/share/WEB-INF/classes/alfresco directory) configuration file we can see that the largest index for out-of-the-box indicators is 90, so by using 100 the emailed indicator will always be displayed last in the list.
    label Points to a property name in a resource file. The value of this property will be displayed in the UI as the indicators tool-tip. In our case the resource file is aio/aio-share-jar/src/main/resources/alfresco/web-extension/messages/aio-share-jar.properties
    evaluator Spring Bean id for an evaluator that is called by the system to find out if the indicator should be visible or not in the UI. An evaluator extends the org.alfresco.web.evaluator.BaseEvaluator class. You can negate the result of calling the evaluator by setting the negate attribute to true. In our case we do want to show the indicator if the Send-As-Email action has been invoked on a content file, so we don’t negate.

    Now update the resource properties file with the value for the label, open the aio-share-jar.properties file and add the following property to it:

    alfresco.tutorials.indicator.isEmailed.label=This document has been emailed
    

    As an indicator image we will use the same one as is used for the action. Copy the email-16.png icon from the aio/aio-share-jar/src/main/resources/META-INF/resources/aio-share-jar/components/documentlibrary/actions directory to the aio/aio-share-jar/src/main/resources/META-INF/resources/aio-share-jar/components/documentlibrary/indicators directory (you might have to create the indicators directory).

  7. Add the form for the Send-As-Email action.

    The Send-As-Email action invokes the out-of-the-box onActionFormDialog JavaScript function, which expects there to be a form registered for the repository action that is invoked.

    The repository action that sends emails with attachments is registered with the id send-as-email (see aio/add-action-repo/src/main/resources/alfresco/module/add-action-repo/context/service-context.xml). We define a form for it as follows in the add-doclib-actions-extension-modules.xml file:

    <extension>
        <modules>
            <module>
                <id>Add Document Library Actions (Send-as-Email, Call WS, Show Msg, Go to Google)</id>
                <version>1.0</version>
                <auto-deploy>true</auto-deploy>
                <configurations>
                    <config evaluator="string-compare" condition="DocumentLibrary">
                    ...
                    </config>
    
                    <config evaluator="string-compare" condition="DocLibActions">
                    ...
                    </config>
    
                    <config evaluator="string-compare"
                            condition="send-as-email"> <!-- ID for the Repository Action that this form is associated with -->
                        <forms>
                            <form>
                                <field-visibility>
                                    <show id="to"/>
                                    <show id="subject"/>
                                    <show id="body_text"/>
                                </field-visibility>
                                <appearance>
                                    <field id="to" label-id="alfresco.tutorials.doclib.action.sendAsEmail.form.field.to"/>
                                    <field id="subject" label-id="alfresco.tutorials.doclib.action.sendAsEmail.form.field.subject"/>
                                    <field id="body_text" label-id="alfresco.tutorials.doclib.action.sendAsEmail.form.field.body_text">
                                        <control template="/org/alfresco/components/form/controls/textarea.ftl" />
                                    </field>
                                </appearance>
                            </form>
                        </forms>
                    </config>
    
                </configurations>
            </module>
        </modules>
    </extension>
    

    Note here that the field identifiers (that is, the id attribute) need to match the parameters sent into the send-as-email repository action. See aio/aio-platform-jar/src/main/java/org/alfresco/tutorial/repoaction/SendAsEmailActionExecuter.java.

    Update the resource properties file with the field labels as follows, the property names must match what we defined in the form definition above (that is, the label-id values). In the aio-share-jar.properties file add the following properties:

    alfresco.tutorials.doclib.action.sendAsEmail.form.field.to=To
    alfresco.tutorials.doclib.action.sendAsEmail.form.field.subject=Subject
    alfresco.tutorials.doclib.action.sendAsEmail.form.field.body_text=Body Text
    
  8. Build and start the application server as follows:
    /all-in-one$ ./run.sh build_start
    
  9. Now, log in to Share (http://localhost:8080/share) and upload a document to some folder. You will see the new Send-As-Email action in the Browse view when hovering over the document and clicking More… in the pop-up menu:
    An example of expanded menu with the Send as Email action marked.

    Clicking on the file name displays the Document Details view, where the Send-As-Email action should also be visible

    An opened docx document with Send as Email action.

    Clicking on the Send-As-Email action will display the form for collecting email information:

    Send as Email dialog box with filled details: receipient, subject, and body text.

    Filling in the form and clicking OK will call the send-as-email repository action, which will send the email with the file as attachment. The Repo action will also apply the cm:emailed aspect to the document. So we should be able to see the indicator on the file telling us the Send-As-Email action has been applied to it:

    An opened docx document with a Send as Email icon marked.

    If the FakeSMTP server is running we should see a new email picked up:

    A Fake SMTP Server with one message received.