Skip to content
Snippets Groups Projects
Commit f67419c6 authored by S.Listl's avatar S.Listl
Browse files

Replacing placeholders for bulk mails

parent 6059a609
No related branches found
No related tags found
No related merge requests found
import("system.logging");
import("system.datetime");
import("system.translate");
import("Util_lib");
import("JditoFilter_lib");
......@@ -10,20 +11,24 @@ import("system.result");
import("Sql_lib");
import("Attribute_lib");
var t = datetime.date()
var getGroups = vars.exists("$param.GetGroups_param") && vars.get("$param.GetGroups_param");
var objectType = vars.exists("$param.ObjectType_param") && vars.get("$param.ObjectType_param");
var parentType = vars.exists("$param.AttrParentType_param") && vars.get("$param.AttrParentType_param");
logging.log([getGroups, objectType, parentType])
var fetchUsages = true;
var uidTableAlias = "UIDROW";
var sqlSelect = "select UIDROW.AB_ATTRIBUTEID, UIDROW.ATTRIBUTE_PARENT_ID, UIDROW.ATTRIBUTE_ACTIVE, UIDROW.DROPDOWNDEFINITION, UIDROW.SORTING, UIDROW.ATTRIBUTE_TYPE, "
+ KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.attributeType(), "UIDROW.ATTRIBUTE_TYPE") //3
+ ", '', UIDROW.ATTRIBUTE_NAME, PARENT1.ATTRIBUTE_NAME, PARENT2.ATTRIBUTE_NAME, PARENT3.ATTRIBUTE_NAME, PARENT3.ATTRIBUTE_PARENT_ID "
+ "from AB_ATTRIBUTE UIDROW "
+ "left join AB_ATTRIBUTE PARENT1 on UIDROW.ATTRIBUTE_PARENT_ID = PARENT1.AB_ATTRIBUTEID " //always select the names of the next 3 parents so that less queries
+ "left join AB_ATTRIBUTE PARENT2 ON PARENT1.ATTRIBUTE_PARENT_ID = PARENT2.AB_ATTRIBUTEID " //are required later when buildung the full name
+ "left join AB_ATTRIBUTE PARENT3 ON PARENT2.ATTRIBUTE_PARENT_ID = PARENT3.AB_ATTRIBUTEID";
+ ", '', UIDROW.ATTRIBUTE_NAME, PARENT1.ATTRIBUTE_NAME, PARENT2.ATTRIBUTE_NAME, PARENT3.ATTRIBUTE_NAME, PARENT3.ATTRIBUTE_PARENT_ID \n\
from AB_ATTRIBUTE UIDROW \n\
left join AB_ATTRIBUTE PARENT1 on UIDROW.ATTRIBUTE_PARENT_ID = PARENT1.AB_ATTRIBUTEID \n\
left join AB_ATTRIBUTE PARENT2 ON PARENT1.ATTRIBUTE_PARENT_ID = PARENT2.AB_ATTRIBUTEID \n\
left join AB_ATTRIBUTE PARENT3 ON PARENT2.ATTRIBUTE_PARENT_ID = PARENT3.AB_ATTRIBUTEID";
/* always select the names of the next 3 parents so that less queries
are required later when buildung the full name */
var sqlOrder = " order by UIDROW.ATTRIBUTE_PARENT_ID asc, UIDROW.SORTING asc";
......@@ -69,18 +74,7 @@ else if (objectType) //if there's an objectType, it comes from the AttributeRel
else // do not return anything, if parameter is there but an empty array
condition.and("1=2");
}
else if (parentType) //condition for all subordinate attributes of an attribute (for the tree of subordinate attributes in an attribute)
{
if (AttributeTypeUtil.isGroupType(parentType))
{
var parentId = vars.exists("$param.AttrParentId_param") && vars.get("$param.AttrParentId_param");
if (parentId)
condition.and("UIDROW.AB_ATTRIBUTEID in ('" + AttributeUtil.getAllChildren(vars.getString("$param.AttrParentId_param")).join("','") + "')");
}
else
condition.and("1=2");
fetchUsages = false;
}
//when there are filters selected, add them to the conditon
......@@ -91,21 +85,26 @@ if (vars.exists("$local.filter") && vars.get("$local.filter"))
condition.andSqlCondition(JditoFilterUtils.getSqlCondition(filter.filter, "AB_ATTRIBUTE", uidTableAlias));
}
var usagesSelect = "select AB_ATTRIBUTE_ID, OBJECT_TYPE from AB_ATTRIBUTEUSAGE \n\
join AB_ATTRIBUTE UIDROW on AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = UIDROW.AB_ATTRIBUTEID";
var usageTbl = db.table(condition.buildSql(usagesSelect, "1=1"));
var usages = {};
for (let i = 0, l = usageTbl.length; i < l; i++)
var usages;
if (fetchUsages) //this query is only necessary in Attribute, not in AttributeRelation
{
let attrId = usageTbl[i][0];
if (attrId in usages)
usages[attrId].push(usageTbl[i][1]);
else
usages[attrId] = [usageTbl[i][1]];
var usagesSelect = "select AB_ATTRIBUTE_ID, OBJECT_TYPE from AB_ATTRIBUTEUSAGE \n\
join AB_ATTRIBUTE UIDROW on AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = UIDROW.AB_ATTRIBUTEID";
var usageTbl = db.table(condition.buildSql(usagesSelect, "1=1"));
usages = {};
for (let i = 0, l = usageTbl.length; i < l; i++)
{
let attrId = usageTbl[i][0];
if (attrId in usages)
usages[attrId].push(usageTbl[i][1]);
else
usages[attrId] = [usageTbl[i][1]];
}
}
var attributes = db.table(condition.buildSql(sqlSelect, "1=1", sqlOrder));
var nameCache = {};
result.object(_buildAttributeTable(attributes, usages));
......@@ -140,7 +139,7 @@ function _buildAttributeTable (pAttributes, pUsages)
for (let i in rows)
{
let rowData = rows[i].data;
if (rowData[5].trim() != $AttributeTypes.COMBOVALUE && i in pUsages)
if (pUsages && rowData[5].trim() != $AttributeTypes.COMBOVALUE && i in pUsages)
{
rowData[7] = pUsages[i].map(function (usage)
{
......@@ -163,8 +162,17 @@ function _buildAttributeTable (pAttributes, pUsages)
*/
function _getFullName (pAttributeName, pParent1Name, pParent2Name, pParent3Name, pParent4Id)
{
var parent4FullName = pParent4Id ? AttributeUtil.getFullAttributeName(pParent4Id) : null;
var parent4FullName;
if (pParent4Id && pParent4Id in nameCache)
parent4FullName = nameCache[pParent4Id];
else
{
parent4FullName = pParent4Id ? AttributeUtil.getFullAttributeName(pParent4Id) : null;
nameCache[pParent4Id] = parent4FullName;
}
pAttributeName = ArrayUtils.joinNonEmptyFields([parent4FullName, pParent3Name, pParent2Name, pParent1Name, pAttributeName], " / ");
return pAttributeName;
}
\ No newline at end of file
}
logging.log(datetime.date() - t)
\ No newline at end of file
......@@ -2,7 +2,7 @@ import("system.logging");
import("system.result");
import("system.neon");
import("system.vars");
import("PostalAddress_lib");
import("Address_lib");
if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && !vars.get("$this.value"))
{
......
<?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>Bulkmail_lib</name>
<name>BulkMail_lib</name>
<majorModelMode>DISTRIBUTED</majorModelMode>
<process>%aditoprj%/process/Bulkmail_lib/process.js</process>
<variants>
......
import("KeywordRegistry_basic");
import("Sql_lib");
import("system.db");
import("DocumentTemplate_lib");
import("Email_lib");
function Bulkmail ()
function BulkMailUtils () {}
BulkMailUtils.sendBulkMail = function (pBulkMailId)
{
var templateId = db.cell(SqlCondition.begin()
.andPrepare("BULKMAIL.BULKMAILID", pBulkMailId)
.buildSql("select DOCUMENTTEMPLATE_ID from BULKMAIL", "1=2")
);
var template = DocumentTemplate.loadTemplate(templateId);
var emailSender;
var recipientData = db.table(SqlCondition.begin()
.andPrepare("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
//TODO: more condition
.buildSql("select BULKMAILRECIPIENTID, CONTACT_ID, '' from BULKMAILRECIPIENT", "1=2")
);
var successIds = [];
var failedIds = [];
var mails = template.getReplacedEmailsByContactIds(recipientData.map(function (e) {return e[0];}));
for (let i = 0, l = recipientData.length; i < l; i++)
{
let contactId = recipientData[i][1];
let email = mails[contactId];
email.toRecipients = [recipientData[i][1]];
email.sender = emailSender;
let isSuccess = email.send();
if (isSuccess)
successIds.push(recipientData[i][0]); //set the recipient status to 'sent'
else
failedIds.push(recipientData[i][0]); //set the recipient status to 'failed'
}
db.updateData("BULKMAILRECIPIENT", ["STATUS"], null, [$KeywordRegistry.bulkMailSentStatus$sent()],
SqlCondition.begin()
.andIn("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", successIds)
.build("1=2")
);
db.updateData("BULKMAILRECIPIENT", ["STATUS"], null, [$KeywordRegistry.bulkMailSentStatus$failed()],
SqlCondition.begin()
.andIn("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", failedIds)
.build("1=2")
);
}
\ No newline at end of file
import("system.logging");
import("Communication_lib");
import("system.neon");
import("Employee_lib");
......@@ -147,67 +146,103 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements)
/**
* replaces the placeholders with data from the contact and returns the result
*/
DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId) //TODO: function required for mass replacing (for bulkmails)
DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId)
{
var replacements = this._getReplacementsByContactId(pContactId);
return this.getReplacedContent(replacements);
var replacements = this._getReplacementsByContactIds([pContactId]);
return this.getReplacedContent(replacements[pContactId]);
}
/**
* @private
* replaces the placeholders with data from the contacts and returns the result
*
* @param {Array} pContactIds contact ids
*
* @return {Object} replaced content for every contactId
*/
DocumentTemplate.prototype._getReplacementsByContactId = function (pContactId)
DocumentTemplate.prototype.getReplacedContentByContactIds = function (pContactIds)
{
var config = this._getRequiredPlaceholders();
var addressData = getAddressesData([pContactId], config, EmployeeUtils.getCurrentContactId()); //TODO: add sender selection
var replacements = {};
for (let i = 0, l = addressData[0].length; i < l; i++)
var replacements = this._getReplacementsByContactIds(pContactIds);
var contents = {};
for (let contactId in replacements)
{
replacements[addressData[0][i]] = addressData[1][i];
contents[contactId] = this.getReplacedContent(replacements[contactId]);
}
return replacements;
return contents;
}
/**
* loads data into an Email object from a template
* replaces the placeholders with data from the contacts and returns the result
*
* @param {Email} pEmail email object to change
* @param {String} pContactId contactId of the recipient
* @param {Array} pContactIds contact ids
*
* @return {Object} emails for every contactId
*/
DocumentTemplate.prototype.setEmailTemplateByContactId = function (pEmail, pContactId)
DocumentTemplate.prototype.getReplacedEmailsByContactIds = function (pContactIds)
{
if (this.type != DocumentTemplate.types.EML && this.type != DocumentTemplate.types.HTML && this.type != DocumentTemplate.types.TXT)
throw new Error("Invalid document type for an email template");
var replacements = DocumentTemplate._getReplacementsByContactId(pContactId);
if (this.type == DocumentTemplate.types.EML) //special treatment because eml contains more information than just the body
var replacements = this._getReplacementsByContactIds(pContactIds);
var emailObj = {};
for (let contactId in replacements)
{
let email = mail.parseRFC(util.decodeBase64String(this.content));
pEmail.sender = DocumentTemplate._replaceText(email[mail.MAIL_SENDER], replacements);
pEmail.subject = DocumentTemplate._replaceText(email[mail.MAIL_SUBJECT], replacements);
pEmail.body = DocumentTemplate._replaceText(email[mail.MAIL_HTMLTEXT], replacements);
if (this.type == DocumentTemplate.types.EML)
emailObj[contactId] = this._getReplacedEML(replacements[contactId], true);
else
{
let body = this.getReplacedContent(replacements[contactId]);
emailObj[contactId] = new Email(null, null, null, body);
}
}
else
pEmail.body = this.getReplacedContent(replacements);
return emailObj;
}
/**
* Replaces placeholders for EML. This function only works for the email body,
* so if you also need the subject, sender, etc use DocumentTemplate.prototype.setEmailTemplateByContactId.
* @private
*/
DocumentTemplate.prototype._getReplacementsByContactIds = function (pContactIds)
{
var config = this._getRequiredPlaceholders();
var contactIdPlaceholder = new Placeholder("contactId", Placeholder.types.SQLPART, "CONTACT.CONTACTID");
config = [contactIdPlaceholder].concat(config);
var addressData = getAddressesData(pContactIds, config, EmployeeUtils.getCurrentContactId()); //TODO: add sender selection
var replacements = {};
var placeholderNames = addressData[0];
var contactIdIndex = placeholderNames.indexOf(contactIdPlaceholder.toString());
for (let i = 1; i < addressData.length; i++)
{
let contactId = addressData[i][contactIdIndex];
for (let ii = 0, ll = placeholderNames.length; ii < ll; ii++)
{
if (!(contactId in replacements))
replacements[contactId] = {};
replacements[contactId][placeholderNames[ii]] = addressData[i][ii];
}
}
return replacements;
}
/**
* Replaces placeholders for EML
*
* @param {Object} pReplacements mapping with replacements for every placeholder
* @param {boolean} [pGetEmail] if true, return Email object
*
* @return {String} the replaced content
* @return {String|Email} the replaced content
*
* @private
*/
DocumentTemplate.prototype._getReplacedEML = function (pReplacements)
DocumentTemplate.prototype._getReplacedEML = function (pReplacements, pGetEmail)
{
var email = mail.parseRFC(util.decodeBase64String(this.content));
var htmlText = email[mail.MAIL_HTMLTEXT];
return DocumentTemplate._replaceText(htmlText, pReplacements);
var mailData = mail.parseRFC(util.decodeBase64String(this.content));
var email;
var body = DocumentTemplate._replaceText(mailData[mail.MAIL_HTMLTEXT], pReplacements);
if (pGetEmail)
{
var sender = DocumentTemplate._replaceText(mailData[mail.MAIL_SENDER], pReplacements);
var subject = DocumentTemplate._replaceText(mailData[mail.MAIL_SUBJECT], pReplacements);
email = new Email(null, sender, subject, body);
}
else
email = body;
return email;
}
/*
......@@ -297,7 +332,7 @@ DocumentTemplate.prototype._getReplacedODT = function (pReplacements)
DocumentTemplate.prototype._getReplacedDOCX = function (pReplacements)
{
var replacements = {};
for (let placeholder in pReplacements)
for (let placeholder in pReplacements) //removes the prefix and postfix, the process needs it like this
replacements[placeholder.slice(3, -3)] = pReplacements[placeholder];
//this is executed as a process because of better performance
......
......@@ -24,9 +24,9 @@ function EmailUtils () {}
EmailUtils.openMailTemplate = function (pToRecipients, pSenderContactId, pTemplateId, pRecipientContactId)
{
var email = new Email(pToRecipients);
email.setSender(pSenderContactId);
if (pTemplateId)
email.setTemplate(pTemplateId, pRecipientContactId);
email.setSender(pSenderContactId);
email.downloadEML();
}
......@@ -74,13 +74,14 @@ function Email (pToRecipients, pSender, pSubject, pBody, pCcRecipients, pBccReci
*
* @param {String} pTemplateId the id of the template
* @param {String} pContactId the id of the template
*
* @throws {Error} if the type of the template is invalid
*/
Email.prototype.setTemplate = function (pTemplateId, pContactId)
{
var template = DocumentTemplate.loadTemplate(pTemplateId);
template.setEmailTemplateByContactId(this, pContactId);
var email = template.getReplacedEmailsByContactIds([pContactId])[pContactId];
this.sender = email.sender;
this.body = email.body;
this.subject = email.subject;
}
/**
......@@ -186,4 +187,52 @@ Email.prototype.downloadEML = function()
{
neon.download(util.encodeBase64String(this.getRFCmail(), null), (this.subject || translate.text("Email Template")) + ".eml");
}
\ No newline at end of file
/**
* sends the email object
*
* @return {boolean} true, if the mail was sent sucessfully
*/
Email.prototype.send = function ()
{
var ENCODING = "UTF-8";
var mailId;
try
{
mailId = mail.newMail();
}
catch(ex)
{
//TODO: fix this dirty workaround [waiting for #1038963], since newMail causes an error on the first call after a user logged in
logging.log(ex);
util.sleep(1500);
mailId = mail.newMail();
}
if (this.toRecipients.length)
mail.addRecipients(mailId, mail.RECIPIENT_TO, this.toRecipients);
if (this.ccRecipients.length)
mail.addRecipients(mailId, mail.RECIPIENT_CC, this.ccRecipients);
if (this.bccRecipients.length)
mail.addRecipients(mailId, mail.RECIPIENT_BCC, this.bccRecipients);
if (this.subject)
mail.setSubject(mailId, this.subject, ENCODING);
if (this.body)
mail.addText(mailId, this.body, "text/html", ENCODING, null);
else
mail.addText(mailId, "", "text/html", ENCODING, null);
try
{
mail.sendMail(mailId);
return true;
}
catch (ex)
{
return false;
}
}
\ No newline at end of file
......@@ -107,3 +107,8 @@ $KeywordRegistry.permissionCondType = function(){return "PermissionCondType";};
$KeywordRegistry.permissionAccessType = function(){return "PermissionAccessType";};
$KeywordRegistry.communicationMediumCampaign = function(){return "CommunicationMediumCampaign";};
$KeywordRegistry.bulkMailSentStatus = function(){return "BulkMailSentStatus";};
$KeywordRegistry.bulkMailSentStatus$pending = function(){return "9a0c5608-070e-49fb-92cd-f6abece9242d";};
$KeywordRegistry.bulkMailSentStatus$sent = function(){return "147211fb-a1cf-49c8-8e08-c3cfe0404f9b";};
$KeywordRegistry.bulkMailSentStatus$failed = function(){return "353e27e9-7491-4bfd-b9f9-f18f2cb2a36c";};
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment