diff --git a/entity/ActivityLink_entity/ActivityLink_entity.aod b/entity/ActivityLink_entity/ActivityLink_entity.aod index 44ea0b63d5f5e157d0d3868aff38d1fcde1c7170..72ee3eb1b50ca76d38b92468a913030faae7df0d 100644 --- a/entity/ActivityLink_entity/ActivityLink_entity.aod +++ b/entity/ActivityLink_entity/ActivityLink_entity.aod @@ -20,6 +20,7 @@ <title>{$OBJECTLINK_TYPE}</title> <consumer>Context</consumer> <mandatory v="true" /> + <stateProcess>%aditoprj%/entity/ActivityLink_entity/entityfields/object_type/stateProcess.js</stateProcess> <displayValueProcess>%aditoprj%/entity/ActivityLink_entity/entityfields/object_type/displayValueProcess.js</displayValueProcess> </entityField> <entityField> @@ -28,6 +29,7 @@ <consumer>Objects</consumer> <linkedContextProcess>%aditoprj%/entity/ActivityLink_entity/entityfields/object_rowid/linkedContextProcess.js</linkedContextProcess> <mandatory v="true" /> + <stateProcess>%aditoprj%/entity/ActivityLink_entity/entityfields/object_rowid/stateProcess.js</stateProcess> <displayValueProcess>%aditoprj%/entity/ActivityLink_entity/entityfields/object_rowid/displayValueProcess.js</displayValueProcess> </entityField> <entityField> diff --git a/entity/ActivityLink_entity/entityfields/object_rowid/stateProcess.js b/entity/ActivityLink_entity/entityfields/object_rowid/stateProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/entity/ActivityLink_entity/entityfields/object_type/displayValueProcess.js b/entity/ActivityLink_entity/entityfields/object_type/displayValueProcess.js index 2965221e0b08ec642696f69eb7ed11d3ceb692cd..42eedf72d8e8b451caeee3fa74e33ff2aff39fcb 100644 --- a/entity/ActivityLink_entity/entityfields/object_type/displayValueProcess.js +++ b/entity/ActivityLink_entity/entityfields/object_type/displayValueProcess.js @@ -3,8 +3,11 @@ import("system.neon"); import("system.vars"); import("system.project"); -if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && !vars.get("$field.OBJECT_TYPE")) { +if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && !vars.get("$field.OBJECT_TYPE")) +{ result.string(""); -} else if (vars.exists("$field.OBJECT_TYPE") && vars.get("$field.OBJECT_TYPE")) { +} +else if (vars.exists("$field.OBJECT_TYPE") && vars.get("$field.OBJECT_TYPE")) +{ result.string(project.getDataModel(project.DATAMODEL_KIND_CONTEXT, vars.get("$field.OBJECT_TYPE"))[1]); } \ No newline at end of file diff --git a/entity/ActivityLink_entity/entityfields/object_type/stateProcess.js b/entity/ActivityLink_entity/entityfields/object_type/stateProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/entity/Organisation_entity/entityfields/openclassificationoverview/onActionProcess.js b/entity/Organisation_entity/entityfields/openclassificationoverview/onActionProcess.js index 20382b740f4628039b481ff7bd875e0a205cab33..41b77a74686fc8f205cea6d7a19e0ea835bb0e87 100644 --- a/entity/Organisation_entity/entityfields/openclassificationoverview/onActionProcess.js +++ b/entity/Organisation_entity/entityfields/openclassificationoverview/onActionProcess.js @@ -1,7 +1,15 @@ +import("system.translate"); +import("system.question"); import("system.neon"); import("ClassificationUpdate_lib"); import("system.vars"); var classificationData = ClassificationUtils.executeUpdating(false, vars.get("$field.CONTACTID"), "Organisation"); - -neon.openContext("Classification", "ClassificationTree_view", null, neon.OPERATINGSTATE_SEARCH, {"ClassificationContent_param": classificationData}, null); \ No newline at end of file +if(classificationData["wrongConfiguration"]) +{ + question.showMessage(translate.text("Calculating the classification failed: the classification is probably configured the wrong way, contact an administrator."), question.ERROR, translate.text("Show Classification")); +} +else +{ + neon.openContext("Classification", "ClassificationTree_view", null, neon.OPERATINGSTATE_SEARCH, {"ClassificationContent_param": classificationData}, null); +} \ No newline at end of file diff --git a/entity/Salesproject_entity/entityfields/openclassificationoverview/onActionProcess.js b/entity/Salesproject_entity/entityfields/openclassificationoverview/onActionProcess.js index 409ae146ee56ad2bd7f74d1450e90f1dea097905..41c8b708628fafcc7e39d1af9fe6d6b5dca33135 100644 --- a/entity/Salesproject_entity/entityfields/openclassificationoverview/onActionProcess.js +++ b/entity/Salesproject_entity/entityfields/openclassificationoverview/onActionProcess.js @@ -1,7 +1,15 @@ +import("system.translate"); +import("system.question"); import("system.neon"); import("ClassificationUpdate_lib"); import("system.vars"); var classificationData = ClassificationUtils.executeUpdating(false, vars.get("$field.SALESPROJECTID"), "Salesproject"); - -neon.openContext("Classification", "ClassificationTree_view", null, neon.OPERATINGSTATE_SEARCH, {"ClassificationContent_param": classificationData}, null); \ No newline at end of file +if(classificationData["wrongConfiguration"]) +{ + question.showMessage(translate.text("Calculating the classification failed: the classification is probably configured the wrong way, contact an administrator."), question.ERROR, translate.text("Show Classification")); +} +else +{ + neon.openContext("Classification", "ClassificationTree_view", null, neon.OPERATINGSTATE_SEARCH, {"ClassificationContent_param": classificationData}, null); +} \ No newline at end of file diff --git a/entity/UniversalFileProcessor_entity/entityfields/drop_action/onActionProcess.js b/entity/UniversalFileProcessor_entity/entityfields/drop_action/onActionProcess.js index 08cfe20b63ade03abbf75c5a8817b0f96059437e..e55ae85d1dc5ab7ec1cf0ca00f89fe3416a8c50f 100644 --- a/entity/UniversalFileProcessor_entity/entityfields/drop_action/onActionProcess.js +++ b/entity/UniversalFileProcessor_entity/entityfields/drop_action/onActionProcess.js @@ -1,27 +1,29 @@ -import("system.logging"); +import("system.vars"); import("system.neon"); -import("system.translate"); import("system.util"); import("system.mail"); -import("IncomingEmailExecutor_lib"); -import("system.vars"); +import("system.plugin"); import("system.process"); import("system.project"); -import("system.plugin"); +import("system.logging"); +import("system.question"); +import("system.translate"); +import("IncomingEmailExecutor_lib"); +var isError = false; +var activityIDs = []; +var incomingMailExec, mailImportResult, mailObj; var dbAlias = "Data_alias"; //hardcoded because of a lack of a recordcontainer var files = vars.get("$local.value"); var status = { activitiesCreated: 0, - unlinkedMailsCreated: 0, - otherImportedFiles: 0, - skippedFiles: 0 + otherImportedFiles: 0 }; -var activityIDs = []; for (var i = 0, l = files.length; i < l; i++) { - vars.set("$field.INFO", translate.withArguments("processing %0/%1", [i.toString(), l.toString()]) + " . . ."); + vars.set("$field.INFO", translate.withArguments("processing %0/%1", [i.toString(), l.toString()]) + " ..."); + switch (files[i].mimeType) { case "application/vnd.ms-outlook": @@ -29,31 +31,40 @@ for (var i = 0, l = files.length; i < l; i++) case "message/rfc822": case "text/html": //in some cases .eml-files are recognized as text/html, till this is fixed accept the text/html contents too //todo: remove text/html workaround when #1056482 is fixed - var mailObj = _getMailObj(files[i]); + + mailObj = _getMailObj(files[i]); + if (mailObj) { mailObj.filename = files[i].filename; mailObj.filename = mailObj.filename.replace(/\.msg$/, ".eml"); - var incomingMailExec = new IncomingEmailExecutor(mailObj); + incomingMailExec = new IncomingEmailExecutor(mailObj); incomingMailExec.setAlias(dbAlias); - var mailImportResult = incomingMailExec.autoProcess() - if ((!mailImportResult.isUnlinkedMail) && mailImportResult.activityId) + + mailImportResult = incomingMailExec.autoProcess() + + if(!mailImportResult.isError) + { status.activitiesCreated++; - else if (mailImportResult.isUnlinkedMail && mailImportResult.activityId) - status.unlinkedMailsCreated++; - else - status.skippedFiles++; + } + else + { + isError = true; + } - if (mailImportResult.activityId){ + if (mailImportResult.activityId) + { activityIDs.push(mailImportResult.activityId); } } else - status.skippedFiles++; + { + isError = true; + } break; default: - status.skippedFiles++; + isError = true; break; } } @@ -61,31 +72,70 @@ for (var i = 0, l = files.length; i < l; i++) vars.set("$global.ACTIVITY_IDS", JSON.stringify(activityIDs)); //TODO: Änderung auf andere Variable #1057014 if (status.activitiesCreated > 0 || status.unlinkedMailsCreated > 0 || status.otherImportedFiles > 0) - neon.refreshAll();//this is needed for the dashboard: other elements are refreshed and display for example unlinkedMails +{ + neon.refreshAll(); //this is needed for the dashboard: other elements are refreshed and display for example unlinkedMails +} var messages = _getMessages(status); + if (messages.length) +{ vars.set("$field.INFO", translate.withArguments("processed %0/%1:", [i.toString(), l.toString()]) + "\n" + messages.join(", ")); +} + +if (isError) +{ + question.showMessage(translate.text("During processing the e-mail an error has occurred.\nPlease contact an administrator."), question.ERROR, + translate.text("E-mail processing error")); +} + +neon.refreshAll(); function _getMailObj(pDroppedFile) { var mailStr; - if (pDroppedFile.mimeType == "message/rfc822" || pDroppedFile.mimeType == "text/html")//todo: remove text/html workaround when #1056482 is fixed - mailStr = util.decodeBase64String(pDroppedFile.data); + + if (pDroppedFile.mimeType == "message/rfc822" || pDroppedFile.mimeType == "text/html") //todo: remove text/html workaround when #1056482 is fixed + { + try + { + mailStr = util.decodeBase64String(pDroppedFile.data); + } + catch(pException) + { + logging.log(translate.text("An error occured during decoding the mails content."), logging.ERROR); + logging.log(pException, logging.ERROR); + } + } else { try { mailStr = plugin.run(null, "de.adito.aditoweb.plugin.msg2rfc.Msg2RfcPlugin", [pDroppedFile.data])[0]; } - catch(ex) + catch(pException) { - logging.log(ex); + logging.log(translate.text("An error occured during converting the msg file into an standardized mail."), logging.ERROR); + logging.log(pException, logging.ERROR); } } if (mailStr) - return mail.parseRFC(mailStr); + { + let parsedMail; + + try + { + parsedMail = mail.parseRFC(mailStr); + } + catch(pException) + { + logging.log(translate.text("An error occured during parsing imported mail."), logging.ERROR); + logging.log(pException, logging.ERROR); + } + + return parsedMail; + } return null; } @@ -93,24 +143,42 @@ function _getMailObj(pDroppedFile) function _getMessages(pStatus) { var res = []; + if (pStatus.skippedFiles == 1) + { res.push(translate.text("one file ignored")); + } else if (pStatus.skippedFiles > 1) + { res.push(translate.withArguments("%0 files ignored", [pStatus.skippedFiles])); + } if (pStatus.otherImportedFiles == 1) + { res.push(translate.text("one file imported")); + } else if (pStatus.otherImportedFiles > 1) + { res.push(translate.withArguments("%0 files imported", [pStatus.otherImportedFiles])); + } if (pStatus.activitiesCreated == 1) + { res.push(translate.text("one actitiy from mail created")); + } else if (pStatus.activitiesCreated > 1) + { res.push(translate.withArguments("%0 activities from mails created", [pStatus.activitiesCreated])); + } if (pStatus.unlinkedMailsCreated == 1) + { res.push(translate.text("one mail could not be linked automatically")); + } else if (pStatus.unlinkedMailsCreated > 1) + { res.push(translate.withArguments("%0 mails could not be linked automatically", [pStatus.unlinkedMailsCreated])); + } + return res; } \ No newline at end of file diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod index c4203f75a400e9dcabf7c4e2a109c86cbcff3718..abf90ead18339eb94d6259059abaeb14d5deb924 100644 --- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod +++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod @@ -8932,6 +8932,36 @@ <entry> <key>Target amount</key> </entry> + <entry> + <key>An error occured during converting the *.msg file into an standardized mail.</key> + </entry> + <entry> + <key>E-mail processing error</key> + </entry> + <entry> + <key>An error occured during processing the mail.</key> + </entry> + <entry> + <key>An error occured during parsing imported mail.</key> + </entry> + <entry> + <key>An error occured during decoding the mails content.</key> + </entry> + <entry> + <key>An error occured during checking whether at least one of the recipients is an internal user or not.</key> + </entry> + <entry> + <key>An error occured during checking whether the sender is an internal user or not.</key> + </entry> + <entry> + <key>DSGVO-Anonymisierung</key> + </entry> + <entry> + <key>privat</key> + </entry> + <entry> + <key>During processing the e-mail an error has occurred.\n Please contact an administrator</key> + </entry> <entry> <key>Approval</key> </entry> diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod index 92287a24b70b6c338fc3ec1ec5cf53be8f7836db..165b1cc32ecc1d46e626a74bcafcf3927bf55e4d 100644 --- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod +++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod @@ -11863,6 +11863,45 @@ Bitte Datumseingabe prüfen</value> <entry> <key>Shows device types used by bulkmail recipients</key> </entry> + <entry> + <key>An error occured during parsing imported mail.</key> + <value>Ein Fehler trat auf, während dem Parsen einer importierten Mail.</value> + </entry> + <entry> + <key>An error occured during converting the *.msg file into an standardized mail.</key> + <value>Ein Fehler trat auf, während dem Konvertieren einer *.msg Datei zu einer standartisierten E-Mail.</value> + </entry> + <entry> + <key>An error occured during decoding the mails content.</key> + <value>Ein Fehler trat auf, während dem dekodieren des E-Mail Inhalts.</value> + </entry> + <entry> + <key>E-mail processing error</key> + <value>E-Mail-Verarbeitungsfehler</value> + </entry> + <entry> + <key>During processing the e-mail an error has occurred.\nPlease contact an administrator.</key> + <value>Bei der Verarbeitung der E-Mail ist ein Fehler aufgetreten.\nBitte kontaktieren Sie einen Administrator.</value> + </entry> + <entry> + <key>An error occured during checking whether the sender is an internal user or not.</key> + <value>Ein Fehler ist aufgetreten während der Überprüfung ob der Sender ein interner Nutzer ist oder nicht.</value> + </entry> + <entry> + <key>An error occured during checking whether at least one of the recipients is an internal user or not.</key> + <value>Ein Fehler ist aufgetreten während der Überprüfung ob mindestens einer der Empfänger ein interner Nutzer ist oder nicht.</value> + </entry> + <entry> + <key>GDPR-anonymization</key> + <value>DSGVO-Anonymisierung</value> + </entry> + <entry> + <key>private</key> + <value>privat</value> + </entry> + <entry> + <key>An error occured during processing the mail.</key> + </entry> <entry> <key>new Email</key> </entry> diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod index 017c7479e64d8bf1deaccf96b3a4d2ddb4e319f0..0b555130145c03cdf58f4be7b21de80c6645654c 100644 --- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod +++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod @@ -9047,6 +9047,36 @@ <entry> <key>Target amount</key> </entry> + <entry> + <key>An error occured during converting the *.msg file into an standardized mail.</key> + </entry> + <entry> + <key>E-mail processing error</key> + </entry> + <entry> + <key>An error occured during processing the mail.</key> + </entry> + <entry> + <key>An error occured during parsing imported mail.</key> + </entry> + <entry> + <key>An error occured during decoding the mails content.</key> + </entry> + <entry> + <key>An error occured during checking whether at least one of the recipients is an internal user or not.</key> + </entry> + <entry> + <key>An error occured during checking whether the sender is an internal user or not.</key> + </entry> + <entry> + <key>DSGVO-Anonymisierung</key> + </entry> + <entry> + <key>privat</key> + </entry> + <entry> + <key>During processing the e-mail an error has occurred.\n Please contact an administrator</key> + </entry> <entry> <key>new Email</key> </entry> diff --git a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod index bb37d522905059e84bc0abb80decff1920129d44..3dfb70545613d049dbb38fb82686193faeec3756 100644 --- a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod +++ b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod @@ -47,10 +47,12 @@ <mailbridgeMailserver> <name>abfa63d1-a47e-41f6-a87d-138bf04adc1e</name> <enabled v="true" /> + <bridgeName>Dev-Exchange</bridgeName> <serverName>mailServerIMAP</serverName> + <timeout v="20000" /> <user>mailbridge</user> <intervall v="5000" /> - <bridgeMode v="1" /> + <bridgeMode v="3" /> <flagMode v="2" /> <process>mailbridge</process> <errorProcess></errorProcess> diff --git a/process/ClassificationUpdate_lib/process.js b/process/ClassificationUpdate_lib/process.js index b66a2c1650b2335071768ceb7bbceccdf65683ac..690cf01a55c188172fef11827659dd1cf4b120c6 100644 --- a/process/ClassificationUpdate_lib/process.js +++ b/process/ClassificationUpdate_lib/process.js @@ -92,7 +92,11 @@ ClassificationUtils.executeUpdating = function(pRefreshAll, pSingleRefreshRowId, stopper = true; } var returnAfterUpdate = ClassificationUpdateHelper._updateOutdatedDatasets(null, buildOutdatedStoredClassificationObjects, singleRefreshRowId, outputInfo);//run updating for this set of Datasets - if(returnAfterUpdate && returnAfterUpdate["outputInfo"]) + if(returnAfterUpdate["wrongConfiguration"]) + { + return returnAfterUpdate; + } + else if(returnAfterUpdate && returnAfterUpdate["outputInfo"]) { outputInfo = returnAfterUpdate["outputInfo"]; } @@ -1638,6 +1642,10 @@ ClassificationUpdateHelper._updateOutdatedDatasets = function(pClassificationObj { filterFields = ["SALESPROJECTID", "CONTACT_ID", "ENDDATE", "INFO", "PHASE", "PROBABILITY", "PROJECTCODE", "PROJECTTITLE", "REASONS", "STARTDATE", "STATUS", "VOLUME"]; } + else if(pSingleRefreshRowId) + { + return {"wrongConfiguration": true}; + } else { throw new Error("updateClassifications_serverProcess: objectType doesn't exist or is not implemented correctly, contact an administrator."); diff --git a/process/Contact_lib/process.js b/process/Contact_lib/process.js index b6677f48572f0d056e8bd596538cbc5b07d6be57..4ca0339b5662248580784e4bd205428886ede4ec 100644 --- a/process/Contact_lib/process.js +++ b/process/Contact_lib/process.js @@ -744,6 +744,27 @@ ContactUtils.getCommFilter = function(pOperator, pRawvalue, pFilterOperatorName, return resultSqlCond; } +/** + * In case the given e-mail has an corresponding contact in the system, the contact id will be returned + * <u><i>otherwise</i></u> an empty array will be returned. + * + * @param {String} pEmail <p> + * The mail address which will be used to look up. + * @return {String} <p> + * In case the contact was found, the contact id will be returned.<br> + * If not an empty string will be returned. + */ +ContactUtils.getContactIdByEmail = function(pEmail) +{ + var email = EmailUtils.extractAddress(pEmail).toUpperCase(); + var contactId = newSelect("CONTACT.CONTACTID") + .from("COMMUNICATION") + .join("CONTACT", "COMMUNICATION.CONTACT_ID = CONTACT.CONTACTID") + .where("COMMUNICATION.ADDR", email, "upper(#) = ?") + .cell(); + return contactId; +} + /** * Checks all links to other entities, if none exist, the function returns true, otherwise false. * diff --git a/process/IncomingEmailExecutor_lib/process.js b/process/IncomingEmailExecutor_lib/process.js index 8a6da2031506da06576c82deadcd7a4162b20577..b82e7201dad48721e2c19b0fbb6b0f6dada8a52a 100644 --- a/process/IncomingEmailExecutor_lib/process.js +++ b/process/IncomingEmailExecutor_lib/process.js @@ -1,22 +1,30 @@ -import("system.translate"); -import("Keyword_lib"); -import("EmailUtil_lib"); -import("Util_lib"); -import("system.question"); -import("system.datetime"); -import("system.vars"); -import("system.util"); -import("ActivityTask_lib"); -import("system.tools"); -import("Employee_lib"); +import("system.logging"); import("system.db"); import("system.mail"); import("system.text"); +import("system.vars"); +import("system.util"); +import("system.tools"); +import("system.question"); +import("system.datetime"); +import("system.translate"); import("Sql_lib"); +import("Util_lib"); +import("Contact_lib"); +import("Keyword_lib"); +import("Employee_lib"); +import("EmailUtil_lib"); +import("ActivityTask_lib"); import("KeywordRegistry_basic"); -//TODO: comment library - +/** + * Class to handle incoming emails. + * + * @param {Object} pMail <p> + * The mail object. + * @return {IncomingEmailExecutor} <p> + * Returns an IncomingEmailExecutor object. + */ function IncomingEmailExecutor(pMail) { //whenver this function is called it may not be in a context where a alias is given: the mail-importing-entity for example has no alias. @@ -55,7 +63,18 @@ IncomingEmailExecutor.prototype.attachProcessor = function (pEmailProcessor) this._emailProcessors.push(pEmailProcessor); } -IncomingEmailExecutor.prototype.setActivityEmployeeContact = function (pContactId, pLanguageIso3, pSetAsFailback) +/** + * Sets the contact which will later used as activity responsible. + * + * @param {String} pContactId <p> + * The contac id. + * @param {String} pLanguageIso3 <p> + * The contac id. + * @param {Boolean} pSetAsFailback <p> + * In case its true, then . + * @return {Void} <p> + */ +IncomingEmailExecutor.prototype.setActivityEmployeeContact = function(pContactId, pLanguageIso3, pSetAsFailback) { //autodetect language if not given if (pLanguageIso3 == undefined) @@ -66,7 +85,9 @@ IncomingEmailExecutor.prototype.setActivityEmployeeContact = function (pContactI .cell(); if (lang) + { pLanguageIso3 = lang; + } } if (pSetAsFailback) @@ -82,11 +103,23 @@ IncomingEmailExecutor.prototype.setActivityEmployeeContact = function (pContactI } } +/** + * Sets the database alias. + * + * @param {String} pAlias <p> + * The name of database alias (e.g.: Data_alias). + * @return {Void} <p> + */ IncomingEmailExecutor.prototype.setAlias = function(pAlias) { this._alias = pAlias || db.getCurrentAlias(); } +/** + * Returns the mail-text as html. + * + * @return {String} <p> + */ IncomingEmailExecutor.prototype.getMailtextAsHtml = function() { var textInfos = [ @@ -96,8 +129,11 @@ IncomingEmailExecutor.prototype.getMailtextAsHtml = function() var attachmentInfos = mail.getAttachmentInfos(this.rawMail); var attachmentCount = attachmentInfos.length; + if (attachmentCount == 0) + { textInfos.push(translate.text("no attachments", this.locale)); + } else { if (attachmentCount == 1) @@ -128,21 +164,39 @@ IncomingEmailExecutor.prototype.getMailtextAsHtml = function() textInfos.push("<br/>\n" + text.text2html(this.rawMail[mail.MAIL_TEXT], true)); var res = textInfos.join("\n"); + return res; } +/** + * Returns the senders info. <br> + * <u><i>(contact-id, status, person-id, iso-language)</i></u> + * + * @return {Array} <p> + * Returns an object containing the senders info. + */ IncomingEmailExecutor.prototype.getSenderInfo = function() { if (this._senderInfo == null) + { this._senderInfo = this.mailSender ? IncomingEmailExecutor.getContactDataByEmail(this.mailSender, this._alias) : []; + } + return this._senderInfo; } -IncomingEmailExecutor.prototype.insertUnlinkedMail = function () +/** + * Inserts the mail as unlinked mail into AB_UNLINKEDMAIL. + * + * @return {Object} <p> + * Returns an object containing the uuid (unlinkedMailId: unlinkedMailId). + */ +IncomingEmailExecutor.prototype.insertUnlinkedMail = function() { var unlinkedMailId = util.getNewUUID(); var cols = ["AB_UNLINKEDMAILID", "SUBJECT", "SENTDATE", "SENDER", "RECIPIENTS", "MAIL", "USER_NEW", "DATE_NEW"]; - var vals = [unlinkedMailId, this.mailSubject, this.mailSentDate, this.mailSender, this.mailRecipients.join(", "), mail.toRFC(this.rawMail), vars.get("$sys.user"), datetime.date()]; + var vals = [unlinkedMailId, this.mailSubject, this.mailSentDate, this.mailSender, this.mailRecipients.join(", "), mail.toRFC(this.rawMail), + vars.get("$sys.user"), datetime.date()]; db.insertData("AB_UNLINKEDMAIL", cols, null, vals, this._alias); return { @@ -150,112 +204,311 @@ IncomingEmailExecutor.prototype.insertUnlinkedMail = function () }; } -IncomingEmailExecutor.prototype.isUnlinkable = function () +/** + * Returns whether the mail is linkable or not.<p> + * <i><u>(a e-mail is always then linkable when the sender has an contact in the system)</u></i> + * + * @return {Boolean|Null} <p> + * True in case it's unlinkable, otherwise false and in case an error occured + * null will be returned. + */ +IncomingEmailExecutor.prototype.isUnlinkable = function() { - return this.getSenderInfo().length == 0; + var isUnlinkable; + + if (this.getSenderInfo()) + { + isUnlinkable = this.getSenderInfo().length == 0; + } + else + { + isUnlinkable = null; + } + + return isUnlinkable; } -IncomingEmailExecutor.getContactDataByEmail = function (pMailAddress, pAlias) +/** + * In case the given e-mail has an corresponding contact in the system, it will be returned + * <u><i>otherwise</i></u> an empty array will be returned. + * + * @param {String} pMailAddress <p> + * The mail address which will be used to look up. + * @param {String} pAlias <p> + * The alias which will be used for db interaction. + * @return {Array|Null} <p> + * In case the contact was found, the contact id, status, person id, isolang will be returned. + * If not an empty array will be returned and in case an error occured null will be returned. + */ +IncomingEmailExecutor.getContactDataByEmail = function(pMailAddress, pAlias) { - var mailAddress = EmailUtils.extractAddress(pMailAddress).toUpperCase(); - return mailAddress - ? newSelect("CONTACT.CONTACTID, CONTACT.STATUS, CONTACT.PERSON_ID, CONTACT.ISOLANGUAGE", pAlias) - .from("COMMUNICATION") - .join("CONTACT", "COMMUNICATION.CONTACT_ID = CONTACT.CONTACTID") - .where("COMMUNICATION.ADDR", mailAddress, "upper(#) = ?") - .table() - : []; + var mailAddress = null; + + try + { + mailAddress = EmailUtils.extractAddress(pMailAddress).toUpperCase(); + + mailAddress = mailAddress ? newSelect("CONTACT.CONTACTID, CONTACT.STATUS, CONTACT.PERSON_ID, CONTACT.ISOLANGUAGE", pAlias) + .from("COMMUNICATION") + .join("CONTACT", "COMMUNICATION.CONTACT_ID = CONTACT.CONTACTID") + .where("COMMUNICATION.ADDR", mailAddress, "upper(#) = ?") + .table() + : []; + } + catch(pException) + { + logging.log(translate.text("An error occured during getting contact data."), logging.ERROR); + logging.log(pException, logging.ERROR); + } + + return mailAddress; } -IncomingEmailExecutor.prototype.createActivity = function(pAdditionalLinks) +/** + * Creates an corresponding activity, matching to the processed mail. + * + * @param {Array[]} [pAdditionalLinks] <p> + * 2d-array which contains arrays which represents links.<br> + * <u>(0: contextname, 1: contactId)</u> + * @param {Boolean} pIsError <p> + * This variable is used, when importing mails trough the + * dashlet, for detecting whether an error is occured or not. + * If so, in the end the a corresponding message will appear + * in the webclient. + * @return {Array} <p> + * Array which contains the uuids of the newly created activities. + */ +IncomingEmailExecutor.prototype.createActivity = function(pAdditionalLinks, pIsError) { + + var recipient; + + try + { + var sendersMail = mail.extractAddress(this.mailSender); + var isSenderInternalUser = tools.getUsersByAttribute(tools.EMAIL, [sendersMail]); + } + catch(pException) + { + logging.log(translate.text("An error occured during checking whether the sender is an internal user or not."), + logging.ERROR); + logging.log(pException, logging.ERROR); + } + + + var isRecipientInternalUser = this.mailRecipients.some(function(pRecipient){ + var isRecipientInternal = false; + + try + { + if (!Utils.isNullOrEmpty(tools.getUsersByAttribute(tools.EMAIL, [mail.extractAddress(pRecipient)])) + && mail.extractAddress(pRecipient).indexOf("mailbridge") == -1) + { + recipient = mail.extractAddress(pRecipient); + isRecipientInternal = true; + } + } + catch(pException) + { + logging.log(translate.text("An error occured during checking whether at least one of the recipients is an internal user or not."), + logging.ERROR); + logging.log(pException, logging.ERROR); + } + + return isRecipientInternal; + }); + var senderContacts = { prefered: [], failback: [] }; - this.getSenderInfo().forEach(this._getProcessingFunction(true, senderContacts), this); - this.activityData.links = this.activityData.links.concat(senderContacts.prefered.length > 0 ? senderContacts.prefered : senderContacts.failback); - + + if (Utils.toBoolean(vars.get("$sys.isserver"))) + { + this.getSenderInfo().forEach(this._getProcessingFunction(true, senderContacts), this); + this.activityData.links = this.activityData.links.concat(senderContacts.prefered.length > 0 ? senderContacts.prefered : + senderContacts.failback); + } + for (var i = 0, l = this.mailRecipients.length; i < l; i++) { - var recipientsInfo = IncomingEmailExecutor.getContactDataByEmail(this.mailRecipients[i], this._alias); + try + { + var recipientsMail = mail.extractAddress(this.mailRecipients[i]); + var isRecipientInternal = tools.getUsersByAttribute(tools.EMAIL, [recipientsMail]); + } + catch(pException) + { + logging.log(translate.text("An error occured during checking whether recipient (recipient: " + recipientsMail + ") is \n\ + an internal user or not."), logging.ERROR); + logging.log(pException, logging.ERROR); + } + + if (Utils.isNullOrEmpty(isRecipientInternal) && recipientsMail.indexOf("mailbridge") == -1) + { + try + { + var recipientsInfo = IncomingEmailExecutor.getContactDataByEmail(this.mailRecipients[i], this._alias); + } + catch(pException) + { + logging.log(translate.text("An error occured during getting recipients contact data."), + logging.ERROR); + logging.log(pException, logging.ERROR); + } + + var recipientContacts = { + prefered: [], + failback: [] + }; - var recipientContacts = { - prefered: [], - failback: [] - }; - recipientsInfo.forEach(this._getProcessingFunction(false, recipientContacts), this); - this.activityData.links = this.activityData.links.concat(recipientContacts.prefered.length > 0 ? recipientContacts.prefered : recipientContacts.failback); + recipientsInfo.forEach(this._getProcessingFunction(false, recipientContacts), this); + this.activityData.links = this.activityData.links.concat(recipientContacts.prefered.length > 0 ? recipientContacts.prefered + : recipientContacts.failback); + } } var langIso3 = this.activityData.employeeContactLanguage || this.failbackActivityData.employeeContactLanguage; var langIso2; + if (langIso3) { langIso2 = LanguageKeywordUtils.Iso2FromIso3(langIso3, this._alias); + if (langIso2) - this.locale = langIso2; + { + this.locale = langIso2; + } } //collecting all the information and combine it for the creation var activityDataForInsert = { subject: this.mailSubject, + entrydate: this.mailSentDate, content: this.getMailtextAsHtml(), categoryKeywordId: $KeywordRegistry.activityCategory$mail(), directionKeywordId: this.activityData.direction || this.failbackActivityData.direction }; - if (vars.get("$sys.isclient") == "true"){ + if (vars.get("$sys.isclient") == "true") + { activityDataForInsert.responsibleContactId = EmployeeUtils.getCurrentContactId(); - } else { - activityDataForInsert.responsibleContactId = this.activityData.employeeContactId ? this.activityData.employeeContactId : this.failbackActivityData.employeeContactId; + } + else + { + if (!Utils.isNullOrEmpty(isSenderInternalUser)) + { + activityDataForInsert.responsibleContactId = ContactUtils.getContactIdByEmail(sendersMail) || ""; + } + else if(isRecipientInternalUser) + { + activityDataForInsert.responsibleContactId = ContactUtils.getContactIdByEmail(recipient) || ""; + } + else + { + activityDataForInsert.responsibleContactId = ""; + } } var activityLinks = this.activityData.links || this.failbackActivityData.links; + if (pAdditionalLinks) + { activityLinks = activityLinks.concat(pAdditionalLinks); + } + activityLinks = ArrayUtils.distinct2d(activityLinks);//TODO: better check before adding the elements into the array if it already exists there - var activityDocs = [[this.filename || "mail.eml", util.encodeBase64String(mail.toRFC(this.rawMail)), true]]; + + var activityDocs = null; + + try + { + activityDocs = [["Mail.eml", util.encodeBase64String(mail.toRFC(this.rawMail)), true]]; + } + catch(pException) + { + logging.log(translate.text("An error occured during getting recipients contact data."), + logging.ERROR); + logging.log(pException, logging.ERROR); + } var activityRes = ActivityUtils.insertNewActivity(activityDataForInsert, activityLinks, activityDocs, this._alias, this.mailSentDate); return activityRes; } +/** + * Deletes the unlinked mail with the given uuid. + * + * @param {String} pUnlinkedMailId <p> + * The uuid of the record which shall be deleted.<br> + * @return {Void} <p> + */ IncomingEmailExecutor.prototype.deleteUnlinkedMail = function (pUnlinkedMailId) { newWhereIfSet("AB_UNLINKEDMAIL.AB_UNLINKEDMAILID", pUnlinkedMailId, undefined, undefined, this._alias) .deleteData(true, "AB_UNLINKEDMAIL"); } +/** + * Process an incoming email (e.g.: from mailbridge, e-mail import dashlet..) + * + * @param {String} pUnlinkedMailId <p> + * The uuid of the record which shall be deleted.<br> + * @return {Void} <p> + */ IncomingEmailExecutor.prototype.autoProcess = function(pUnlinkedMailId) { - let tempResult = {}; - tempResult.isUnlinkedMail = false; + let tempResult = { + isUnlinkedMail: false, + isError: false + }; + if (this.isUnlinkable()) { tempResult.isUnlinkedMail = true; + if (pUnlinkedMailId) + { return { unlinkedMailId: pUnlinkedMailId - }; + }; + } + } + else if(this.isUnlinkable() == null) + { + tempResult.isError = true; } - tempResult.activityId = this.createActivity().activityId; - this.deleteUnlinkedMail(pUnlinkedMailId); - this._emailProcessors.forEach(function (emailProcessor) + if (!tempResult.isError) { - emailProcessor.process(this.rawMail); - }, this); + tempResult.activityId = this.createActivity().activityId; + this.deleteUnlinkedMail(pUnlinkedMailId); + + this._emailProcessors.forEach(function (emailProcessor) + { + emailProcessor.process(this.rawMail); + }, this); + } return tempResult; } -IncomingEmailExecutor.prototype._getProcessingFunction = function (pIsSender, pTargetArray) +/** + * Returns an anonymous function which processes ? + * + * @param {Boolean} pIsSender <p> + * Whether the contact is the sender or not.<br> + * @param {Array} pTargetArray <p> + * The uuid of the record which shall be deleted.<br> + * @return {Void} <p> + */ +IncomingEmailExecutor.prototype._getProcessingFunction = function(pIsSender, pTargetArray) { - return function(contactInfoRow) { + return function(contactInfoRow){ + var [contactId, contactStatus, contactPersonId, languageIso3] = contactInfoRow; - //there *should* only exist no or one user per contactid, never two or more - so getUser (not getUsers) should be fine + //there *should* only exist no or one user per contactid, never two or more - so getUser (not getUsers) should be fine var user = tools.getUserByAttribute(tools.CONTACTID, [contactId]); var isEmployee = user != null; var isContactActive = contactStatus == $KeywordRegistry.contactStatus$active(); @@ -264,6 +517,7 @@ IncomingEmailExecutor.prototype._getProcessingFunction = function (pIsSender, pT if (isEmployee && !this.activityData.employeeContactId) { var direction = pIsSender ? $KeywordRegistry.activityDirection$outgoing() : $KeywordRegistry.activityDirection$incoming(); + if (isContactActive) { this.setActivityEmployeeContact(contactId, languageIso3); @@ -287,18 +541,31 @@ IncomingEmailExecutor.prototype._getProcessingFunction = function (pIsSender, pT .join("CONTACT", "anyContact.ORGANISATION_ID = CONTACT.ORGANISATION_ID and CONTACT.PERSON_ID is null", "anyContact") .whereIfSet(["CONTACT", "CONTACTID", "anyContact"], contactId) .arrayRow() + orgData[0] = orgData[0].replace(/\s/g, ''); - if (orgData[1] == $KeywordRegistry.contactStatus$active()) - pTargetArray["prefered"].push(["Organisation", orgData[0]]); - else - pTargetArray["failback"].push(["Organisation", orgData[0]]); + if(orgData[0] != '0' && orgData[0] != '1') + { + if (orgData[1] == $KeywordRegistry.contactStatus$active()) + { + pTargetArray["prefered"].push(["Organisation", orgData[0]]); + } + else + { + pTargetArray["failback"].push(["Organisation", orgData[0]]); + } + } } var link = [context, contactId]; + if (isContactActive) - pTargetArray["prefered"].push(link); + { + pTargetArray["prefered"].push(link); + } else + { pTargetArray["failback"].push(link); + } } }; } \ No newline at end of file diff --git a/process/mailbridge/process.js b/process/mailbridge/process.js index 3d5144d29fdd14251a0918d11ea3b900a800a823..1cca305e2d4d18a6dc16f7ac29a19bf4ff24020c 100644 --- a/process/mailbridge/process.js +++ b/process/mailbridge/process.js @@ -1,9 +1,9 @@ -import("IncomingEmailExecutor_lib"); import("EmailFilterHandling_lib"); import("system.text"); import("system.vars"); import("system.mail"); import("system.logging"); +import("IncomingEmailExecutor_lib"); var sender = text.decodeFirst(vars.getString("$local.sender")); var recipients = text.decodeMS(vars.getString("$local.recipients"));