Newer
Older
Martin Groppe
committed
import("JditoFilter_lib");
import("CommunicationBlacklist_lib");
import("EmailFilterHandling_lib");
import("system.logging");
import("system.entities");
Martin Groppe
committed
import("system.fileIO");
import("system.project");
import("system.translate");
import("ActivityTask_lib");
import("system.util");
import("Contact_lib");
import("system.datetime");
import("system.neon");
import("Employee_lib");
import("system.vars");
import("KeywordRegistry_basic");
import("Sql_lib");
import("system.db");
import("DocumentTemplate_lib");
import("Communication_lib");
import("Email_lib");
import("system.process");
import("system.notification");
Martin Groppe
committed
import("system.db");
Martin Groppe
committed
import("system.workflow");
* Functions for bulk mails.
*/
function BulkMailUtils () {}
/**
* Executes a process to send bulk mails on the server and creates a notification when finished.
*
* @param {String} pBulkMailId <p>
* Id of the bulk mail.<br>
Martin Groppe
committed
* @param {Bool} pTestRun (optional) <p>
* True indicates a Testrun<br>
* @param {String} pUser=currentUser (optional) <p>
* User that will get the notification, <br>
* if null (not undefined!), no notification<br>
* will be created.<br>
Martin Groppe
committed
BulkMailUtils.sendBulkMailOnServer = function (pBulkMailId, pTestRun, pUser)
{
if (pUser === undefined)
pUser = EmployeeUtils.getCurrentUserId();
var processConfig = process.createStartAsyncConfig()
.setName("sendBulkMail_serverProcess")
.setLocalVariables({
Martin Groppe
committed
testRun : pTestRun,
Martin Groppe
committed
.setUser(pUser||"mailbridge")
}
/**
* Sends a bulk mail. You should only call this function on the server because it
* can take some time to execute, use BulkMailUtils.sendBulkMailOnServer instead.
*
* @param {String} pBulkMailId <p>
* Id of the bulk mail.<br>
Martin Groppe
committed
* True indicates a Testrun<br>
* @param {Bool} pUser (optional) <p>
* If there are no test recipients or no recipients marked for a test replacement in a test run
* we send an email to this user instead<br>
* @param {Object} pAdditionalLinkParameters(optional)<p>
* Additional parameters that get put into the weblinks for the redirect webservice.
* Expects object of key value pairs. <br>
* @param {String} pAdHochMailingRecipientId (optional) <p>
* The id of a recipient added to a adhoc mailing list. The mailing ignores all other recipients if this parameter is set<br>
* @param {String} pOriginUrl (optional) <p>
* Base URL for link replacement. Only needed when sending an Ad-Hoc Mailing without a configured baseReplacementURL in the Configuration <br>
* since sys.origin does not exist during workflowactions.
* @return {Object} <p>
* Count of sucessful and failed mails.<br>
BulkMailUtils.sendBulkMail = function (pBulkMailId, pIsTestRun, pUser, pAdditionalLinkParameters, pAdHochMailingRecipientId, pOriginUrl)
if (pIsTestRun == undefined)
{
pIsTestRun = false;
}
Martin Groppe
committed
var sendUserTitle = project.getPreferenceValue("custom.bulkmail.user");
var [templateId, subject, emailSender, createActivity, bulkMailName, useTemplateAttachments, mosaicoTemplateId] =
newSelect("DOCUMENTTEMPLATE_ID, SUBJECT, SENDER_EMAIL_ADDRESS, CREATEACTIVITIES, NAME, USE_TEMPLATE_ATTACHMENTS, MOSAICOTEMPLATE_ID")
.from("BULKMAIL")
.where("BULKMAIL.BULKMAILID", pBulkMailId)
.arrayRow();
useTemplateAttachments = Utils.toBoolean(useTemplateAttachments);

Vinzent Broens
committed
var template = BulkMailUtils.getBulkMailTemplate(pBulkMailId, templateId, true, useTemplateAttachments, null, mosaicoTemplateId);
Martin Groppe
committed
var testRecipientData;
var recipientLoadConfig = entities.createConfigForLoadingRows()
.fields(["BULKMAILRECIPIENTID", "CONTACT_ID", "EMAIL_ADDRESS", "PERSON_ID", "ORGANISATION_ID"])
.provider("RecipientsToBeMailed")
.addParameter("BulkMailId_param", pBulkMailId)
.addParameter("IsTestMail_param", pIsTestRun);
if(pAdHochMailingRecipientId)
{
recipientLoadConfig.uid(pAdHochMailingRecipientId);
}
recipientData = entities.getRows(recipientLoadConfig);
var blacklist = new CommunicationBlacklist().loadBlacklistRecipients(pBulkMailId);
Martin Groppe
committed
testRecipientData = newSelect("BULKMAILTESTRECIPIENT.CONTACT_ID, BULKMAILTESTRECIPIENT.EMAIL_ADDRESS")
.from("BULKMAILTESTRECIPIENT")
.where("BULKMAILTESTRECIPIENT.BULKMAIL_ID", pBulkMailId)
Martin Groppe
committed
.table();
if (testRecipientData.length == 0 || recipientData.length == 0 && pUser)
{
var userData = tools.getUserByAttribute(tools.NAME,pUser,tools.PROFILE_DEFAULT);
if (userData)
{
testRecipientData = [userData[tools.PARAMS][tools.CONTACTID],userData[tools.PARAMS][tools.EMAIL]];
recipientData = [{"CONTACT_ID":userData[tools.PARAMS][tools.CONTACTID],"EMAIL":userData[tools.PARAMS][tools.EMAIL]}];
}
}
Martin Groppe
committed
var mailrunId = util.getNewUUID();
new SqlBuilder()
.tableName("MAIL_RUN")
.insertFields({
"MAIL_RUNID": mailrunId,
"OBJECT_ROWID": pBulkMailId,
"OBJECT_TYPE": "Bulkmail",
"DATE_RUN_START": vars.get("$sys.date"),
"STATUS": $KeywordRegistry.bulkMailStatus$beingSent(),
"TESTRUN": pIsTestRun ? 1 : 0
});
Martin Groppe
committed
var mailLogIds = new Map();
var contactIds = recipientData.map(function (recipient)
{
var contactId = recipient["CONTACT_ID"];
mailLogIds.set(contactId, util.getNewUUID());
return contactId;
});
var baseUrl = (pOriginUrl || project.getInstanceConfigValue("custom.bulkmail.baseReplacementURL", vars.get("$sys.origin"))) + "/services/rest/redirect_rest?";
var additionalParameterString = "";
if (pAdditionalLinkParameters)
{
additionalParameterString = "&" + Object.keys(pAdditionalLinkParameters)
.map(function (key)
{
return key + "=" + pAdditionalLinkParameters[key]
})
.join("&");
}
var linkPlaceholders = newSelect(["PLACEHOLDER", "WEBLINKID", "URL", "ISREDIRECT"])
.from("WEBLINK")
.table()
.map(function ([placeholder, weblinkId, url, isRedirect])
{
if (Utils.toBoolean(isRedirect))
{
Martin Groppe
committed
var linkFn = function (pContactId)
{
return baseUrl + "link=" + weblinkId + "&log=" + mailLogIds.get(pContactId) + additionalParameterString;
Martin Groppe
committed
}
return new Placeholder(placeholder, Placeholder.types.CALLBACKFUNCTION, linkFn);
}
return new Placeholder(placeholder, Placeholder.types.FIXEDVALUE, url);
});
Martin Groppe
committed
Martin Groppe
committed
var webviewFn = function(pContactId)
{
return (pOriginUrl || project.getInstanceConfigValue("custom.bulkmail.baseReplacementURL", vars.get("$sys.origin"))) + "/services/rest/webview_rest?" + "log=" + mailLogIds.get(pContactId);
Martin Groppe
committed
}
var webviewPlaceholder = new Placeholder("webview", Placeholder.types.CALLBACKFUNCTION, webviewFn);
var additionalPlaceholders = [webviewPlaceholder].concat(linkPlaceholders);
var bouncedSoftIds = [];
var bouncedHardIds = [];
Martin Groppe
committed
var mails = template.getReplacedEmailsByContactIds(contactIds, additionalPlaceholders);
var subjectTemplate = new DocumentTemplate(subject, DocumentTemplate.types.PLAIN);
var subjects = subjectTemplate.getReplacedContentByContactIds(contactIds);
var bulkMailLink = [["BulkMail", pBulkMailId]];
var activitySubject = translate.withArguments("Bulk mail \"%0\" sent", [bulkMailName]);
var emailFilterProcessor = new IncomingEmailFilterProcessor().loadFilters();
if (!pIsTestRun)
{
recipientData.forEach(function (recipient)
{
let isSuccess = false;
Martin Groppe
committed
var errorMessage = "";
let recipientId = recipient["BULKMAILRECIPIENTID"];
let contactId = recipient["CONTACT_ID"];
let emailAddress = recipient["EMAIL_ADDRESS"];
let personId = recipient["PERSON_ID"];
let organisationId = recipient["ORGANISATION_ID"];
let email = mails[contactId];
Martin Groppe
committed
let recipientStatus = $KeywordRegistry.bulkMailRecipientStatus$failed();
if (email !== undefined && emailAddress && !blacklist.hasContactId(contactId))
Martin Groppe
committed
{
Martin Groppe
committed
try
{
email.toRecipients = [emailAddress];
email.sender = emailSender;
email.subject = subjects[contactId];
BulkMailUtils.storeEmlFile(pBulkMailId, mailrunId, mailLogId,email.getEML());
isSuccess = email.send(sendUserTitle);
if (!isSuccess)
{
errorMessage = logging.toLogString(email.getMailError(), true);
var filterType = emailFilterProcessor.processError(errorMessage, contactId, emailAddress);
if (filterType == $KeywordRegistry.emailFilterType$bounceHard())
bouncedStatus = $KeywordRegistry.bulkMailRecipientStatus$hardBounce();
else if (filterType == $KeywordRegistry.emailFilterType$bounceSoft())
bouncedStatus = $KeywordRegistry.bulkMailRecipientStatus$softBounce();
Martin Groppe
committed
recipientStatus = bouncedStatus || $KeywordRegistry.bulkMailRecipientStatus$failed();
}
else
{
recipientStatus = $KeywordRegistry.bulkMailRecipientStatus$sent();
}
}
catch (ex)
Martin Groppe
committed
errorMessage = logging.toLogString(ex, true);
//set the recipient status to 'sent' or 'failed'
new SqlBuilder()
.tableName("MAIL_LOG")
.insertFields({
"MAIL_LOGID": mailLogId,
"MAIL_RUN_ID": mailrunId,
"CONTACT_ID": contactId,
Martin Groppe
committed
"ERRORMESSAGE": errorMessage,
"SENDER_EMAIL": emailSender,
"RECIPIENT_EMAIL": emailAddress,
"MAILING_SUBJECT": subjects[contactId],
"DATE_SEND": vars.get("$sys.date")
});
Martin Groppe
committed
//TODO: Klären was von alter Logik noch bleiben soll. Status macht nur Sinn wenn jede Bulkmail nur einmal gesendet wird. Bleiben Activitys?
successIds.push(recipientId);
}
else if (bouncedStatus == $KeywordRegistry.bulkMailRecipientStatus$softBounce())
{
bouncedSoftIds.push(recipientId);
}
else if (bouncedStatus == $KeywordRegistry.bulkMailRecipientStatus$hardBounce())
{
bouncedHardIds.push(recipientId);
}
else
{
failedIds.push(recipientId);
}
if (isSuccess && createActivity == "1")
{
let activityData = {
categoryKeywordId : $KeywordRegistry.activityCategory$mail(),
directionKeywordId : $KeywordRegistry.activityDirection$outgoing(),
subject : activitySubject,
content : email.body
};
let contactLink = [[ContactUtils.getContextByPersOrg(personId, organisationId), contactId]];
ActivityUtils.insertNewActivity(activityData, bulkMailLink.concat(contactLink));
}
});
Martin Groppe
committed
var updates = [];

Vinzent Broens
committed
updates = updates.concat(successIds.map(function (successId)
Martin Groppe
committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
{
return newWhere("BULKMAILRECIPIENT.BULKMAILRECIPIENTID",successId)
.buildUpdateStatement({
"STATUS": $KeywordRegistry.bulkMailRecipientStatus$sent(),
"SENTDATE": sentDate
});
}));
updates = updates.concat(failedIds.map(function (failedId)
{
return newWhere("BULKMAILRECIPIENT.BULKMAILRECIPIENTID",failedId)
.buildUpdateStatement({
"STATUS": $KeywordRegistry.bulkMailRecipientStatus$failed(),
"SENTDATE": sentDate
});
}));
updates = updates.concat(bouncedSoftIds.map(function (bouncedSoftId)
{
return newWhere("BULKMAILRECIPIENT.BULKMAILRECIPIENTID",bouncedSoftId)
.buildUpdateStatement({
"STATUS": $KeywordRegistry.bulkMailRecipientStatus$softBounce(),
"SENTDATE": sentDate
});
}));
updates = updates.concat(bouncedHardIds.map(function (bouncedHardId)
{
return newWhere("BULKMAILRECIPIENT.BULKMAILRECIPIENTID",bouncedHardId)
.buildUpdateStatement({
"STATUS": $KeywordRegistry.bulkMailRecipientStatus$hardBounce(),
"SENTDATE": sentDate
});
}));
db.updates(updates);
newWhere("MAIL_RUN.MAIL_RUNID", mailrunId)
.updateFields({
"STATUS": $KeywordRegistry.bulkMailStatus$sent(),
"DATE_RUN_FINISHED": vars.get("$sys.date")
});
if(!pAdHochMailingRecipientId)
{
newWhere("BULKMAIL.BULKMAILID", pBulkMailId)
.updateFields({
"STATUS": $KeywordRegistry.bulkMailStatus$sent()
}
else
{
for (let i = 0, l = recipientData.length; i < l; i++)
{
let isSuccess = false;
Martin Groppe
committed
let errorMessage = "";
let contactId = recipientData[i]["CONTACT_ID"];
Martin Groppe
committed
let currentMailLogId = mailLogIds.get(contactId);
if (email !== undefined)
{
email.sender = emailSender;
email.subject = "Test: "+subjects[contactId];
for (let j =0; j<testRecipientData.length;j++)
{
if(testRecipientData[j][1])
{
Martin Groppe
committed
let nextMailLogId = util.getNewUUID();
Martin Groppe
committed
try
{
email.toRecipients = [testRecipientData[j][1]];
email.body = StringUtils.replaceAll(email.body,currentMailLogId,nextMailLogId);
currentMailLogId = nextMailLogId;
this.storeEmlFile(pBulkMailId, mailrunId, nextMailLogId,email.getEML());
isSuccess = email.send(sendUserTitle);
}
catch(ex)
{
errorMessage = logging.toLogString(ex, true);
}
Array.prototype.push.call(isSuccess ? successIds : failedIds, recipientData[i]["BULKMAILRECIPIENTID"]);
Martin Groppe
committed
new SqlBuilder()
.tableName("MAIL_LOG")
.insertFields({
"MAIL_LOGID":nextMailLogId,
"MAIL_RUN_ID":mailrunId,
"CONTACT_ID":testRecipientData[j][0],
Martin Groppe
committed
"ERRORMESSAGE": errorMessage || logging.toLogString(email.getMailError(), true) || "",
Martin Groppe
committed
"STATUS":(isSuccess ?$KeywordRegistry.bulkMailRecipientStatus$sent(): $KeywordRegistry.bulkMailRecipientStatus$failed()),
"SENDER_EMAIL":emailSender,
"RECIPIENT_EMAIL":testRecipientData[j][1],
"MAILING_SUBJECT":email.subject,
"DATE_SEND":vars.get("$sys.date")
Martin Groppe
committed
});
Martin Groppe
committed
}
}
Martin Groppe
committed
}
newWhere("MAIL_RUN.MAIL_RUNID",mailrunId)
.updateData(true,"MAIL_RUN",["STATUS","DATE_RUN_FINISHED"],null,[$KeywordRegistry.bulkMailStatus$sent(),vars.get("$sys.date")]);
}
return {
sucessful : successIds.length,
failed : failedIds.length
};
}
/**
* Opens a context to select a bulk mail to add recipients to.<br>
* @param {String} pContext the context of the contacts (Person or Organisation)
Martin Groppe
committed
* @param {String[]} pIds Ids that should be added.<br>
* @param {String|Object} pFilter the filter for the contacts that should be used if no Ids are selected
* @param {String|Object} pParameters the relevant parameters that are needed to get the Ids from entities.loadrows in the form:{parametername:parametervalue}
Martin Groppe
committed
BulkMailUtils.openAddRecipientView = function (pContext, pIds, pFilter, pParameters)
Martin Groppe
committed
if (!Utils.isString(pParameters))
pParameters = JSON.stringify(pParameters);
if (!Utils.isString(pIds))
pIds = JSON.stringify(pIds);
if (Utils.isString(pFilter))
pFilter = JSON.parse(pFilter);
Martin Groppe
committed
if(Utils.isNullOrEmpty(pFilter.filter))
pFilter.filter= JSON.parse(JditoFilterUtils.getEmptyFilter()).filter;
pFilter = JSON.stringify(pFilter);
var recipe = neonFilter.createEntityRecordsRecipeBuilder().parameters({
"ObjectType_param": pContext,
Martin Groppe
committed
"Ids_param": pIds,
"Filter_param": pFilter,
"Parameters_param": pParameters

Florian Maier
committed
neon.openContextWithRecipe("BulkMailAddRecipients", "BulkMailAddRecipientsEdit_view", recipe, neon.OPERATINGSTATE_VIEW);
/**
* Opens a context to select a bulk mail to add recipients to.<br>
*
* @param {String} pRecordsRecipe RecordsRecipe for the selection that should be added
*/
BulkMailUtils.openAddRecipientViewWithRecipe = function (pRecordsRecipe)
{
logging.log(pRecordsRecipe);
var recipe = neonFilter.createEntityRecordsRecipeBuilder().parameters({
"RecordsRecipe_param": pRecordsRecipe
}).toString();
neon.openContextWithRecipe("BulkMailAddRecipients", "BulkMailAddRecipientsEdit_view", recipe, neon.OPERATINGSTATE_VIEW);
}
* Deletes all bulk mail recipients that have a commrestriction for emails.<br>
* @param {String} pBulkMailId <p>
* The mail id.<br>
*/
BulkMailUtils.removeCommRestrictionRecipients = function (pBulkMailId)
{
var recipientIds = newSelect("BULKMAILRECIPIENTID")
.join("CONTACT", "BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
.where("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
.and(new CommunicationSettingsCondition()
.emails("BULKMAILRECIPIENT.EMAIL_ADDRESS")
.rejected()
.existSettings()
.buildCondition())
newWhereIfSet("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", recipientIds, SqlBuilder.IN())
* Adds recipients to a bulkmail.<br>
* @param {String} pBulkMailId <p>
* Bulk mail id.<br>
* @param {String[]} pContactIds <p>
* Contact ids of the recipients.<br>
*/
BulkMailUtils.addRecipients = function (pBulkMailId, pContactIds)
{
if (pContactIds.length > 0)
var sqlBuilder = new SqlBuilder();

Vinzent Broens
committed
var inserts = [];
var contactData;

Vinzent Broens
committed
while (pContactIds.length > 0){
var ContactIdsChunk = pContactIds.splice(0, 1000);
contactData = newSelect(["CONTACTID", "(" + CommUtil.getStandardSubSqlMail(newWhere("COMMUNICATION.OBJECT_ROWID = CONTACTID").and("COMMUNICATION.OBJECT_TYPE", "Contact")) + ")"])
.from("CONTACT")
.where("CONTACT.CONTACTID", ContactIdsChunk, SqlBuilder.IN())
.table();
inserts = inserts.concat(contactData.map(function([contactId, standardMail])
{
return sqlBuilder.buildInsertStatement({
"BULKMAIL_ID": pBulkMailId,
"CONTACT_ID": contactId,
"STATUS": $KeywordRegistry.bulkMailRecipientStatus$added(),
"IS_TEST_RECIPIENT" : 0,
"EMAIL_ADDRESS": standardMail
}, "BULKMAILRECIPIENT", "BULKMAILRECIPIENTID");
}));
}
* Loads the document template of a bulk mail. If the bulk mail
* itself has a template, it is preferred over the documentTemplate-id.
* @param {String} pBulkMailId <p>
* The id of the bulk mail.<br>
* @param {String} pDocumentTemplateId <p>
* The id of the document template.<br>
* @param {Boolean} pResolveSubtemplates=true (optional) <p>
* If true subtemplates are resolved (if the type is html)
* @param {Boolean} pUseTemplateAttachments=false <p>
* If true the attachments from the document template is always used
* @param {FileUpload} pUpload (optional) <p>
* The upload value if a custom template is used.<br>
* @param {String} pMosaicoTemplateId (optional) <p>
* The id of the mosaico template.<br>
* @return {DocumentTemplate} <p>
* The document template, null if no content was found.<br>
BulkMailUtils.getBulkMailTemplate = function (pBulkMailId, pDocumentTemplateId, pResolveSubtemplates, pUseTemplateAttachments, pUpload, pMosaicoTemplateId)
if (pUpload && pUpload.isFilled() && BulkMailUtils.isValidMimeType(pUpload.mimeType))
{
return DocumentTemplate.fromUpload(pUpload);
}
var bulkTemplate = DocumentTemplate.loadTemplate(pBulkMailId, "BULKMAIL", pResolveSubtemplates);
var documentTemplate = DocumentTemplate.loadTemplate(pDocumentTemplateId, undefined, pResolveSubtemplates);
var mosaicoTemplate = DocumentTemplate.loadTemplate(pMosaicoTemplateId, "MOSAICOTEMPLATE", pResolveSubtemplates);
if (pMosaicoTemplateId)
{
return mosaicoTemplate;
}
else
{
return documentTemplate;
}
if (pUseTemplateAttachments)
{
bulkTemplate.setAttachments(documentTemplate.getAttachments());
}
* Checks if a contact is a recipient of a bulk mail.<br>
* @param {String} pBulkMailId <p>
* The id of the bulk mail.<br>
* @param {String} pContactId <p>
* The contact id.<br>
* @param {String} pRecipientId <p>
* The contact id of the contact where,<br>
* the bulk mail shall sent to.<br>
* @return {boolean} <p>
* True, if the contact is a recipient.<br>
*/
BulkMailUtils.isRecipient = function (pBulkMailId, pContactId, pRecipientId)
{
return newSelect("count(*)")
.from("BULKMAILRECIPIENT")
.where("BULKMAILRECIPIENT.CONTACT_ID", pContactId)
.and("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
.andIfSet("BULKMAILRECIPIENT.BULKMAILRECIPIENTID", pRecipientId, SqlBuilder.NOT_EQUAL())
.cell() != "0"; //TODO: is there a way exists could be used?
* Opens the BulkMail context in new mode.<br>
* @param {String[]} pRecipients (optional) <p>
* Recipients that should be added after creation.<br>
Martin Groppe
committed
* @param {String} pContext (optional) <p>
* Context the filter is coming from.<br>
* @param {Object} pFilter (optional) <p>
* sys.filter of selection that should be added to new bulkmail<br>
Martin Groppe
committed
BulkMailUtils.newBulkMail = function (pRecipients, pContext, pFilter)
Martin Groppe
committed
"PresetRecipients_param" : pRecipients?JSON.stringify(pRecipients):null,
"PresetRecipientsContext_param": pContext,
"PresetRecipientsFilter_param": pFilter?JSON.stringify(pFilter):null
var recipe = neonFilter.createEntityRecordsRecipeBuilder().parameters(params).toString();

Florian Maier
committed
neon.openContextWithRecipe("BulkMail", "BulkMailEdit_view", recipe, neon.OPERATINGSTATE_NEW);
/**
* Opens the BulkMail context in new mode.<br>
*
* @param {String} pRecordsRecipe <p>
* Recordsrecipe containing the recipients for the new Bulkmail.
* Currently supported Contexts are campaignstep, campaignparticipant, person and <br> sys.filter of selection that should be added to new bulkmail<br>
*/
BulkMailUtils.newBulkMailWithRecordsRecipe = function (pRecordsRecipe)
{
if (!Utils.isString(pRecordsRecipe))
{
pRecordsRecipe = JSON.stringify(pRecordsRecipe);
}
var params = {
"PresetRecipientsRecordsRecipe_param": pRecordsRecipe
};
var recipe = neonFilter.createEntityRecordsRecipeBuilder().parameters(params).toString();
neon.openContextWithRecipe("BulkMail", "BulkMailEdit_view", recipe, neon.OPERATINGSTATE_NEW);
}
/**
* Filters the given contactIds if they can be added as new recipients.
* Checks if a contact is already a recipient or if there is a advertising ban.
*
* @param {String} pBulkMailId id of the bulk mail the contacts should be added to
* @param {String[]} pContactIds contacts to filter
* @return {String[]} contacts that can be added as recipients
*/
BulkMailUtils.filterNewRecipients = function (pBulkMailId, pContactIds)
{
return newSelect("CONTACTID")
.from("CONTACT")
.whereIfSet("CONTACT.CONTACTID", pContactIds, SqlBuilder.IN())
// only add contacts that aren't already recipients
.and(null, newSelect("BULKMAILRECIPIENTID")
.from("BULKMAILRECIPIENT")
.where("BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
.and("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
, SqlBuilder.NOT_EXISTS())
// check if there's a commrestriction
.and(new CommunicationSettingsCondition()
.emails(CommUtil.getStandardSubSqlMail())
.rejected()
.existNoSettings()
.buildCondition())
Martin Groppe
committed
/**
* Filters the given contactIds if they can be added as new recipients.
* Checks if a contact is already a recipient or if there is a advertising ban.
*
* @param {String} pBulkMailId id of the bulk mail the contacts should be added to
* @param {String} pCondition Condition part of sys.filter
* @param {String} pContext Context that belongs to the filtercondition
* @return {String[]} contacts that can be added as recipients
*/
BulkMailUtils.filterNewRecipientsByCondition = function (pBulkMailId, pCondition, pContext)
{
var condition = newSelect("CONTACTID")
.from("CONTACT")

Vinzent Broens
committed
.join("ADDRESS", "ADDRESS.ADDRESSID = CONTACT.ADDRESS_ID")
.join("ORGANISATION", "ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID")
Martin Groppe
committed
.whereIfSet(pCondition)
// only add contacts that aren't already recipients
.and(null, newSelect("BULKMAILRECIPIENTID")
.from("BULKMAILRECIPIENT")
.where("BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
.and("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
, SqlBuilder.NOT_EXISTS())
// check if there's a commrestriction
.and(new CommunicationSettingsCondition()
.emails(CommUtil.getStandardSubSqlMail())
.rejected()
.existNoSettings()
.buildCondition());
if (pContext == "Person")
{

Vinzent Broens
committed
condition.join("PERSON", "PERSON.PERSONID = CONTACT.PERSON_ID");
Martin Groppe
committed
}

Vinzent Broens
committed
if (pContext == "Organisation")
Martin Groppe
committed
{
condition.and("CONTACT.PERSON_ID is null");
}
if (pContext == "CampaignParticipant")
{
condition.join("CAMPAIGNPARTICIPANT","CAMPAIGNPARTICIPANT.CONTACT_ID = CONTACT.CONTACTID");
}
if (pContext == "CampaignStep")
{
condition.join("CAMPAIGNPARTICIPANT","CAMPAIGNPARTICIPANT.CONTACT_ID = CONTACT.CONTACTID")
.join("CAMPAIGNSTEP","CAMPAIGNSTEP.CAMPAIGNSTEPID = CAMPAIGNPARTICIPANT.CAMPAIGNSTEP_ID");
}
return condition.arrayColumn();
}
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
/*
* adds a Recipient to an ad hoc mailing list and sends the mail.
*
* @param {String} pBulkMailId id of the bulk mail the contact should be added to
* @param {String} pContactId id of the contact that gets added
* @param {String} pEmailAddress address the ad hoc mailing gets sent to.
* @param {Object} pAdditionalLinkParameters(optional)<p>
* Additional parameters that get put into the weblinks for the redirect webservice.
* Expects object of key value pairs. <br>
* @param {String} pOriginUrl Base URL for link replacement.
*/
BulkMailUtils.addToAdHocMail = function (pBulkMailId, pContactId, pEmailAddress, pAdditionalLinkParameters, pOriginUrl)
{
if(!pBulkMailId || !pContactId)
{
return;
}
var bulkMailRecipientId = util.getNewUUID();
new SqlBuilder().insertFields({
"BULKMAILRECIPIENTID": bulkMailRecipientId,
"BULKMAIL_ID": pBulkMailId,
"CONTACT_ID": pContactId,
"STATUS": $KeywordRegistry.bulkMailRecipientStatus$pending(),
"EMAIL_ADDRESS": pEmailAddress
},
"BULKMAILRECIPIENT");
this.sendBulkMail(pBulkMailId, false, false, pAdditionalLinkParameters, bulkMailRecipientId, pOriginUrl);
}
Martin Groppe
committed
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
/**
* Filters the given contactIds if they can be added as new recipients.
* Checks if a contact is already a recipient or if there is a advertising ban.
*
* @param {String} pBulkMailId id of the bulk mail the contacts should be added to
* @param {String} pRecordsRecipe recordsrecipe for the selection that should be filtered.
* @return {String[]} contacts that can be added as recipients
*/
BulkMailUtils.filterNewRecipientsByRecordsRecipe = function (pBulkMailId, pRecordsRecipe)
{
var recipients = [];
var entity = JSON.parse(pRecordsRecipe).entityName;
var loadConfig = entities.createConfigForLoadingRows()
.fromEntityRecordsRecipe(pRecordsRecipe)
.fields(["#UID"]);
var rows = entities.getRows(loadConfig);
while (rows.length > 0)
{
var currentIds = rows.splice(0,1000).map(function (row)
{
return row["#UID"];
});
var sql = newSelect("CONTACTID")
.from("CONTACT")
.join("ADDRESS", "ADDRESS.ADDRESSID = CONTACT.ADDRESS_ID")
.join("ORGANISATION", "ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID")
// only add contacts that aren't already recipients
.where(null, newSelect("BULKMAILRECIPIENTID")
.from("BULKMAILRECIPIENT")
.where("BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID")
.and("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId)
, SqlBuilder.NOT_EXISTS())
// check if there's a commrestriction
.and(new CommunicationSettingsCondition()
.emails(CommUtil.getStandardSubSqlMail())
.rejected()
.existNoSettings()
.buildCondition());
if (entity == "Person_entity")
{
sql.join("PERSON", "PERSON.PERSONID = CONTACT.PERSON_ID")
.and("CONTACT.CONTACTID",currentIds,SqlBuilder.IN());
}
if (entity == "Organisation_entity")
{
sql.and("CONTACT.PERSON_ID is null")
.and("CONTACT.CONTACTID",currentIds,SqlBuilder.IN());
}
if (entity == "CampaignParticipant_entity")
{
sql.join("CAMPAIGNPARTICIPANT","CAMPAIGNPARTICIPANT.CONTACT_ID = CONTACT.CONTACTID")
.and("CAMPAIGNPARTICIPANT.CAMPAIGNPARTICIPANTID",currentIds,SqlBuilder.IN());
}
if (entity == "CampaignStep_entity")
{
sql.join("CAMPAIGNPARTICIPANT","CAMPAIGNPARTICIPANT.CONTACT_ID = CONTACT.CONTACTID")
.join("CAMPAIGNSTEP","CAMPAIGNSTEP.CAMPAIGNSTEPID = CAMPAIGNPARTICIPANT.CAMPAIGNSTEP_ID")
.and("CAMPAIGNSTEP.CAMPAIGNSTEPID",currentIds,SqlBuilder.IN());
}
recipients = recipients.concat(sql.arrayColumn());
}
return recipients;
}
* Opens the given bulk mail.
*
* @param {String} pBulkMailId <p>
* The id of the bulk mail.<br>
*/
BulkMailUtils.openBulkMail = function (pBulkMailId)
{
var recipe = neonFilter.createEntityRecordsRecipeBuilder().uidsIncludelist([pBulkMailId]).toString();

Florian Maier
committed
neon.openContextWithRecipe("BulkMail", "BulkMailMain_view", recipe, neon.OPERATINGSTATE_VIEW);
* Checks is the given mime type can be used for a bulk mail.<br>
* @param {String} pMimeType <p>
* The mime type.<br>
* @return {Boolean} <p>
* Whether the type is usable or not.<br>
*/
BulkMailUtils.isValidMimeType = function (pMimeType)
{
var templateType = DocumentTemplate.types.fromMimeType(pMimeType);
return BulkMailUtils.isValidTemplateType(templateType)
}
/**
* Checks is the given template type can be used for a bulk mail.<br>
* @param {String} pTemplateType <p>
* Template type.<br>
* @return {Boolean} <p>
* Whether the type is usable or not.<br>
*/
BulkMailUtils.isValidTemplateType = function (pTemplateType)
{
switch (pTemplateType)
{
case DocumentTemplate.types.EML:
case DocumentTemplate.types.HTML:
case DocumentTemplate.types.TXT:
return true;
default:
return false;
}
}
* Checks whether the given status id matches,<br>
* to the status of a bulk mail which is sent or<br>
* not.
*
* @param {String} pStatus <p>
* The key id of the current status.<br>
* @return {Boolean} <p>
* True if the status is "sent" or "sending".<br>
*/
BulkMailUtils.isStatusSendingOrSent = function (pStatus)
{
return pStatus == $KeywordRegistry.bulkMailStatus$sent() || pStatus == $KeywordRegistry.bulkMailStatus$beingSent()
}
/**
* Checks whether the given status id matches,<br>
* to the status of a bulk mail which is sent or<br>
* not.
*
* @param {String} pStatus <p>
* The key id of the current status.<br>
* @return {Boolean} <p>
* True if the status is "sent" or "sending".<br>
*/
BulkMailUtils.isStatusSendingSentOrAdHoc = function (pStatus)
{
return pStatus == $KeywordRegistry.bulkMailStatus$sent() || pStatus == $KeywordRegistry.bulkMailStatus$beingSent() || pStatus == $KeywordRegistry.bulkMailStatus$adHoc()
}
/**
* Opens BulkMail context in new mode, with the given bulk mail id.<br>
*
* @param {String} pBulkMailId <p>
* The id of the bulk mail.<br>
*/
BulkMailUtils.copy = function(pBulkMailId)
{
var params = {
"CopyBulkMailId_param" : pBulkMailId
};
var recipe = neonFilter.createEntityRecordsRecipeBuilder().parameters(params).toString();

Florian Maier
committed
neon.openContextWithRecipe("BulkMail", null, recipe, neon.OPERATINGSTATE_NEW);
/**
* Opens BulkMail context in new mode, with the given template from MosaicoTemplate id.<br>
*
* @param {String} pMosaicoTemplateId <p>
* The id of the bulk mail.<br>
*/
BulkMailUtils.createFromMosaicoTemplate = function(pMosaicoTemplateId)
{
var params = {
"CreateFromMosaicoTemplateId_param" : pMosaicoTemplateId
};
var recipe = neonFilter.createEntityRecordsRecipeBuilder().parameters(params).toString();

Florian Maier
committed
neon.openContextWithRecipe("BulkMail", null, recipe, neon.OPERATINGSTATE_NEW);
}
Martin Groppe
committed
/*
*Stores the Eml file for a bulkmailrecipient in the Filesystem
*
* @param {String} pBulkMailId <p>
* The id of the bulk mail.<br>
* @param {String} pMailRunId <p>
* The id of the bulk mail run.<br>
* @param {String} pMailLogId <p>
* The id of the corresponding mail log entry.<br>
* @param {String} pFile
Martin Groppe
committed
**/
BulkMailUtils.storeEmlFile = function (pBulkMailId, pMailRunId, pMailLogId, pFile)
var locationoption = project.getPreferenceValue("bulkmail.fileStorage", "/bulkMailFiles/");
var path = vars.get("$sys.serverdata") + locationoption + pBulkMailId + "/" + pMailRunId + "/";
var filename = pMailLogId + ".eml"
Martin Groppe
committed
var fullPath = path + filename;
fileIO.storeData(fullPath, pFile, util.DATA_BINARY, false);
}
/*
* Stores the eml file of a bounce in the filesystem
*
* @param {String} pBounceId <p>
* The id of the bounce.<br>
* @param {String} pFile
**/
BulkMailUtils.storeBounceEmlFile = function (pBounceId, pFile)
{
var locationoption = project.getPreferenceValue("bulkmail.fileStorage", "/bulkMailFiles/");
var path = vars.get("$sys.serverdata") + locationoption + "Bounces/";
var filename = pBounceId + ".eml"
var fullPath = path + filename;
fileIO.storeData(fullPath, pFile, util.DATA_TEXT, false);
}
Martin Groppe
committed
/*
*Loads the Eml file for a bulkmailrecipient from the Filesystem
*
* @param {String} pBulkMailId <p>
* The id of the bulk mail.<br>
* @param {String} pMailRunId <p>
* The id of the bulk mail run.<br>
* @param {String} pMailLogId <p>
* The id of the corresponding mail log entry.<br>
* @return {String} <p>
* The file as base64 String<br>
**/
BulkMailUtils.getEmlFile = function(pBulkMailId,pMailRunId, pMailLogId)
{
Martin Groppe
committed
var locationoption = project.getPreferenceValue("bulkmail.fileStorage","/bulkMailFiles/");
var path = vars.get("$sys.serverdata")+locationoption +pBulkMailId+"/"+pMailRunId+"/";
var filename = pMailLogId+".eml"
var fullPath = path + filename;
return (fileIO.getData(fullPath,util.DATA_BINARY));
}