From 3aa5f36ced7549cf11122c95f699e28387031dcc Mon Sep 17 00:00:00 2001 From: "S.Listl" <S.Listl@SLISTL.aditosoftware.local> Date: Fri, 6 Mar 2020 16:00:22 +0100 Subject: [PATCH] Webservices for flowable-modeler --- .../recordcontainers/jdito/contentProcess.js | 6 +- .../_____LANGUAGE_EXTRA.aod | 3 + .../_____LANGUAGE_de/_____LANGUAGE_de.aod | 7 +- .../_____LANGUAGE_en/_____LANGUAGE_en.aod | 3 + process/Sql_lib/documentation.adoc | 18 +++ process/workflowPrivileges_rest/process.js | 70 +++++++++++ .../workflowPrivileges_rest.aod | 14 +++ process/workflowRoles_rest/process.js | 81 ++++++++++++ .../workflowRoles_rest/workflowRoles_rest.aod | 14 +++ process/workflowUsers_rest/process.js | 118 ++++++++++++++---- .../workflowUsers_rest/workflowUsers_rest.aod | 3 +- role/PROJECT_Workflow/PROJECT_Workflow.aod | 6 + 12 files changed, 312 insertions(+), 31 deletions(-) create mode 100644 process/workflowPrivileges_rest/process.js create mode 100644 process/workflowPrivileges_rest/workflowPrivileges_rest.aod create mode 100644 process/workflowRoles_rest/process.js create mode 100644 process/workflowRoles_rest/workflowRoles_rest.aod create mode 100644 role/PROJECT_Workflow/PROJECT_Workflow.aod diff --git a/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js b/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js index 44b94eb5a22..50cb3e1f446 100644 --- a/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js @@ -34,15 +34,15 @@ result.object((function () } else { - // if (isOnlyForCurrentUser) - // loadConfig.candidateIdentifier(EmployeeUtils.getCurrentUserId()); + if (isOnlyForCurrentUser) + loadConfig.candidateIdentifier(EmployeeUtils.getCurrentUserId()); if (processInstanceId) loadConfig.processInstanceId(processInstanceId); } var tasks = JSON.parse(onlyFinished ? workflow.getHistoricTasks(loadConfig) - : workflow.getTasks(loadConfig)); + : workflow.getTasks(loadConfig)) || []; //it is possible that a task is requested that was just finished -> if a task with given id could not be found, try to load it from historic tasks if (tasks.length === 0 && taskIds && taskIds.length > 0 && !onlyFinished) diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod index 38cd6d2cb61..104cbcd35be 100644 --- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod +++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod @@ -6095,6 +6095,9 @@ <entry> <key>Resume</key> </entry> + <entry> + <key>Finished tasks</key> + </entry> </keyValueMap> <font name="Dialog" style="0" size="11" /> <sqlModels> diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod index cb56cd502ce..88d7a085aa1 100644 --- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod +++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod @@ -2131,7 +2131,7 @@ </entry> <entry> <key>Workflow instances</key> - <value>Vorgangsinstanzen</value> + <value>Prozessinstanzen</value> </entry> <entry> <key>{$TASK_PRIORITY_NONE}</key> @@ -6921,7 +6921,7 @@ </entry> <entry> <key>Workflow instance</key> - <value>Vorgangsinstanz</value> + <value>Prozessinstanz</value> </entry> <entry> <key>Source duplicate</key> @@ -7723,7 +7723,7 @@ Bitte Datumseingabe prüfen</value> </entry> <entry> <key>Workflow</key> - <value>Vorgang</value> + <value>Prozess</value> </entry> <entry> <key>Campaign steps </key> @@ -7802,6 +7802,7 @@ Bitte Datumseingabe prüfen</value> </entry> <entry> <key>Workflow definitions</key> + <value>Prozessdefinitionen</value> </entry> <entry> <key>Version</key> diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod index a81de862077..8c69eed791a 100644 --- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod +++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod @@ -6153,6 +6153,9 @@ <entry> <key>Resume</key> </entry> + <entry> + <key>Finished tasks</key> + </entry> </keyValueMap> <font name="Dialog" style="0" size="11" /> </language> diff --git a/process/Sql_lib/documentation.adoc b/process/Sql_lib/documentation.adoc index 2017f4b9646..33dc30f6edc 100644 --- a/process/Sql_lib/documentation.adoc +++ b/process/Sql_lib/documentation.adoc @@ -262,6 +262,24 @@ var costData = newSelect("CAMPAIGNCOSTID, CAMPAIGNSTEP_ID, CAMPAIGNSTEP.NAME, CA .table(); ---- +=== apply + +WARNING: Not all databases support "outer apply" or "cross apply". + +An apply can also be added via `.join`. If you set the parameter `pReplacementForWordJoin`, the given keyword will be used instead of "join". + +Here's an example for the usage of "outer apply": +[source,js] +---- +var activitySelect = newSelect("SUBJECT, INFO, personLink.OBJECT_ROWID") + .from("ACTIVITY") + .join( + newSelect("OBJECT_ROWID") + .from("ACTIVITYLINK") + .where("ACTIVITYLINK.OBJECT_TYPE", "Person"), + null, "personLink", "outer", "apply"); //it would also be possible to omit pPrefix and then write "outer apply" +---- + === group by `groupBy(pFields)` adds a group by statement to the SQL code. The parameter can be filled the same way as `.select(pFields)`. diff --git a/process/workflowPrivileges_rest/process.js b/process/workflowPrivileges_rest/process.js new file mode 100644 index 00000000000..b6efb5d9f06 --- /dev/null +++ b/process/workflowPrivileges_rest/process.js @@ -0,0 +1,70 @@ +import("system.text"); +import("system.tools"); + +function restget (pRequest) +{ + let request = JSON.parse(pRequest); + let header = request.header; + let privFilter = header.Privfilter + ? JSON.parse(header.Privfilter) + : {}; + + let privileges = { + ACCESS_IDM : { + id : "access-idm-f8-4e7f-85ac-57ae095925ec", + name : "access-idm" + }, + ACCESS_MODELER : { + id : "access-modeler-50e-a22d-b9acb75047d7", + name : "access-modeler" + }, + ACCESS_ADMIN : { + id : "access-admin-346a6-b871-bc5f7be120a2", + name : "access-admin" + }, + ACCESS_TASK : { + id : "access-task-9-4398-a1b5-3ae642de2169", + name : "access-task" + }, + ACCESS_REST_API : { + id : "access-rest-api-0b-990a-f1b27506ed80", + name : "access-rest-api" + } + }; + let privilegeArray = [privileges.ACCESS_IDM, privileges.ACCESS_MODELER, privileges.ACCESS_ADMIN, privileges.ACCESS_TASK, privileges.ACCESS_REST_API]; + if (privFilter.id) + { + let privilege = privilegeArray.find(function (priv) + { + return priv.id == privFilter.id; + }); + privilegeArray = privilege ? [privilege] : []; + } + if (privFilter.name) + { + let privilege = privilegeArray.find(function (priv) + { + return priv.name == privFilter.name; + }); + privilegeArray = privilege ? [privilege] : []; + } + + let roles; + if (privFilter.userId) + { + let user = tools.getUserByAttribute(tools.NAME, privFilter.userId); + roles = user ? user[tools.ROLENAMES].slice() : []; + } + else if (privFilter.groupId) + roles = [privFilter.groupId]; + else + roles = privFilter.groupIds; + + let filteredPrivileges = []; + if (!roles || roles.indexOf("PROJECT_Workflow") !== -1 || roles.indexOf("INTERNAL_ADMINISTRATOR") !== -1) + filteredPrivileges = privilegeArray; + + request.response.body = JSON.stringify(filteredPrivileges); + + return JSON.stringify(request); +} diff --git a/process/workflowPrivileges_rest/workflowPrivileges_rest.aod b/process/workflowPrivileges_rest/workflowPrivileges_rest.aod new file mode 100644 index 00000000000..5a75e4758d9 --- /dev/null +++ b/process/workflowPrivileges_rest/workflowPrivileges_rest.aod @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>workflowPrivileges_rest</name> + <majorModelMode>DISTRIBUTED</majorModelMode> + <process>%aditoprj%/process/workflowPrivileges_rest/process.js</process> + <publishAsWebservice v="false" /> + <style>REST</style> + <restAcceptedMimeType>application/json</restAcceptedMimeType> + <restDeliveredMimeType>application/json</restDeliveredMimeType> + <jditoWebserviceUser>flowableIdmService</jditoWebserviceUser> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/workflowRoles_rest/process.js b/process/workflowRoles_rest/process.js new file mode 100644 index 00000000000..07b379e4fd8 --- /dev/null +++ b/process/workflowRoles_rest/process.js @@ -0,0 +1,81 @@ +import("system.text"); +import("system.tools"); + +function restget (pRequest) +{ + let request = JSON.parse(pRequest); + let header = request.header; + let roleIds = header.Ids && JSON.parse(header.Ids); + let userId = header.Userid; + + if (userId) + { + let user = tools.getUserByAttribute(tools.NAME, userId); + roleIds = user ? user[tools.ROLENAMES].slice() : []; + } + + let roles = tools.getAllRoles([tools.ROLE_PROJECT, tools.ROLE_CUSTOM], false); + roles = Object.keys(roles).map(function (role) + { + let [title, type, desc, id] = roles[role]; + return { + name : title, + id : id, + type : type + }; + }); + + let filter = { + EQUAL : "equal", + IGNORECASE : "ignoreCase", + IN : "in", + LIKE : "like", + LIKEIGNORECASE : "likeIgnoreCase", + + _filters : [], + addIfSet : function (pUserPropertyName, pFilterValue, pType) + { + if (pFilterValue && pFilterValue.length !== 0) + this.add(pUserPropertyName, pFilterValue, pType); + }, + add : function (pUserPropertyName, pFilterValue, pType) + { + this._filters.push([pUserPropertyName, pFilterValue, pType]); + }, + check : function (pUser) + { + return this._filters.every(function ([prop, value, type]) + { + let userValue = pUser[prop] || ""; + let flags; + switch (type) + { + case this.EQUAL: + return userValue == value; + case this.IGNORECASE: + return userValue.toUpperCase() == value.toUpperCase(); + case this.IN: + return value.indexOf(userValue) !== -1; + case this.LIKEIGNORECASE: + flags = "i"; + case this.LIKE: + value = text.replaceAll(value, {"%" : ".*", "_" : "."}); + return new RegExp(value, flags).test(userValue); + } + return false; + }, this); + } + }; + + filter.addIfSet("id", header.Id, filter.EQUAL); + filter.addIfSet("id", roleIds, filter.IN); + filter.addIfSet("name", header.Name, filter.EQUAL); + filter.addIfSet("name", header.Namelike, filter.LIKE); + filter.addIfSet("name", header.Namelikeignorecase, filter.LIKEIGNORECASE); + + roles = roles.filter(filter.check, filter); + + request.response.body = JSON.stringify(roles); + + return JSON.stringify(request); +} diff --git a/process/workflowRoles_rest/workflowRoles_rest.aod b/process/workflowRoles_rest/workflowRoles_rest.aod new file mode 100644 index 00000000000..7bdd09bfb46 --- /dev/null +++ b/process/workflowRoles_rest/workflowRoles_rest.aod @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>workflowRoles_rest</name> + <majorModelMode>DISTRIBUTED</majorModelMode> + <process>%aditoprj%/process/workflowRoles_rest/process.js</process> + <publishAsWebservice v="false" /> + <style>REST</style> + <restAcceptedMimeType>application/json</restAcceptedMimeType> + <restDeliveredMimeType>application/json</restDeliveredMimeType> + <jditoWebserviceUser>flowableIdmService</jditoWebserviceUser> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/workflowUsers_rest/process.js b/process/workflowUsers_rest/process.js index 80446eb27dc..6f33fd3573c 100644 --- a/process/workflowUsers_rest/process.js +++ b/process/workflowUsers_rest/process.js @@ -1,3 +1,4 @@ +import("system.text"); import("system.vars"); import("system.logging"); import("system.tools"); @@ -10,19 +11,90 @@ function restget (pRequest) const MIN_SEARCHLENGTH = 0; let request = JSON.parse(pRequest); - let searchValue = request.header.filter || request.header.Filter; - - request.response.body = JSON.stringify({users : _getUsers(searchValue)}); + let header = request.header; + let userFilter = header.Userfilter + ? JSON.parse(header.Userfilter) + : {}; + + //object that helps with filtering, it provides functions for adding conditions to the object and for checking the conditions + let filter = { + EQUAL : "equal", + IGNORECASE : "ignoreCase", + IN : "in", + ANY_IN : "anyIn", + LIKE : "like", + LIKEIGNORECASE : "likeIgnoreCase", + + _filters : [], + addIfSet : function (pUserPropertyName, pFilterValue, pType) + { + if (pFilterValue && pFilterValue.length !== 0) + this.add(pUserPropertyName, pFilterValue, pType); + }, + add : function (pUserPropertyName, pFilterValue, pType) + { + this._filters.push([pUserPropertyName, pFilterValue, pType]); + }, + check : function (pUser) + { + return this._filters.every(function ([prop, value, type]) + { + let userValue = pUser[prop] || ""; + let flags; + switch (type) + { + case this.EQUAL: + return userValue == value; + case this.IGNORECASE: + return userValue.toUpperCase() == value.toUpperCase(); + case this.IN: + if (Array.isArray(userValue)) + return userValue.indexOf(value) !== -1; + return value.indexOf(userValue) !== -1; + case this.ANY_IN: + return value.some(function (val) {return userValue.indexOf(val) !== -1;}); + case this.LIKEIGNORECASE: + flags = "i"; + case this.LIKE: + value = text.replaceAll(value, {"%" : ".*", "_" : "."}); + return new RegExp(value, flags).test(userValue); + } + return false; + }, this); + } + }; + + filter.addIfSet("id", userFilter.id, filter.EQUAL); + filter.addIfSet("id", userFilter.ids && JSON.parse(userFilter.ids), filter.IN); + filter.addIfSet("id", userFilter.idIgnoreCase, filter.IGNORECASE); + filter.addIfSet("lastName", userFilter.lastName, filter.EQUAL); + filter.addIfSet("lastName", userFilter.lastNameLike, filter.LIKE); + filter.addIfSet("lastName", userFilter.lastNameLikeIgnoreCase, filter.LIKEIGNORECASE); + filter.addIfSet("firstName", userFilter.firstName, filter.EQUAL); + filter.addIfSet("firstName", userFilter.firstNameLike, filter.LIKE); + filter.addIfSet("firstName", userFilter.firstNameLikeIgnoreCase, filter.LIKEIGNORECASE); + filter.addIfSet("fullName", userFilter.displayName, filter.EQUAL); + filter.addIfSet("fullName", userFilter.displayNameLike, filter.LIKE); + filter.addIfSet("fullName", userFilter.displayNameLikeIgnoreCase, filter.LIKEIGNORECASE); + filter.addIfSet("fullName", userFilter.fullNameLike, filter.LIKE); +// filter.addIfSet("fullName", userFilter.Fullnamelikeignorecase, filter.LIKEIGNORECASE); + filter.addIfSet("email", userFilter.email, filter.EQUAL); + filter.addIfSet("email", userFilter.emailLike, filter.LIKE); + filter.addIfSet("groups", userFilter.groupIds && JSON.parse(userFilter.groupIds), filter.ANY_IN); + filter.addIfSet("groups", userFilter.groupId, filter.IN); + + request.response.body = JSON.stringify(_getUsers(userFilter.fullNameLikeIgnoreCase)); return JSON.stringify(request); function _getUsers (pSearch) { - if (pSearch === undefined || pSearch.trim() < MIN_SEARCHLENGTH) + if (pSearch !== undefined && pSearch.trim() < MIN_SEARCHLENGTH) return []; //separate words by spaces - let patterns = pSearch.toUpperCase().split(/\s/).filter(function (pat) {return pat;}); + let patterns = pSearch && pSearch.replace("%", "", "g").toUpperCase().split(/\s/).filter(function (pat) {return pat;}) + let allUsers = tools.getUsersByAttribute(tools.ISACTIVE, ["true"], tools.PROFILE_DEFAULT); let resultUsers = []; @@ -30,25 +102,25 @@ function restget (pRequest) for (let i = 0, l = allUsers.length; i < l; i++) { let user = allUsers[i]; - let id = user[tools.NAME]; let firstName = user[tools.PARAMS][tools.FIRSTNAME]; let lastName = user[tools.PARAMS][tools.LASTNAME]; - let email = user[tools.EMAIL]; - let rating = _getRating(patterns, [firstName.toUpperCase(), lastName.toUpperCase()]); - if (rating !== 0) - { - resultUsers.push({ - id : id, - firstName : firstName, - lastName : lastName, - email : email, - fullName : (firstName + " " + lastName).trim(), - tenantId : null, - groups : [], - privileges : [], - searchRating : rating - }); - } + let rating = patterns + ? _getRating(patterns, [firstName.toUpperCase(), lastName.toUpperCase()]) + : 1; + + user = { + id : user[tools.NAME], + firstName : firstName, + lastName : lastName, + email : user[tools.PARAMS][tools.EMAIL], + fullName : (firstName + " " + lastName).trim(), + tenantId : null, + groups : user[tools.ROLENAMES].slice(), + privileges : [], + searchRating : rating + }; + if (filter.check(user) && rating !== 0) + resultUsers.push(user); } //sort by result quality @@ -56,7 +128,7 @@ function restget (pRequest) { return b.searchRating - a.searchRating; }); - + return resultUsers.slice(0, MAX_COUNT); } diff --git a/process/workflowUsers_rest/workflowUsers_rest.aod b/process/workflowUsers_rest/workflowUsers_rest.aod index 2b745c8a376..c44615d096e 100644 --- a/process/workflowUsers_rest/workflowUsers_rest.aod +++ b/process/workflowUsers_rest/workflowUsers_rest.aod @@ -7,8 +7,7 @@ <style>REST</style> <restAcceptedMimeType>application/json</restAcceptedMimeType> <restDeliveredMimeType>application/json</restDeliveredMimeType> - <loginTypeId>internal.none</loginTypeId> - <restrictedRoles /> + <jditoWebserviceUser>flowableIdmService</jditoWebserviceUser> <variants> <element>EXECUTABLE</element> </variants> diff --git a/role/PROJECT_Workflow/PROJECT_Workflow.aod b/role/PROJECT_Workflow/PROJECT_Workflow.aod new file mode 100644 index 00000000000..06f9449d5f5 --- /dev/null +++ b/role/PROJECT_Workflow/PROJECT_Workflow.aod @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<role xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/role/1.2.0"> + <name>PROJECT_Workflow</name> + <title>Workflow management</title> + <majorModelMode>DISTRIBUTED</majorModelMode> +</role> -- GitLab