Set unique document name based on metadata

Each time a new document is uploaded, the Automation action sets a unique document name based in metadata values. 

  • Property okp:data.id stores a unique auto incremental value.
  • Property okp:data.code stores a project code value.
  • Property okp:data.customer stores a customer code.
  • Property okp:data.description stores a document description.
  • When a new document is uploaded the user must fill all the fields except okp:data.id which is automatically set by OpenKM.
  • When Metadata group is changed - event triggered- is executed automation code which generates okp:data.id and renames the document based on mask projectCode-autonumericId-clientCode-description.documentExtension.

The tables used in this sample is defined as:

-- LastID table
create table UNIQUE_ID (UN_ID INT, primary key(UN_ID));

insert into UNIQUE_ID (UN_ID) values (1);


-- Customer table
create table CUSTOMER (CUS_ID varchar(2),CUS_NAME varchar(32), primary key(CUS_ID));


insert into CUSTOMER (CUS_ID, CUS_NAME) values ('01', 'Customer 01');
insert into CUSTOMER (CUS_ID, CUS_NAME) values ('02', 'Customer 02');
insert into CUSTOMER (CUS_ID, CUS_NAME) values ('03', 'Customer 03');

Metadata group definition:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE property-groups PUBLIC "-//OpenKM//DTD Property Groups 3.10//EN"
"http://www.openkm.com/dtd/property-groups-3.10.dtd">
<property-groups>
    <property-group label="Datos" name="okg:data">
        <input label="Id" type="text" name="okp:data.id" width="200px" readonly="true"/>
        <input label="Project code" type="text" name="okp:data.code" width="200px">
            <validator type="req"/>
            <validator type="num"/>
            <validator type="maxlen" parameter="6"/>
            <validator type="minlen" parameter="6"/>
        </input>
        <select label="Customer" name="okp:data.customer" type="simple" 
                optionsQuery="select CUS_ID, CUS_NAME from CUSTOMER order by CUS_NAME">
            <validator type="req"/>
        </select>
        <input label="Description" type="text" name="okp:data.description" width="200px">
            <validator type="req"/>
            <validator type="maxlen" parameter="150"/>
        </input>
  </property-group>
</property-groups>

Automation action:

package com.openkm.plugin.automation.action;

import com.google.gson.Gson;
import com.openkm.core.DatabaseException;
import com.openkm.db.bean.*;
import com.openkm.db.service.LegacySrv;
import com.openkm.module.db.DbDocumentModule;
import com.openkm.plugin.BasePlugin;
import com.openkm.plugin.automation.Action;
import com.openkm.plugin.automation.AutomationException;
import com.openkm.plugin.automation.AutomationUtils;
import com.openkm.util.FileUtils;
import com.openkm.util.PathUtils;
import net.xeoh.plugins.base.annotations.PluginImplementation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@PluginImplementation
public class SetUniqueName extends BasePlugin implements Action {
    private static final Logger log = LoggerFactory.getLogger(SetUniqueName.class);
    private static final String PROPERTY_GROUP_NAME = "okg:data";
    private static final String PROPERTY_FIELD_ID_NAME = "okp:data.id";
    private static final String PROPERTY_FIELD_CODE_NAME = "okp:data.code";
    private static final String PROPERTY_FIELD_CUSTOMER_NAME = "okp:data.customer";
    private static final String CODE_PATTERN = "%06d";


    private static final ArrayList<AutomationRule.EnumEvents> EVENTS_AT_PRE = Stream.of(AutomationRule.EnumEvents.EVENT_PROPERTY_GROUP_ADD).collect(Collectors.toCollection(ArrayList::new));

    private static final ArrayList<AutomationRule.EnumEvents> EVENTS_AT_POST = new ArrayList<>();

    @Autowired
    private AutomationUtils automationUtils;

    @Autowired
    private LegacySrv legacySrv;

    @Autowired
    private DbDocumentModule dbDocumentModule;

    @Override
    public List<AutomationRule.EnumEvents> getValidEventsAtPre() {
        return EVENTS_AT_PRE;
    }

    @Override
    public List<AutomationRule.EnumEvents> getValidEventsAtPost() {
        return EVENTS_AT_POST;
    }

    @Override
    public void executePre(Map<String, Object> env, Object... params) throws AutomationException {
        // Pre stage, here the metadata still has not been created and it is set the unique code in the map of values
        NodeBase node = automationUtils.getNodeBase(env);
        String propertyGroupName = automationUtils.getPropertyGroupName(env);
        try {
            if (node instanceof NodeDocument && PROPERTY_GROUP_NAME.equals(propertyGroupName)) {
                // Set the property in the map of values
                Map<String, String> proceedingProperties = automationUtils.getPropertyGroupProperties(env);
                proceedingProperties.put(PROPERTY_FIELD_ID_NAME, getUniqueCode());
                // Rename document based in metadata values
                String currentName = PathUtils.getName(node.getPath());
                String currentExtension = FileUtils.getFileExtension(currentName); // Extension must not be replaced
                // Getting values
                String id = proceedingProperties.get(PROPERTY_FIELD_ID_NAME);
                String code = proceedingProperties.get(PROPERTY_FIELD_CODE_NAME);
                String jsonValueOfCustomer = proceedingProperties.get(PROPERTY_FIELD_CUSTOMER_NAME);
                Gson gson = new Gson();
                List<String> customerValues = gson.fromJson(jsonValueOfCustomer, List.class);
                String customerValue = customerValues.get(0);
                // Setting the new name
                String newName = code + "-" + id + "-" + customerValue;
                if (!currentExtension.isEmpty()) {
                    newName += "." + currentExtension;
                }
                dbDocumentModule.rename(null, node.getUuid(), newName);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new AutomationException(e.getMessage(), e);
        }
    }

    private synchronized String getUniqueCode() throws DatabaseException {
        Integer maxCode = 0;

        StringBuilder query = new StringBuilder("SELECT UN_ID FROM UNIQUE_ID");

        for (List<String> row : legacySrv.executeSQL(query.toString())) {
            maxCode = new Integer(row.get(0));
        }

        // increment value
        legacySrv.executeSQL("UPDATE UNIQUE_ID SET UN_ID = UN_ID +1");

        return String.format(CODE_PATTERN, maxCode);
    }

    @Override
    public void executePost(Map<String, Object> env, Object... params) throws AutomationException {
    }

    @Override
    public String getName() {
        return "Set Unique Name";
    }

    @Override
    public String getParamType00() {
        return Automation.PARAM_TYPE_EMPTY;
    }

    @Override
    public String getParamSrc00() {
        return Automation.PARAM_SOURCE_EMPTY;
    }

    @Override
    public String getParamDesc00() {
        return "";
    }

    @Override
    public String getParamType01() {
        return Automation.PARAM_TYPE_EMPTY;
    }

    @Override
    public String getParamSrc01() {
        return Automation.PARAM_SOURCE_EMPTY;
    }

    @Override
    public String getParamDesc01() {
        return "";
    }

    @Override
    public String getParamType02() {
        return Automation.PARAM_TYPE_EMPTY;
    }

    @Override
    public String getParamSrc02() {
        return Automation.PARAM_SOURCE_EMPTY;
    }

    @Override
    public String getParamDesc02() {
        return "";
    }
}

Create automation rule. Go to Administration > Automation and register a new rule:

  • Rule-based on "add metadata" event at the "pre" stage.
  • Set action named "SetUniqueName" in the actions.