diff --git a/entity/Notification_entity/Notification_entity.aod b/entity/Notification_entity/Notification_entity.aod index 494d9bcb8bb3bb1e0d9a3be80e0a0db20de09761..2374ea30f1a06418f85eb7fdb62ae2212cc8eb20 100644 --- a/entity/Notification_entity/Notification_entity.aod +++ b/entity/Notification_entity/Notification_entity.aod @@ -48,6 +48,7 @@ <entityField> <name>DESCRIPTION</name> <title>Description</title> + <contentType>HTML</contentType> </entityField> <entityField> <name>FORCEDPRIORITY</name> diff --git a/entity/Observation_entity/Observation_entity.aod b/entity/Observation_entity/Observation_entity.aod index e69c04a5bb10203a45c74ee574f84a18567d3231..dd75d356f6dbf53cb772829dee427a5bd1a5caa2 100644 --- a/entity/Observation_entity/Observation_entity.aod +++ b/entity/Observation_entity/Observation_entity.aod @@ -43,6 +43,7 @@ <consumer>Users</consumer> <groupable v="true" /> <mandatory v="true" /> + <state>DISABLED</state> <valueProcess>%aditoprj%/entity/Observation_entity/entityfields/observer/valueProcess.js</valueProcess> <displayValueProcess>%aditoprj%/entity/Observation_entity/entityfields/observer/displayValueProcess.js</displayValueProcess> </entityField> diff --git a/entity/Observation_entity/documentation.adoc b/entity/Observation_entity/documentation.adoc index 5968fb30c133a2a4193a1de4fa8c0e2655281b7f..4337e3eb2962ea51bf3afed9e58f06e13644137d 100644 --- a/entity/Observation_entity/documentation.adoc +++ b/entity/Observation_entity/documentation.adoc @@ -19,4 +19,3 @@ inserted, updated or deleted. * Enable the custom field observation.isEnabled in the _____PREFERENCES_PROJECT * Create the Observation Context and add the Entity, the Views (ObservationEdit_view, ObservationFilter_view, ObservationPreview_view), the Icon (VAADIN:EYE) and the Tile "Observation" to it - diff --git a/entity/Observation_entity/entityfields/includedependencies/valueProcess.js b/entity/Observation_entity/entityfields/includedependencies/valueProcess.js index 17d96815f787ef6b77dd7e341456d3c52a69f46a..13e327167d0c0540abfe928c87bdd43d4f9298b9 100644 --- a/entity/Observation_entity/entityfields/includedependencies/valueProcess.js +++ b/entity/Observation_entity/entityfields/includedependencies/valueProcess.js @@ -4,7 +4,7 @@ import("system.result"); let isIncluded; -if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$this.value") == null) +if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW) { if (vars.get("$field.OBSERVATION_ID")) { diff --git a/entity/Person_entity/entityfields/filterviewactiongroup/children/observe/stateProcess.js b/entity/Person_entity/entityfields/filterviewactiongroup/children/observe/stateProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..84fd36a56b2c734b33329288dd586315fa8bab70 --- /dev/null +++ b/entity/Person_entity/entityfields/filterviewactiongroup/children/observe/stateProcess.js @@ -0,0 +1,5 @@ +import("system.vars"); +import("system.result"); +import("Observation_lib"); + +result.string(Observation.actionState(vars.get("$sys.selection"))); \ No newline at end of file diff --git a/neonContext/Observation/Observation.aod b/neonContext/Observation/Observation.aod new file mode 100644 index 0000000000000000000000000000000000000000..aeab7d749b7e799c4c22e6d58f55bbc73c5be06c --- /dev/null +++ b/neonContext/Observation/Observation.aod @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.1"> + <name>Observation</name> + <title>Observation</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:EYE</icon> + <filterView>ObservationFilter_view</filterView> + <editView>ObservationEdit_view</editView> + <previewView>ObservationPreview_view</previewView> + <entity>Observation_entity</entity> + <references> + <neonViewReference> + <name>081e645d-ede7-4987-891c-725e2300c7a0</name> + <view>ObservationFilter_view</view> + </neonViewReference> + <neonViewReference> + <name>381da87e-006b-4fd6-b2b2-18e53d675928</name> + <view>ObservationEdit_view</view> + </neonViewReference> + <neonViewReference> + <name>8e1417a2-f172-451f-9e76-81b852abcaa1</name> + <view>ObservationPreview_view</view> + </neonViewReference> + </references> +</neonContext> diff --git a/neonView/ObservationEdit_view/ObservationEdit_view.aod b/neonView/ObservationEdit_view/ObservationEdit_view.aod index bba30a064ed46a6f57d1c974e43ed69f1a520add..01b240c0985dfd09e6e6198a126c55c2c87e5ecd 100644 --- a/neonView/ObservationEdit_view/ObservationEdit_view.aod +++ b/neonView/ObservationEdit_view/ObservationEdit_view.aod @@ -46,7 +46,8 @@ <entityField>TRIGGEREVENTDELETE</entityField> </entityFieldLink> <entityFieldLink> - <name>aa93c341-578b-4da9-8ee8-2b3d9ea9e1ca</name> + <name>ac899215-4356-4034-b263-d40807f0b0f1</name> + <entityField>includeDependencies</entityField> </entityFieldLink> <entityFieldLink> <name>c6fa82e2-5830-46c5-9127-e273ddf5a194</name> diff --git a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod index 0dc3f425be8aadf22bab652c555f49cd82d728fb..8e1dc8e20846a3f20c7a727afd5bcb62024d69f6 100644 --- a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod +++ b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod @@ -175,7 +175,7 @@ <customBooleanProperty> <name>observation.isEnabled</name> <description>Whether the observations are enabled or not</description> - <property v="false" /> + <property v="true" /> </customBooleanProperty> <customBooleanProperty> <name>observation.isMultiselectionEnabled</name> diff --git a/process/Dependency_lib/process.js b/process/Dependency_lib/process.js index 54305d6527bdc2b883fe62e567a560c06684f0a6..488e2f54086286b280071c73f1a6c6c9cff1dffa 100644 --- a/process/Dependency_lib/process.js +++ b/process/Dependency_lib/process.js @@ -75,7 +75,7 @@ Dependency.defaultFunctionForRelation = function (pRelationTable, pRelationField return newSelect(pRelationTable + "." + (pSourceField || "OBJECT_ROWID")) .from(pRelationTable) - .groupBy(pRelationTable + "." + pSourceField || "OBJECT_ROWID") + .groupBy(pRelationTable + "." + (pSourceField || "OBJECT_ROWID")) .whereIfSet(pRelationTable + "." + pRelationField, relationFieldValue) .andIfSet(pRelationTable + ".OBJECT_TYPE", pContext) .arrayColumn(); @@ -133,7 +133,8 @@ Dependency.mapping = function () "Person_entity": { "Activity_entity" : { "options" : { - "isObservable" : true + "isObservable" : true, + "isOwnNotified" : true }, "getUIDsfn" : Dependency.defaultFunctionForRelation("ACTIVITYLINK", "OBJECT_ROWID", "CONTACTID", "Person", "CONTACT", "ACTIVITY_ID") }, @@ -338,7 +339,8 @@ Dependency.mapping = function () "Activity_entity" : { "Person_entity" : { "options" : { - "isObservable" : true + "isObservable" : true, + "isOwnNotified" : true }, "getUIDsfn" : Dependency.defaultFunctionForRelation("ACTIVITYLINK", "ACTIVITY_ID", "ACTIVITYID", "Person", "ACTIVITY") }, diff --git a/process/Observation_lib/process.js b/process/Observation_lib/process.js index b67681a7849ecdad075089797c7084260d5934c7..51e6bfcf7ebcccc182274335db9eb08593d52938 100644 --- a/process/Observation_lib/process.js +++ b/process/Observation_lib/process.js @@ -1,3 +1,4 @@ +import("Util_lib"); import("system.neon"); import("KeywordRegistry_basic"); import("system.logging"); @@ -20,23 +21,43 @@ import("system.db"); import("system.favorite"); import("system.neon"); -function Observation(){} +/** + * This class handels the Observations. + * + * @class + */ +function Observation(pVariable, pStoredFilterResults, pStoredObservedFields) +{ + this.callerVariables = pVariable || {}; + this.storedFilterResults = pStoredFilterResults || {}; + this.storedObservedFields = pStoredObservedFields || {}; +} -Observation.OBJECT_TYPE = function () { +Observation.OBJECT_TYPE = function () +{ return "OBJECT_TYPE_Dependency"; } -Observation.OBJECT_IDs = function () { +Observation.OBJECT_IDs = function () +{ return "OBJECT_IDs_Dependency"; } -Observation.PRIO = function () { - return "PRIORITY"; +Observation.PRIO = function () +{ + return "PRIORITY_NOTIFICATION_Observation"; } -Observation.CONTENTTITLE = function () { +Observation.CONTENTTITLE = function () +{ return "OBJECT_CONTENTTITLE"; } -Observation.ENTITY_NAME = function () { +Observation.ENTITY_NAME = function () +{ return "ENTITY_NAME"; } +Observation.RECORDS_SPECIFIC_VALUES = function () +{ + return "RECORDS_SPECIFIC_VALUES"; +} + /** * Thees are the Entities which can be selected in the ObservationFilter_view if you have the rights. */ @@ -68,170 +89,340 @@ Observation.OBSERVABLE_ENTITIES = function () { Observation.parseVariableIfNeed = function(pVariables,pVariable) { if (pVariables[pVariable] && typeof pVariables[pVariable] !== 'object' && pVariables[pVariable] !== null) + { pVariables[pVariable] = JSON.parse(pVariables[pVariable]); + } } /** - * Checks the observations for the specific changed data set and then forwards them to the Observation._notifiyUsers() function. + * Bringing variables into the right format. This fucntion is call by reference. * * @param {Object} [pVariables] the Variables which were set in the Workflow_lib - * @param {String} [pObservationId] the id of the parent observation. This variable is required for the recursion. - * * @return {Void} */ -Observation.checkObservation = function(pVariables, pObservationId) +Observation.parseALLVariable = function(pVariables) { - if (pVariables[WorkflowVariables.TRIGGER()]) + Observation.parseVariableIfNeed(pVariables, WorkflowVariables.CHANGED_ROWS()); + Observation.parseVariableIfNeed(pVariables, WorkflowVariables.CHANGED_ROWS_TYPES()); + Observation.parseVariableIfNeed(pVariables, WorkflowVariables.ROWDATA()); + Observation.parseVariableIfNeed(pVariables, WorkflowVariables.INITIAL_ROWDATA()); + Observation.parseVariableIfNeed(pVariables, WorkflowVariables.FIELDS_TO_LOAD()); + pVariables[Observation.ENTITY_NAME()] = ContextUtils.getEntity(pVariables[WorkflowVariables.TARGET_CONTEXT()]); + + try { - // parse all JSON-Objects - Observation.parseVariableIfNeed(pVariables, WorkflowVariables.CHANGED_ROWS()); - Observation.parseVariableIfNeed(pVariables, WorkflowVariables.CHANGED_ROWS_TYPES()); - Observation.parseVariableIfNeed(pVariables, WorkflowVariables.ROWDATA()); - Observation.parseVariableIfNeed(pVariables, WorkflowVariables.INITIAL_ROWDATA()); - pVariables[Observation.ENTITY_NAME] = ContextUtils.getEntity(pVariables[WorkflowVariables.TARGET_CONTEXT()]); + Observation.parseVariableIfNeed(pVariables, WorkflowVariables.TARGET_ID()); + } + catch (e if e instanceof SyntaxError) + { + let id = pVariables[WorkflowVariables.TARGET_ID()]; + // If in the Variable is only a singel variabel in string format + if (id) + { + pVariables[WorkflowVariables.TARGET_ID()] = [id]; + } + else + { + throw e; + } + } +} + +/** + * Get all Observations + * + * @param {Void} [pTriger] the trigger of the change e.g. "TRIGGEREVENTUPDATE, TRIGGEREVENTDELETE, TRIGGEREVENTINSERT" + * @param {Void} [pTargetIds] the object id of the changed row + * @param {Void} [pTargetContext] the context of the changed row + * @param {Void} [pObservationId] the id of the parend observation + * @return {Array[][]} + */ +Observation.getObservations = function(pTriger, pTargetIds, pTargetContext, pObservationId) +{ + + // get all observations with the ovservers + let observations = newSelect(["OBSERVATION.OBJECT_ID", "OBSERVATION.OBJECT_FILTER" ,"OBSERVATION.OBSERVER", "OBSERVATION.OBJECT_FIELD", "O.OBJECT_TYPE", "OBSERVATION.OBSERVATION_ID", "OBSERVATION.NOTIFICATION_PRIO"]) + .from("OBSERVATION") + .leftJoin("OBSERVATION", "OBSERVATION.OBSERVATION_ID = O.OBSERVATIONID", "O") + .where( + newWhereIfSet("OBSERVATION.OBJECT_ID", pTargetIds, SqlBuilder.IN()) + .or("OBSERVATION.OBJECT_ID IS NULL")) + .and("OBSERVATION.OBJECT_TYPE", pTargetContext); - var observers = {}; - // get all observations with the ovservers - var observations = newSelect(["OBSERVATION.OBJECT_ID", "OBSERVATION.OBJECT_FILTER" ,"OBSERVATION.OBSERVER", "OBSERVATION.OBJECT_FIELD", "O.OBJECT_TYPE", "OBSERVATION.OBSERVATION_ID", "OBSERVATION.NOTIFICATION_PRIO"]) - .from("OBSERVATION") - .leftJoin("OBSERVATION", "OBSERVATION.OBSERVATION_ID = O.OBSERVATIONID", "O") - .where( - newWhere("OBSERVATION.OBJECT_ID", pVariables[WorkflowVariables.TARGET_ID()]) - .or("OBSERVATION.OBJECT_ID IS NULL")) - .and("OBSERVATION.OBJECT_TYPE", pVariables[WorkflowVariables.TARGET_CONTEXT()]); + if (pObservationId) + { + // if the variable is set the parend observation is search for. + observations.andIfSet("OBSERVATION.OBSERVATIONID", pObservationId) + } + else + { + observations.and("OBSERVATION." + pTriger, "1"); + } - if (pObservationId) + return observations.table(); +} + +/** + * Look whether the ids are in the filter object included and the observer has the permissions to see the data sets. + * + * @param {Void} [pUserTitle] the title of the observer + * @param {Void} [pFilterObject] the filterobject with the observer is observing + * @param {Void} [pID] the data row with the observer is observing + * @return {Array} + */ +Observation.prototype.checkFilterAndPermissions = function (pUserTitle, pFilterObject, pID) +{ + let storedIndex = pUserTitle; + let filterResult = {}; + var config = entities.createConfigForLoadingRows(); + + if (pFilterObject) + { + storedIndex += pFilterObject; + storedIndex += this.callerVariables[WorkflowVariables.TARGET_ID()]; + config.filter(JSON.stringify(JSON.parse(pFilterObject).filter)) + .uids(this.callerVariables[WorkflowVariables.TARGET_ID()]); + } + else // if pFilterObject is null this is an id observation. + { + storedIndex += pID; + config.uids([pID]); + } + + // check if the observation has been alredy checkt + if (this.storedFilterResults[storedIndex]) + { + return this.storedFilterResults[storedIndex]; + } + + try + { + config.user(pUserTitle) + .entity(this.callerVariables[Observation.ENTITY_NAME()]) + .fields(["#UID", "#CONTENTTITLE"].concat(this.callerVariables[WorkflowVariables.FIELDS_TO_LOAD()])); + + entities.getRows(config).forEach(function (pRow) { + if (pRow["#UID"] && pRow["#CONTENTTITLE"]) + { + let res; + if (this.callerVariables[WorkflowVariables.FIELDS_TO_LOAD()]) + { + res = [pRow["#CONTENTTITLE"], pRow] + } + else // if dependency check --> FIELDS_TO_LOAD = null + { + res = pRow["#CONTENTTITLE"] + } + filterResult[pRow["#UID"]] = res; + } + }, this); + } + catch (e) + { + // This Catch is needed for the permission exeptions and the recursion + logging.log(e, logging.ERROR); + filterResult = null; + } + + this.storedFilterResults[storedIndex] = filterResult; + return filterResult +} + +/** + * Parse the observed fields of the observer and filter the ones the observer have no rights out + * + * @param {Void} [pObjectFields] the observed fileds in Multi-string (e.g. "; ;+ ;++ ACTIVITY.DIRECTION;++ DIRECTION;++ ;+ Richtung;+ ; ;+ ;++ ACTIVITY.ENTRYDATE;++ ENTRYDATE;++ ;+ Datum;+ ; ;+ ;++ ACTIVITY.INFO;++ INFO;++ ;+ Beschreibung;+ ; ;+ ;++ ACTIVITY.CATEGORY;++ CATEGORY;++ ;+ Kategorie;+ ; ;+ ;++ ACTIVITY.SUBJECT;++ SUBJECT;++ ;+ Betreff;+ ; ;+ ;++ ACTIVITY.RESPONSIBLE;++ RESPONSIBLE;++ ;+ Verantwortlich;+ ; ") + * @param {Void} [pUserTitle] the observer title + * @return {Object} + */ +Observation.prototype.parseAndFilterObjectFields = function (pObjectFields, pUserTitle) +{ + let storedIndex = pObjectFields + pUserTitle; + + if (this.storedObservedFields[storedIndex]) + { + return this.storedObservedFields[storedIndex] + } + + let observeFields = {}; + observeFields[Observation.RECORDS_SPECIFIC_VALUES()] = {}; + text.decodeMS(pObjectFields).forEach(function (observeFiled) { + let field = text.decodeMS(observeFiled); + let fieldNames = text.decodeMS(field[0]); + if (this.callerVariables[WorkflowVariables.CHANGED_ROWS()].indexOf(fieldNames[0]) > -1) { - // if the variable is set the parend observation is search for. - observations.andIfSet("OBSERVATION.OBSERVATIONID", pObservationId) + let displayValueField = "#COLUMNEXP_____" + fieldNames[1] + ".displayValue"; + let observedField = this.callerVariables[WorkflowVariables.ROWDATA()][displayValueField] ? displayValueField : fieldNames[0]; + if (tools.hasPermission(tools.PERMISSION_VIEW, this.callerVariables[Observation.ENTITY_NAME()], fieldNames[1], pUserTitle)) + { + observeFields[observedField] = field[1]; + } } - else + }, this); + + this.storedObservedFields[storedIndex] = observeFields; + return observeFields; +} + +/** + * Chack if the Observation has a Dependenencie and if it has the observation will be checked recursive. + * This function is call by references and the dependent ids and context will saved in the pTempObserver object. + * + * @param {String} [pObserver] the Observer ID + * @param {String} [pDependentContext] the context of the parend observation + * @param {Object} [pTempObserver] the tempObservation of + * @param {String} [pDependentObservationId] the id of the parend observation + * @return {Void} + */ +Observation.prototype._checkDependencies = function (pObserver, pDependentContext, pTempObserver, pDependentObservationId) +{ + let tempOriginalRowdata = JSON.stringify(this.callerVariables[WorkflowVariables.ROWDATA()]); + let targetEntity = ContextUtils.getEntity(this.callerVariables[WorkflowVariables.TARGET_CONTEXT()]); + let dependentEntity = ContextUtils.getEntity(pDependentContext); + + var dependentObject = Dependency.mapping()[targetEntity][dependentEntity]; + + var dependentCheckVars = {} + dependentCheckVars[WorkflowVariables.TRIGGER()] = this.callerVariables[WorkflowVariables.TRIGGER()]; + dependentCheckVars[WorkflowVariables.TARGET_CONTEXT()] = pDependentContext; + dependentCheckVars[WorkflowVariables.EVENT_USER()] = pObserver; + + Object.keys(pTempObserver[pObserver][Observation.RECORDS_SPECIFIC_VALUES()]).forEach(function (pRecordID) { + let specificRecordValues = pTempObserver[pObserver][Observation.RECORDS_SPECIFIC_VALUES()][pRecordID]; + Observation._syncRecordsSpecificValues(specificRecordValues, this.callerVariables[WorkflowVariables.ROWDATA()]); + + var dependentIds = dependentObject.getUIDsfn(this.callerVariables[WorkflowVariables.ROWDATA()], this.callerVariables[WorkflowVariables.INITIAL_ROWDATA()]); + + if (!dependentObject.options.isOwnNotified) + { + specificRecordValues[Observation.OBJECT_TYPE()] = pDependentContext; + } + + dependentCheckVars[WorkflowVariables.TARGET_ID()] = dependentIds; + + var results = new Observation(dependentCheckVars, this.storedFilterResults) + .checkObservation(pDependentObservationId); + + if (results) + { + specificRecordValues[Observation.OBJECT_IDs()] = results; + } + }, this) + this.callerVariables[WorkflowVariables.ROWDATA()] = JSON.parse(tempOriginalRowdata); +} + +/** + * Bring the Fields in the right format. + * + * @param {Array} [pFilterResults] + * @return {Object} + */ +Observation.prototype._formatFieldsToLoad = function (pFilterResults) +{ + let res = {}; + let fieldsToLoad = this.callerVariables[WorkflowVariables.FIELDS_TO_LOAD()] + + if (Array.isArray(fieldsToLoad)) + { + let recordFields = {}; + let pro = project.getRecordContainerModel(this.callerVariables[Observation.ENTITY_NAME()])["recordFieldMappings"]; + for (let index in pro) { - observations.and("OBSERVATION." + pVariables[WorkflowVariables.TRIGGER()], "1"); + fieldName = pro[index].name.split("."); + if (fieldsToLoad.indexOf(fieldName[0]) > -1 || fieldsToLoad.indexOf(pro[index].name) > -1) + { + Object.keys(pFilterResults).forEach(function (pRowID) + { + if (!res[pRowID]) + { + res[pRowID] = {}; + res[pRowID]["#CONTENTTITLE"] = pFilterResults[pRowID][0]; + } + + if (fieldName[1] === "value") + { + res[pRowID][(pro[index].recordfield || pro[index].name)] = pFilterResults[pRowID][1][fieldName[0]]; + } + else + { + res[pRowID]["#COLUMNEXP_____" +fieldName[0] + ".displayValue"] = pFilterResults[pRowID][1][pro[index].name]; + } + }); + } } + } + else + { + Object.keys(pFilterResults).forEach(function (pRowID) + { + if (!res[pRowID]) + { + res[pRowID] = {}; + res[pRowID]["#CONTENTTITLE"] = pFilterResults[pRowID][0]; + } + }); + } + return res; +} + +/** + * Checks the observations for the specific changed data set and then forwards them to the Observation._notifiyUsers() function. + * + * @param {String} [pObservationId] the id of the parent observation. This variable is required for the recursion. + * + * @return {Void} + */ +Observation.prototype.checkObservation = function(pObservationId) +{ + if (this.callerVariables[WorkflowVariables.TRIGGER()]) + { + Observation.parseALLVariable(this.callerVariables); - observations = observations.table(); + var observers = {}; + this.observations = Observation.getObservations( + this.callerVariables[WorkflowVariables.TRIGGER()], + this.callerVariables[WorkflowVariables.TARGET_ID()], + this.callerVariables[WorkflowVariables.TARGET_CONTEXT()], + pObservationId + ); - for (let i = 0; i < observations.length; i++) + for (let i = 0; i < this.observations.length; i++) { var tempObserver = {}; - var observation = observations[i]; + var observation = this.observations[i]; var user = tools.getUserByAttribute(tools.NAME, observation[2], tools.PROFILE_DEFAULT); var filterResult; // exclude the user who made the changes. - if (user && pVariables[WorkflowVariables.EVENT_USER()] !== observation[2]) + if (user)// && pVariables[WorkflowVariables.EVENT_USER()] !== observation[2]) { - var config = entities.createConfigForLoadingRows() - .user(user.title) - .uids([pVariables[WorkflowVariables.TARGET_ID()]]) - .entity(pVariables[Observation.ENTITY_NAME]) - - if (observation[1]) - config.filter(JSON.stringify(JSON.parse(observation[1]).filter)); - - try - { - filterResult = entities.getRows(config.fields(["#CONTENTTITLE"]))[0]["#CONTENTTITLE"]; - } - catch (e) - { - // This Catch is needed for the Permission exeptions and the recursion - logging.log(e); - filterResult = null; - } + filterResult = this.checkFilterAndPermissions(user.title, observation[1], observation[0]); - if (filterResult) + if (filterResult && Object.keys(filterResult).length) { if (pObservationId) { return filterResult; } - var observeFields = {}; - text.decodeMS(observation[3]).forEach(function (observeFiled) { - let field = text.decodeMS(observeFiled); - let fieldNames = text.decodeMS(field[0]); - let displayValueField = "#COLUMNEXP_____" + fieldNames[1] + ".displayValue"; - let observedField = pVariables[WorkflowVariables.ROWDATA()][displayValueField] ? displayValueField : null; - if (tools.hasPermission(tools.PERMISSION_VIEW, pVariables[Observation.ENTITY_NAME], fieldNames[1], user.title)) - { - observeFields[fieldNames[0]] = [field[1], observedField]; - } - }); - - tempObserver[observation[2]] = {}; - - pVariables[WorkflowVariables.CHANGED_ROWS()].forEach(function (recordField) { - if (observeFields[recordField]) - { - if (observeFields[recordField][1]) - { - tempObserver[observation[2]][observeFields[recordField][1]] = observeFields[recordField][0]; - } - else - { - tempObserver[observation[2]][recordField] = observeFields[recordField][0]; - } - } - }); + tempObserver[observation[2]] = this.parseAndFilterObjectFields(observation[3], user.title, filterResult); + tempObserver[observation[2]][Observation.RECORDS_SPECIFIC_VALUES()] = this._formatFieldsToLoad(filterResult); } - else if (pVariables[WorkflowVariables.TRIGGER()] == WorkflowSignalSender.EVENT_DELETE()) + else if (this.callerVariables[WorkflowVariables.TRIGGER()] == WorkflowSignalSender.EVENT_DELETE()) { tempObserver[observation[2]] = {}; } + if (tempObserver[observation[2]]) { tempObserver[observation[2]][Observation.PRIO()] = observation[6]; if (observation[4] && !pObservationId) { - tempObserver[observation[2]][Observation.OBJECT_TYPE()] = observation[4]; - tempObserver[observation[2]][Observation.OBJECT_IDs()] = {}; - - var dependentIds = - Dependency.mapping()[ContextUtils.getEntity(pVariables[WorkflowVariables.TARGET_CONTEXT()])][ContextUtils.getEntity(observation[4])] - .getUIDsfn(pVariables[WorkflowVariables.ROWDATA()], pVariables[WorkflowVariables.INITIAL_ROWDATA()]); - - var dependentCheckVars = {} - dependentCheckVars[WorkflowVariables.TRIGGER()] = pVariables[WorkflowVariables.TRIGGER()]; - dependentCheckVars[WorkflowVariables.TARGET_CONTEXT()] = observation[4]; - dependentCheckVars[WorkflowVariables.EVENT_USER()] = observation[2]; - for (let index = 0; index < dependentIds.length; index++) - { - dependentCheckVars[WorkflowVariables.TARGET_ID()] = dependentIds[index]; - var contentTitle = Observation.checkObservation(dependentCheckVars, observation[5]); - if (contentTitle) // Check Dependent - { - tempObserver[observation[2]][Observation.OBJECT_IDs()][dependentIds[index]] = contentTitle; - } - } - } - } - - if (tempObserver[observation[2]] && (!tempObserver[observation[2]][Observation.OBJECT_IDs()] ||Object.keys(tempObserver[observation[2]][Observation.OBJECT_IDs()]).length > 0)) - { - if (!observers[observation[2]]) - { - observers[observation[2]] = tempObserver[observation[2]]; - } - else - { - if (!observers[observation[2]][Observation.OBJECT_IDs()] || - JSON.stringify(observers[observation[2]][Observation.OBJECT_IDs()]) == JSON.stringify(tempObserver[observation[2]][Observation.OBJECT_IDs()]) && - observers[observation[2]][Observation.OBJECT_TYPE()] == tempObserver[observation[2]][Observation.OBJECT_TYPE()]) - { - Object.keys(tempObserver[observation[2]]).forEach(function (pField) - { - if (!observers[observation[2]][pField] && pVariables[WorkflowVariables.CHANGED_ROWS()].indexOf(pField) > -1) - { - observers[observation[2]][pField] = tempObserver[observation[2]][pField]; - } - }); - } + this._checkDependencies(observation[2], observation[4], tempObserver, observation[5]); } } - tempObserver[observation[2]] = null; + Observation._syncTempObservationAndObservation(tempObserver, observers, observation[2], this.callerVariables[WorkflowVariables.CHANGED_ROWS()]) } } @@ -240,11 +431,75 @@ Observation.checkObservation = function(pVariables, pObservationId) return null; } - Observation._notifiyUsers(pVariables, observers); + Observation._notifiyUsers(this.callerVariables, observers); } return null; } + +/** + * Sync pTempObserver with pObservers + * + * @param {Void} [pTempObserver] + * @param {Void} [pObservers] + * @param {Void} [pObserverUserID] + * @param {Void} [pChangedRows] + * @return {Void} + */ +Observation._syncTempObservationAndObservation = function (pTempObserver, pObservers, pObserverUserID, pChangedRows) +{ + if (pTempObserver[pObserverUserID] && (!Utils.isNullOrEmpty(pTempObserver[pObserverUserID][Observation.OBJECT_IDs()]))) + { + if (!pObservers[pObserverUserID]) + { + pObservers[pObserverUserID] = pTempObserver[pObserverUserID]; + } + else + { + if (Object.keys(pObservers[pObserverUserID][Observation.RECORDS_SPECIFIC_VALUES()]).length > 0) + { + Observation._syncRecordsSpecificValues( + pTempObserver[pObserverUserID][Observation.RECORDS_SPECIFIC_VALUES()], + pObservers[pObserverUserID][Observation.RECORDS_SPECIFIC_VALUES()]); + } + else + { + pObservers[pObserverUserID][Observation.RECORDS_SPECIFIC_VALUES()] = pTempObserver[pObserverUserID][Observation.RECORDS_SPECIFIC_VALUES()]; + } + } + } + pTempObserver[pObserverUserID] = null; +} + +/** + * Copie the content of pTempObject into the pObject. + * This function is call by reference. + * + * @param {Object} [pTempObject] + * @param {Object} [pObject] + * @return {Void} + */ +Observation._syncRecordsSpecificValues = function (pTempObject, pObject) +{ + Object.keys(pTempObject).forEach(function (pID) + { + if(pObject[pID] && typeof pTempObject[pID] === "object") + { + if (pID != Observation.OBJECT_IDs() || pTempObject[Observation.OBJECT_TYPE()] == pObject[Observation.OBJECT_TYPE()]) + { + Observation._syncRecordsSpecificValues(pTempObject[pID], pObject[pID]); + } + } + else + { + if (!pObject[pID] || pID != Observation.OBJECT_TYPE()) + { + pObject[pID] = pTempObject[pID]; + } + } + }); +} + /** * Handle the Notifications for the given Observers and * assembles the individual notification for each user @@ -264,40 +519,46 @@ Observation._notifiyUsers = function (pVariables, pObservers) notificationType : "ObservationNotification" } - observers.forEach(function (pObserver) { - filteredVariables.notificationDescription = beginNotificationDescription; - // If there is a OBJECT_TYPE, this is a dependency observation - if (pObservers[pObserver][Observation.OBJECT_TYPE()]) + observers.forEach(function (pObserver) + { + Object.keys(pObservers[pObserver][Observation.RECORDS_SPECIFIC_VALUES()]).forEach(function (pRecordUID) { - filteredVariables.notificationCaption = pVariables[WorkflowVariables.TRIGGER()]; - var context = pObservers[pObserver][Observation.OBJECT_TYPE()]; + pVariables[WorkflowVariables.TARGET_ID()] = pRecordUID; + let specificRecordValues = pObservers[pObserver][Observation.RECORDS_SPECIFIC_VALUES()][pRecordUID]; + // If there is a OBJECT_TYPE, this is a dependency observation + if (specificRecordValues[Observation.OBJECT_TYPE()]) + { + var context = specificRecordValues[Observation.OBJECT_TYPE()]; - for (var targetId in pObservers[pObserver][Observation.OBJECT_IDs()]) + for (var targetId in specificRecordValues[Observation.OBJECT_IDs()]) + { + filteredVariables.notificationDescription = beginNotificationDescription; + filteredVariables.notificationSubcategory = specificRecordValues[Observation.OBJECT_IDs()][targetId] + Observation._notification( + pVariables, + filteredVariables, + pObservers, + pObserver, + context, + targetId); + } + } + else { - filteredVariables.notificationSubcategory = pObservers[pObserver][Observation.OBJECT_IDs()][targetId] - Observation._notification( - pVariables, - filteredVariables, - pObservers, - pObserver, - context, - targetId); + if (!pObservers[pObserver][Observation.OBJECT_IDs()] || Object.keys(pObservers[pObserver][Observation.OBJECT_IDs()]).length > 0) + { + filteredVariables.notificationDescription = beginNotificationDescription; + Observation._notification( + pVariables, + filteredVariables, + pObservers, + pObserver, + pVariables[WorkflowVariables.TARGET_CONTEXT()], + pVariables[WorkflowVariables.TARGET_ID()]); + } } - } - else - { - filteredVariables.notificationCaption = pVariables[WorkflowVariables.TRIGGER()]; - Observation._notification( - pVariables, - filteredVariables, - pObservers, - pObserver, - pVariables[WorkflowVariables.TARGET_CONTEXT()], - pVariables[WorkflowVariables.TARGET_ID()]); - - } - - }); + }, this); + }, this); } } @@ -314,8 +575,9 @@ Observation._notifiyUsers = function (pVariables, pObservers) */ Observation._notification = function (pVariables, pFilteredVariables, pObservers, pObserver, pContext, pTargetId) { + let spezificRowData = pObservers[pObserver][Observation.RECORDS_SPECIFIC_VALUES()][pVariables[WorkflowVariables.TARGET_ID()]]; pFilteredVariables.notificationPriority = pObservers[pObserver][Observation.PRIO()]; - pFilteredVariables.notificationCaption = pVariables[WorkflowVariables.CONTENTTITLE()]; + pFilteredVariables.notificationCaption = pVariables[WorkflowVariables.CONTENTTITLE()] || spezificRowData["#CONTENTTITLE"]; pFilteredVariables.notificationAffectedUID = pTargetId; pFilteredVariables.notificationAffectedContext = pContext; var isfirstField = true; @@ -335,7 +597,7 @@ Observation._notification = function (pVariables, pFilteredVariables, pObservers pNotification.linkinfo == text.encodeMS([pContext, pTargetId]) && pNotification.type == pFilteredVariables.notificationType && !pNotification.description.endsWith("....there is more data available")) - { + { isfirstField = false; pFilteredVariables.notificationContentId = pNotification.contentid; pFilteredVariables.notificationDescription = pNotification.description; @@ -357,6 +619,8 @@ Observation._notification = function (pVariables, pFilteredVariables, pObservers if (pVariables[WorkflowVariables.CHANGED_ROWS()].indexOf(field) > -1) { var formatedFieldValue = Observation.formatFieldValue(rowData,pVariables[WorkflowVariables.CHANGED_ROWS_TYPES()], field); + formatedFieldValue = formatedFieldValue || Observation.formatFieldValue(spezificRowData, pVariables[WorkflowVariables.CHANGED_ROWS_TYPES()], field); + pFilteredVariables.notificationDescription += " " +(isfirstField ? "" : translate.text("and"))+ " " + pObservers[pObserver][field] + " " + translate.text("was set to") + " \"" + formatedFieldValue + "\""; @@ -393,7 +657,7 @@ Observation._createNotification = function (variables) variables.notificationDescription = variables.notificationDescription.toString(); if (false) // WorkflowUtils.engineIsEnabled() { - checkObservation.signalEventReceived("Observation", variables); + } else { @@ -455,10 +719,13 @@ Observation._createNotification = function (variables) */ Observation.formatFieldValue = function (pRowData, pTypes, pField) { - switch (pTypes[pField]) + var tempFormat = pTypes[pField] ? pTypes[pField].split("::") : [null]; + switch (tempFormat[0]) { case "DATE": return datetime.toDate(pRowData[pField], translate.text("dd.MM.yyyy"), "Europe/Berlin"); + case "DROP_DOWN": + return tempFormat[1]; default : return pRowData[pField] } @@ -525,6 +792,32 @@ Observation.cancelAction = function () } } +/** + * Notify all observer of the given ids of a contxt. + * + * @param {Object} [pVaribles] + * @param {String|Array} [pTargetIds] the target id or a Array with the target ids + * @param {String} [pTargetContext] the target Context + * @return {Void} + * + * @example + * let varsObj = { + * "changedRows": JSON.stringify(["ACTIVITY.INFO"]), + * "fieldsToLoad" : JSON.stringify(["INFO", "ACTIVITYID", "INFO.displayValue"]) + * } + * + * Observation.serialAction(varsObj, vars.get("$sys.selection"), "Activity"); + * + */ +Observation.seriesAction = function (pVaribles, pTargetIds, pTargetContext) +{ + if (pTargetIds && typeof pTargetIds === 'object') + { + pTargetIds = JSON.stringify(pTargetIds) + } + + WorkflowSignalSender.updated(pVaribles ,pTargetIds , pTargetContext); +} /** * Returns the title of the cancel observation action depending on the count of UIDs @@ -616,7 +909,7 @@ Observation.actionState = function (pSelectedUIDs, pIsCancelAction) let isMultiselectionAction = project.getPreferenceValue("custom.observation.isMultiselectionEnabled", "false"); if (isEnabled == "false" || (isMultiselectionAction == "false" && (pSelectedUIDs && pSelectedUIDs.length) && vars.get("$sys.presentationmode") == neon.CONTEXT_PRESENTATIONMODE_FILTER)) - { + { return neon.COMPONENTSTATE_INVISIBLE; } @@ -693,7 +986,8 @@ Observation.getAllPosibleFields = function (pType) if (Dependency.excludedFields()[entity]) excludeFields = excludeFields.concat(Dependency.excludedFields()[entity]); - if (rcm.type == project.RECORDCONTAINERTYPE_DB){ + if (rcm.type == project.RECORDCONTAINERTYPE_DB) + { for (var index in rcm.linkInformation) { var table = rcm.linkInformation[index]; diff --git a/process/Observation_test/Observation_test.aod b/process/Observation_test/Observation_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..528cd6f03ed43cad209371b27cec1d7277c340e2 --- /dev/null +++ b/process/Observation_test/Observation_test.aod @@ -0,0 +1,11 @@ +<?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.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.2"> + <name>Observation_test</name> + <title>[TEST] Observation_lib</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/Observation_test/process.js</process> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/Observation_test/process.js b/process/Observation_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..dc44a3b28f52c1240c49410b48fd152e6525d16f --- /dev/null +++ b/process/Observation_test/process.js @@ -0,0 +1,66 @@ +import("Observation_lib"); +import("Sql_lib"); +import("system.result"); +import("system.translate"); +import("system.vars"); +import("Keyword_lib"); +import("UnitTest_lib"); + + +var parseVariableIfNeed = new TestSuite("Observation.parseVariableIfNeed", [ + new Test("", + function(pTester, pDataProvider) { + + let object = { "TEST" :pDataProvider[0]} + Observation.parseVariableIfNeed(object, "TEST"); + var actualValue = object["TEST"]; + + pTester.expectThat(actualValue).equals(pDataProvider[1]).assert(); + }, + function dataProvider(){ + return [ + [JSON.stringify({"NAME" : "HANS"}), {"NAME" : "HANS"}], + [{"NAME" : "HANS"}, {"NAME" : "HANS"}], + [null, null], + [0, 0], + [undefined, undefined], + ["[1,2,3]", [1,2,3]], + [[1,2,3], [1,2,3]] + ]; + } + ) +]); + +var parseVariableIfNeed = new TestSuite("Observation.parseVariableIfNeed", [ + new Test("", + function(pTester, pDataProvider) { + + let object = { "TEST" :pDataProvider[0]} + Observation.parseVariableIfNeed(object, "TEST"); + var actualValue = object["TEST"]; + + pTester.expectThat(actualValue).equals(pDataProvider[1]).assert(); + }, + function dataProvider(){ + + return [ + [JSON.stringify({"NAME" : "HANS"}), {"NAME" : "HANS"}], + [{"NAME" : "HANS"}, {"NAME" : "HANS"}], + [null, null], + ["TESTString", "TESTString"], + [0, 0], + [undefined, undefined], + ["[1,2,3]", [1,2,3]], + [[1,2,3], [1,2,3]] + ]; + } + ) +]); + +var tester = new Tester("Test Observation_lib"); +tester.initCoverage(Observation); +tester.test(parseVariableIfNeed); + +tester.summary(); + +result.object(tester.getResults()); \ No newline at end of file diff --git a/process/Workflow_lib/process.js b/process/Workflow_lib/process.js index 3965813e2bc9e643f68b126dce56c8e1552ae7e8..f5c336f0b0bb8222dabf5a0b32ee8fdaff2d2f5c 100644 --- a/process/Workflow_lib/process.js +++ b/process/Workflow_lib/process.js @@ -215,11 +215,11 @@ WorkflowSignalSender.deleted = function (pVariables, pTargetId, pTargetContext) */ WorkflowSignalSender.eventHappened = function (pEvent, pTargetId, pTargetContext, pVariables) { - let temp = {}; - temp[ WorkflowVariables.TARGET_CONTEXT()] = pTargetContext; - temp[WorkflowVariables.TARGET_ID()] = pTargetId; - temp[WorkflowVariables.TRIGGER()] = pEvent; - let variables = WorkflowVariables.getAllVariablesValue(temp); + pVariables = pVariables || {}; + pVariables[WorkflowVariables.TARGET_CONTEXT()] = pVariables[WorkflowVariables.TARGET_CONTEXT()] || pTargetContext; + pVariables[WorkflowVariables.TARGET_ID()] = pVariables[WorkflowVariables.TARGET_ID()] || pTargetId; + pVariables[WorkflowVariables.TRIGGER()] = pVariables[WorkflowVariables.TRIGGER()] || pEvent; + let variables = WorkflowVariables.getAllVariablesValue(pVariables); var processConfig = process.createStartAsyncConfig().setName("workflowExtension_serverProcess") .setLocalVariables({"variablesWorkflow" : JSON.stringify(variables)}) @@ -234,7 +234,7 @@ WorkflowSignalSender.eventHappened = function (pEvent, pTargetId, pTargetContext { if (_checkCondition(signal.entity, variables[WorkflowVariables.TARGET_ID()], signal.condition)) { - var filteredVariables = pVariables || {}; + var filteredVariables = pVariables; // TODO: Evtl machts keinen Sinn mehr. signal.variables.forEach(function (varName) { filteredVariables[varName] = variables[varName]; @@ -333,6 +333,22 @@ WorkflowVariables.TARGET_CONTEXT.getDefaultValue = function () return ContextUtils.getCurrentContextId(); } +/** + * Returns the variable name for the fileds to load + */ +WorkflowVariables.FIELDS_TO_LOAD = function () +{ + return "fieldsToLoad"; +} + +/** + * Returns the default value for the fileds to load + */ +WorkflowVariables.FIELDS_TO_LOAD.getDefaultValue = function () +{ + return JSON.stringify([]); +} + /** * Returns the variable name for the rowdata */ @@ -346,7 +362,7 @@ WorkflowVariables.ROWDATA = function () */ WorkflowVariables.ROWDATA.getDefaultValue = function () { - return JSON.stringify(vars.get("$local.rowdata")); + return JSON.stringify(( vars.exists("$local.rowdata") ? vars.get("$local.rowdata"): {})); } /** @@ -362,7 +378,7 @@ WorkflowVariables.INITIAL_ROWDATA = function () */ WorkflowVariables.INITIAL_ROWDATA.getDefaultValue = function () { - return JSON.stringify(vars.get("$local.initialRowdata")); + return JSON.stringify(( vars.exists("$local.initialRowdata") ? vars.get("$local.initialRowdata"): {})); } /** @@ -378,7 +394,7 @@ WorkflowVariables.CHANGED_ROWS = function () */ WorkflowVariables.CHANGED_ROWS.getDefaultValue = function () { - return JSON.stringify(vars.get("$local.changed")); + return JSON.stringify(( vars.exists("$local.changed") ? vars.get("$local.changed"): [])); } /** @@ -394,19 +410,37 @@ WorkflowVariables.CHANGED_ROWS_TYPES = function () */ WorkflowVariables.CHANGED_ROWS_TYPES.getDefaultValue = function () { - let isDBrc = project.getRecordContainerModel(ContextUtils.getEntity(ContextUtils.getCurrentContextId())).type == project.RECORDCONTAINERTYPE_DB; - let types = {} - vars.get("$local.changed").forEach(function(pField) { + let types = {}; + if (vars.exists("$local.changed")) + { + let isDBrc = project.getRecordContainerModel(ContextUtils.getEntity(ContextUtils.getCurrentContextId())).type == project.RECORDCONTAINERTYPE_DB; + + vars.get("$local.changed").forEach(function(pField) { let splitedField = pField.split("."); let fieldName; - if (isDBrc) { + if (isDBrc) + { fieldName = splitedField[1] - } else { + } + else + { fieldName = splitedField[0] } + if (splitedField[1] != "displayValue" && vars.exists("$property." + fieldName + ".contentType") ) - types[pField] = vars.get("$property." + fieldName + ".contentType"); + { + let contentType = vars.get("$property." + fieldName + ".contentType").trim(); + types[pField] = contentType; + } + + if (splitedField[1] != "displayValue" && vars.exists("$field." + fieldName + ".displayValue") && vars.get("$field." + fieldName + ".displayValue") ) + { + types[pField] = "DROP_DOWN" + "::" + vars.get("$field." + fieldName + ".displayValue").trim(); + } + }); + } + return JSON.stringify(types); } @@ -471,7 +505,7 @@ WorkflowVariables.CONTENTTITLE = function () */ WorkflowVariables.CONTENTTITLE.getDefaultValue = function () { - return vars.get("$field.#CONTENTTITLE"); + return vars.exists("$local.rowdata") ? vars.get("$field.#CONTENTTITLE") : null; } /** @@ -504,7 +538,8 @@ WorkflowVariables.getAllVariables = function () "TARGET_CONTEXT", "TARGET_ID", "TRIGGER", - "CONTENTTITLE" + "CONTENTTITLE", + "FIELDS_TO_LOAD" ] } diff --git a/process/workflowExtension_serverProcess/process.js b/process/workflowExtension_serverProcess/process.js index a2fe06d71683692aaf05900c2d878c513b492c4e..4da7b83aaed8ace0f35a9ea7ec7353d7c3697b7f 100644 --- a/process/workflowExtension_serverProcess/process.js +++ b/process/workflowExtension_serverProcess/process.js @@ -13,7 +13,7 @@ var changedRows = JSON.parse(localVariables[WorkflowVariables.CHANGED_ROWS()]); if (project.getPreferenceValue("custom.observation.isEnabled", false) == "true") { - Observation.checkObservation(localVariables); + new Observation(localVariables).checkObservation(); } ClassificationUtils.setClassificationStorageDatasetsOutdated([targetId], entityName, rowData, changedRows);