![No UI](https://img.shields.io/static/v1?label=UI&message=none&color=inactive) The *Camunda Core* extension provides a synchronization of CELUM users and groups with Camunda and other utilities. Additionally it gives access to the Camunda REST API via CELUM (/main/camunda/*), so that Workflow extensions in CELUM only need to communicate with CELUM directly. [MINITOC] ## Properties To be configured in {home}/appserver/conf/custom.properties ### General ##### camundaCore.license > type: string, **required: yes**, default: - The license key for the plugin (product: camundaCore), provided by *brix*. ##### camundaCore.camunda.url > type: string, **required: yes**, default: - The URL to the camunda REST API. Has to start with `http` or `https` and end in `/`. E.g. http://localhost:8080/engine-rest/ ##### camundaCore.camunda.username > type: string, required: no, default: - The username for the Camunda REST API (only required if it is protected). ##### camundaCore.camunda.password > type: string, required: no, default: - The password for the Camunda REST API (only required if it is protected). ##### camundaCore.web.token > type: string, required: no, default: - The token for the services which don't require login (e.g. mail service) to protect them. ### User and Group Synchronization Only synchronizes the following events immediately, the rest is done by the sanitize job: - user/group added to group - group/user deletion - group/user creation (only if everything is synced) This ensures, that the users can immediately work with Camunda as soon as they are created in CELUM. Since v2.0 all groups with aliases will be synced. ##### camundaCore.userSync.enabled > type: boolean, required: no, default: `true` Enables/disables the user and group synchronization. Server restart required. ##### camundaCore.userSync.sanitize.cronExpression > type: string, required: no, default: `0 0 1 * * ?` (each night at 1 am) Quartz cron trigger that tells the sanitize job when and how often it should run. ##### camundaCore.tasks.cleanup.cronExpression > type: string, required: no, default: `0 0 0 2 * ?` (each night at 2 am) Quartz cron trigger that tells the historic tasks cleanup job when and how often it should run. ##### camundaCore.userSync.groups > type: comma-separated list of group ids, required: no, default: - (all groups), version: <v2.0 The groups (and members of those groups) which should be synchronized. If this property is not set, all groups are synchronized. ##### camundaCore.userSync.groupsRecursive > type: boolean, required: no, default: `false`, version: < v2.0 Synchronize all the sub-groups of the specified groups as well. Users are always resolved recursively because Camunda doesn't support hierarchical groups (only users can be members of groups and not other groups). ##### camundaCore.userSync.prefix.user > type: string, required: no, default: `CelumUser` The prefix to use for the CELUM users in Camunda. E.g. the user with ID 123 and the default prefix would become CelumUser123 in Camunda. ##### camundaCore.userSync.prefix.group > type: string, requierd: no, default: `CelumGroup`, version: alias-support 2.0+ The prefix to use for the CELUM groups in Camunda. E.g. the group with ID 456 and the default prefix would become CelumGroup456 in Camunda. If there is an alias for the group the alias is taken without prefix. ##### camundaCore.userSync.groupType > type: string, required: no, default: `CELUM` The group type of CELUM groups in Camunda. This is just a string and can be anything, but it can be helpful for searching the synchronized groups in Camunda. ##### camundaCore.username > type: string, required: no, default: `$firstname $lastname [$username]`, version: 2.0+ Defines how a user is displayed. Available placeholders: $firstname, $lastname, $username, $id. ##### camundaCore.groupname > type: string, required: no, default: `$groupname`, version: 2.0+ Defines how a group is displayed. Available placeholders: $groupname, $id. ### Password Checker The password checker provides an internal service and a controller to verify passwords. The controller accepts POST requests to `/main/camundaCore/password?userId=...&password=...`. userId is optional (defaults to the logged-in user). The following responses are possible: - 403 FORBIDDEN (<v2.0 406 NOT ACCEPTABLE): the user sending the request does not match the specified user id (can only happen if loggedInUserOnly is set to true) - 405 NOT ALLOWED: the user is deactivated - 404 NOT FOUND: the user wasn't found - 423 LOCKED (<v2.0 403 FORBIDDEN): the user was locked because the maximum number of incorrect attempts was reached within the configured time interval - 406 NOT ACCEPTABLE (<v2.0 401 UNAUTHORIZED): the password was wrong (could probably also happen if the user's CELUM session timed out) - 401 UNAUTHORIZED (only v2.0+): the session expired - 200 OK: password was correct To be able to use the password checker, the following table has to be created: create table camunda_password_check_attempts ( id bigint auto_increment primary key, user_id bigint not null, timestamp timestamp not null ); ##### camundaCore.passwordChecker.maxFails > type: integer, required: no, default: `5` After failing the password check this many times in the specified time interval, the user will be deactivated. ##### camundaCore.passwordChecker.intervalInMinutes > type: integer, required: no, default: `5` The time interval in minutes. ##### camundaCore.passwordChecker.resetAfterSuccess > type: boolean, required: no, default: `true` Delete the failed attempts after successful check? ##### camundaCore.passwordChecker.controller.loggedInUserOnly > type: boolean, required: no, default: `true` If set to false, every logged-in user can check the password of any user. Should not be false, otherwise it is possible to lock out other users by intentionally entering a wrong password enough times. This only affects the controller and not the internal password check service. ### Absences There is an internal service and a controller to manage the absences. Tasks which are directly assigned to users can be automatically re-assigned to the replacement unless they already have the same task. The controller provides the following methods to manage absences: - GET `main/camundaCore/absence?userId=...&active=...` both parameters are optional. For userId, the default is the logged-in user, and the default for active is true (only return absence if it is active). Returns an Absence JSON object. - GET `main/camundaCore/absence/list?active=...` only available if loggedInUserOnly is set to false. Active is optional and the default is true (only return active absences, not those in the future). Returns a list of Absence JSON objects. - POST `main/camundaCore/absence` creates or updates an absence. Has to be sent as absence JSON object in the body. userId is optional, the default is the logged-in user. - DELETE `main/camundaCore/absence?userId=...` userId is optional, the default is the logged-in user. Response codes: - 403 FORBIDDEN (<v2.0 406 NOT ACCEPTABLE): the user sending the request does not match the specified user id (can only happen if loggedInUserOnly is set to true) - 404 NOT FOUND: no absence found for specified userId - 400 BAD REQUEST: wrong date format - 201 CREATED: the absence was created (wasn't an update) - 401 UNAUTHORIZED (only v2.0+): the session expired - 200 OK Absence JSON object: { "id": ... "userId": 487 "replacementId": 430, "from": "2020-03-17", "to": "2020-03-17", } To be able to use the absence service, the following table has to be created: create table camunda_absence ( id bigint auto_increment primary key, user_id bigint not null, replacement_id bigint not null, from_date date not null, to_date date not null ); ##### camundaCore.absence.controller.loggedInUserOnly > type: boolean, required: no, default: `true` The logged-in user can only request or modify their own absence (recommended). ### Observers There is an internal service and a controller to manage observers. Observers can be informed automatically with the mail service. The controller provides the following methods to manage observers: - GET `main/camundaCore/observer?userId=...` userId is optional, the default is the logged-in user. Returns an Observer JSON object. - GET `main/camundaCore/observer/list` only available if loggedInUserOnly is set to false. Returns a list of Observer JSON objects. - POST `main/camundaCore/observer` creates or updates an observer, has to be sent as observer JSON object in the body. userId is optional, the default is the logged-in user. - DELETE `main/camundaCore/observer?userId=...` userId is optional, the default is the logged-in user. Response codes: - 403 FORBIDDEN (<v2.0 406 NOT ACCEPTABLE): the user sending the request does not match the specified user id (can only happen if loggedInUserOnly is set to true) - 404 NOT FOUND: no observer found for specified userId - 401 UNAUTHORIZED (only v2.0+): the session expired - 201 CREATED: the observer was created (wasn't an update) - 200 OK Observer JSON object: { "id": ... "userId": 487 } To be able to use the observer service, the following table has to be created: create table camunda_observer ( id bigint auto_increment primary key, user_id bigint not null ); ##### camundaCore.observer.enabled > type: boolean, required: no, default: `true` If this property is set to true, then deleted users will be removed automatically from the observer list. Restart required. ##### camundaCore.observer.controller.loggedInUserOnly > type: boolean, required: no, default: `true` The logged-in user can only request or modify their own observer status (recommended). ### Mails There is an internal mail service and a controller. Both accept a SendMailRequest object. The mail engine uses velocity templates, which have to be placed in the class path, e.g. CELUM_HOME/appserver/velocity (recommended). Mail template with all variables: #* @vtlvariable name="data" type="ch.brix.camundaCore.mail.MailData" *# #* @vtlvariable name="additionalData" type="java.util.Map" *#
Always available (all but the first property depend on the recipient), but maybe not set in CELUM: Available if assetId is set for the request:
The controller accepts POST requests to `camundaCore/mail` (note that there is no main) with a SendMailRequest object as the body and the response will be a SendMailResult object (JSON). The SendMailRequest object has the following properties: - token (string): if this token doesn't match the configured one, the response code will be 401: UNAUTHORIZED. - subjectMessageKey (string): the message key for the subject of the mail - template (string): the mail of the template (without the _locale.vm) - locale (string): the language in which the mail should be sent (default is the CELUM default system locale) - recipients (array of integers): the user ids of the recipients (the users to which the mail should be sent) - includeObservers (boolean): if set to true, the mail will also be sent to the observers (default is false) - assetId (integer): the id of the asset - taskId (string) - taskName (string) The SendMailResult object properties: - success (array of integers): the user ids to which a mail could be sent - failed (array of integers): the user ids for which sending the mail failed (only if not failed due to the three other reasons below) - ignored (array of integers): the user ids which were ignored because the user is deactivated - notFound (array of integers): the user ids which couldn't be found in CELUM - noMail (array of integers): the user ids for which the mail address is missing in CELUM ##### camundaCore.mail.from > type: string, required: yes, default: - The email address which should be displayed in the from field. ##### camundaCore.mail.bcc > type: string, required: no, default: - If the bcc is set, then this email address receives a copy of every mail that was sent with this mail service. ##### camundaCore.mail.ignoreDeactivatedUsers > type: boolean, required: no, default: `true` If set to true, then deactivated users won't receive any mails and will be ignored. ### Mail worker The mail worker processes external tasks with the topic `mail` automatically. - The messageVariable has to contain the message id. It defines the subject and the template to be taken. - The recipients variable has to be a comma-separated string with the following possible values: - `observers`: send mail to all observers - <group key>: send mail to a group defined by camundaCore.groups.{key}.{recursive} - <camunda user/group id>: a user/group ID to which the message should be sent (everything starting with the user prefix will be treated as user id, same for groups) - <variable name>: the variable has to contain a comma-separated string of the three options above (if none of the above is true an element will be treated as variable) - Following values will be available in the template (additionalData) - `variables`: all the variables (Map<String, VariableValueDto>) - the asset variables (camundaCore.variables.assets) will be resolved and contain a list of assets accessed by the variable name - the node variables (camundaCore.variables.nodes) will be resolved and contain a list of nodes accessed by the variable name - the usersAndGroups variables (camundaCore.variables.usersOrGroups) will be resolved and contain a list of resolved user/group names accessed by the variable name ##### camundaCore.mail.worker.enabled > type: boolean, required: no, default: `false`, version: 2.0+ Enables the mail worker. ##### camundaCore.mail.worker.recipientsVariable > type: boolean, required: no, default: `recipients`, version: 2.0+ The variable which contains the recipients. ##### camundaCore.mail.worker.messageKey > type: boolean, required: no, default: `message`, version: 2.0+ The variable which contains the message to be sent. ##### camundaCore.mail.worker.{id}.subject > type: boolean, required: no, default: -, version: 2.0+ Defines the subject (message key) for a mail. ##### camundaCore.mail.worker.{id}.template > type: boolean, required: no, default: -, version: 2.0+ Defines the template (name) for a mail. ### Update asset/node value worker An asset worker updating assets/nodes from variables. Listens to the topic `updateAssetOrNode`. Value transformations: - Date field: Date - Checkbox: String "true" or "false" - Number, Double: String => toString() - Text (area): String - Node-Reference: String => comma-separated list of node ids - Localized text (area): String => JSON object with the locales as keys - Availability: String => "available", "unavailable" or "date-controlled" (additionally sets/reads Date variables dateTo and dateFrom i.e. their alias) - Asset name: String - Node name: String => JSON object with the locales as keys ##### camundaCore.updateAssetOrNode.worker.enabled > type: boolean, required: no, default: `false`, version: 2.0+ Enables the update asset or node value worker. ##### camundaCore.updateAssetOrNode.worker.assetVariable > type: string, required: no, default: `assets`, version: 2.0+ The variable for the assets. The variable can contain comma-separated asset ids and/or variable names of variables with asset ids. ##### camundaCore.updateAssetOrNode.worker.nodeVariable > type: string, required: no, default: `nodes`, version: 2.0+ The variable for the nodes. The variable can contain comma-separated node ids and/or variable names of variables with node ids. ##### camundaCore.updateAssetOrNode.worker.assetFieldVariable > type: string, required: no, default: `assetFields`, version: 2.0+ The variable for the asset fields. The variable can contain comma-separated variable names and/or information field ids. The information field ids and variable names have to be listed here camundaCore.assetField.{variableName} ##### camundaCore.updateAssetOrNode.worker.nodeFieldVariable > type: string, required: no, default: `nodeFields`, version: 2.0+ The variable for the node fields. The variable can contain comma-separated variable names and/or information field ids. The information field ids and variable names have to be listed here camundaCore.nodeField.{variableName} ##### camundaCore.updateAssetOrNode.worker.addNodesToAssetFieldVariable > type: semicolon-separated list of {field}:{comma-separated list of values}, required: no, default: `addNodesToAssetField`, version: 2.0+ The variable for the nodes to add to node-referencing information fields on assets. The field can be an alias or a node information field id. The values can be aliases or node ids. E.g. `channels:youtube,vimeo;copyright:protected` ##### camundaCore.updateAssetOrNode.worker.addNodesToNodeFieldVariable > type: semicolon-separated list of {field}:{comma-separated list of values}, required: no, default: `addNodesToNodeField`, version: 2.0+ The variable for the nodes to add to node-referencing information fields on nodes. ##### camundaCore.updateAssetOrNode.worker.removeNodesFromAssetFieldVariable > type: semicolon-separated list of {field}:{comma-separated list of values}, required: no, default: `removeNodesFromAssetField`, version: 2.0+ The variable for the nodes to remove from node-referencing information fields on assets. ##### camundaCore.updateAssetOrNode.worker.removeNodesFromNodeFieldVariable > type: semicolon-separated list of {field}:{comma-separated list of values}, required: no, default: `removeNodesFromNodeField`, version: 2.0+ The variable for the nodes to remove from node-referencing information fields on nodes. ### Get asset/node value worker An asset worker updating variables from assets/nodes. Listens to the topic `getAssetOrNode`. See update asset/node values worker. ##### camundaCore.getAssetOrNode.worker.enabled > type: boolean, required: no, default: `false`, version: 2.0+ Enables the get asset or node value worker. ##### camundaCore.getAssetOrNode.worker.assetVariable > type: string, required: no, default: `assets`, version: 2.0+ The variable for the assets. The variable can contain comma-separated asset ids and/or variable names of variables with asset ids. ##### camundaCore.getAssetOrNode.worker.nodeVariable > type: string, required: no, default: `nodes`, version: 2.0+ The variable for the nodes. The variable can contain comma-separated node ids and/or variable names of variables with node ids. ##### camundaCore.getAssetOrNode.worker.assetFieldVariable > type: string, required: no, default: `assetFields`, version: 2.0+ The variable for the asset fields. The variable can contain comma-separated variable names and/or information field ids. The information field ids and variable names have to be listed here camundaCore.assetField.{variableName} ##### camundaCore.getAssetOrNode.worker.nodeFieldVariable > type: string, required: no, default: `nodeFields`, version: 2.0+ The variable for the node fields. The variable can contain comma-separated variable names and/or information field ids. The information field ids and variable names have to be listed here camundaCore.nodeField.{variableName} ### Workflow ##### camundaCore.process.historyDaysToLive > type: integer, required: no, default: 30, version: 2.0+ The number of days until a historic task gets cleaned up. 0 for no cleanup. ##### camundaCore.process.adminUser > type: integer (user id), required: no, default: api user, version 2.0+ The user with which the workflows modify the metadata. ##### camundaCore.process.tempNode > type: integer (node id), required: for upload, default: - A node id in which temporary assets are created when uploaded in the workflow. ##### camundaCore.process.tempFolder > type: string (path), required: for upload, default: - A folder in which temporary files are shortly saved for the upload (don't use CELUM's temp folder). ##### camundaCore.task.{processDefinitionKey}.{taskDefinitionKey}.name > type: string (message key), required: no, default: - Specify a (multilingual) title for a task. ##### camundaCore.group.{key}.{recursive} > type: integer (group id), required: no, default: -, version: 2.0+ Defines a group that can be resolved from a variable. E.g. camundaCore.groups.approvers.true=345 would define group 345 as the approvers group (recursive). Now if the mail worker sees "approvers" in the recipients it will send a message to all users in this group (recursive). ##### camundaCore.assetType.{alias} > type: integer (asset type id), required: no, default: -, version: 2.0+ Defines an alias for an asset type. ##### camundaCore.nodeType.{alias} > type: integer (node type id), required: no, default: -, version: 2.0+ Defines an alias for a node type. ##### camundaCore.assetField.{alias/variableName} > type: information field id, required: no, default: -, version: 2.0+ Defines an alias for an asset information field. Special values for fields without ID: - assetName - availability (available, unavailable, date-controlled) - dateFrom (for date-controlled availability) - dateTo (for date-controlled availability) - assetType ##### camundaCore.nodeField.{alias/variableName} > type: information field id, required: no, default: -, version: 2.0+ Defines an alias for a node information field. Special values for fields without ID: - nodeName - nodeType ##### camundaCore.assetField.{alias/variableName}.{valueAlias} > type: integer (node id or dropdown id), required: no, default: -, version 2.0+ Define aliases for values for the given asset field. ##### camundaCore.nodeField.{alias/variableName}.{valueAlias} > type: integer (node id or dropdown id), required: no, default: -, version 2.0+ Define aliases for values for the given node field. ##### camundaCore.variables.assets > type: comma-separated list of variable names, required: no, default: -, version: 2.0+ The variables containing a comma-separated list of asset ids. ##### camundaCore.variables.nodes > type: comma-separated list of variable names, required: no, default: -, version: 2.0+ The variables containing a comma-separated list of node ids. ##### camundaCore.variables.usersOrGroups > type: comma-separated list of variable names, required: no, default: -, version: 2.0+ The variables containing a comma-separated list of Camunda user and/or group ids. It is also possible to have group keys in there. ### Start workflow - The process definition key is stored in the variable "processDefinitionKey". - The assets are stored in the variable "assets". - The nodes are stored in the variable "nodes". - The initiator is stored in the variable "initiator". - The old asset values to reverse them if the workflow is cancelled in the variable "oldAssetValues". - The old node values to reverse them if the workflow is cancelled in the variable "oldNodeValues". ##### camundaCore.start.{processDefinitionKey}.assetScope > type: string, required: no, default: -, version: 2.0+ A [search expression](https://docs.brix.ch/celum_extensions/search_util_2) which defines whether a process can be started or not. Only if there is an assetScope workflows can be started on assets. ##### camundaCore.start.{processDefinitionKey}.nodeScope > type: string, required: no, default: -, version: 2.0+ A scope for nodes on which the workflow can be started. Only if there is a nodeScope workflows can be started on nodes. The following parameters are supported: - **nodes** a list of node ids - **nodeTypes** a list of node type ids - **recursive** (default true), if *recursive* is false and node types is specified then only the root nodes are found - **includeParent** (default false), includes the specified nodes themselves also when *recursive* is true - **excludeNodes** (always recursive and the nodes specified here are included), exclude nodes if it is not possible to get the desired result otherwise, not recommended because it is expensive ##### camundaCore.start.{processDefinitionKey}.minAssets > type: integer, required: no, default: 0, version: 2.0+ The minimum number of assets that have to be selected. ##### camundaCore.start.{processDefinitionKey}.maxAssets > type: integer, required: no, default: 0, version: 2.0+ The maximum number of assets that can be selected (-1 means no upper bound). ##### camundaCore.start.{processDefinitionKey}.minNodes > type: integer, required: no, default: 0, version: 2.0+ The minimum number of nodes that have to be selected. ##### camundaCore.start.{processDefinitionKey}.maxNodes > type: integer, required: no, default: 0, version: 2.0+ The maximum number of nodes that can be selected (-1 means no upper bound). ##### camundaCore.start.{processDefinitionKey}.orMode > type: boolean, required: no, default: false, version: 2.0+ If this is set to true then only the min/max assets condition or the min/max node condition has to apply and not both. This also means that the process can only be started with assets or nodes but not both. ##### camundaCore.start.{processDefinitionKey}.name > type: string, required: no, default: -, version: 2.0+ The human-readable name of the process (message key). ##### camundaCore.start.{processDefinitionKey}.startAllowedUserGroupIds > type: comma-separated list of user group ids, required: no, default: -, version: 2.0+ Users in the specified groups (recursive) are allowed to start the process. ##### camundaCore.start.{processDefinitionKey}.openTasklist > type: boolean, required: no, default: false, version: 2.0+ Whether the tasklist should be opened or not after the process was started. ##### camundaCore.start.{processDefinitionKey}.showRelatedTasks > type: boolean, required: no, default: false, version: 2.0+ Whether assignees can see tasks with the same task definition key in the same process instance or not. ##### camundaCore.start.{processDefinitionKey}.initiatorView > type: boolean, required: no, default: false, version: 2.0+ Whether the initiator can see all the tasks in the processes he started or not. ##### camundaCore.start.{processDefinitionKey}.initiatorEdit > type: boolean, required: no, default: false, version: 2.0+ Whether the initiator can edit all the tasks in the processes he started or not. ##### camundaCore.start.{processDefinitionKey}.setAssetField.{field} > type: string, required: no, default: false, version: 2.0+ The asset fields to be set. {field} can be an alias for a checkbox or a dropdown or the information field id. The value can be an alias for a dropdown value, a dropdown item id or true/false. Those fields should be used to prevent the start of the same workflow with the same asset. ##### camundaCore.start.{processDefinitionKey}.setNodeField.{field} > type: string, required: no, default: false, version: 2.0+ The asset fields to be set. {field} can be an alias for a checkbox or a dropdown or the information field id. The value can be an alias for a dropdown value, a dropdown item id or true/false. Those fields should be used to prevent the start of the same workflow with the same node. ### Forms ##### camundaCore.forms.{task}.{key} > type: string, required: no, default: false, version: 2.0+ Defines a form for a task definition key {task}. The {key} is the form entry key which should be returned as variable with the value. A form entry consists of the following semi-colon separated parts: 1. type: assetName, nodeName, assetType, nodeType, availability, info_{id}, file, text, textarea, checkbox, tab (dummy property) 2. name: message key 3. enabled: true/false 4. required: true/false 5. position: int 6. value: Object, depends 7. placeholder: message key 8. variable name 9. options: JSON Options Options: - [users: array of Users] - [values: array of ListValue] - max: int - min: int - locales: array of locales - format: string - restriction: string (e.g. "future" for dates) - [dateFrom: date] - [dateTo: date] - mandatoryWith: array of string (keys of other fields) - tab: string (key of the tab) - tooltip: message key - passwordProtected: true/false (enough to list for one field, so the whole form gets password protected) - abort: array of string (initiator, assignee, candidates, editors, viewers) ## Deployments ### Dev Deployments 1. Stop the CELUM app server service 2. Stop the Camunda service 3. Update the Camunda *.jar-File 4. Update the Camunda connector for CELUM (either core or customized extension) 5. Delete the Camunda tables in the Camunda database 6. Start the Camunda service 7. Start the CELUM app server service 8. Run the "Camunda > User and Group Sync Sanitize" system task in CELUM ### Prod Deployments 1. Stop the CELUM app server service 2. Stop the Camunda service 3. Update the Camunda *.jar-File 4. Start the Camunda service 5. Migrate the running process instances if required (or skip this step and let them complete using the old process definition) 6. Update the Camunda connector for CELUM (either core or customized extension) 7. Start the CELUM app server service 8. If the process instances weren't migrated, wait until all old process instances have finished and then do a clean-up of the stuff in CELUM that was only needed for the previous process definition and is removable now (e.g. information fields that aren't needed anymore) ## Compatibility Matrix | Camunda Core | CELUM | :----- | :----- | 1.0.0 | 5.13.4 (tested with 6.4) | | 2.0.0 | 6.4+ | ## Release Notes ##### 1.0.0 > Released 2020-03-09 Initial version