Work in progress on refactoring all mail sending to use the message sender an sender workers. No yet finished.
This commit is contained in:
parent
355e03900a
commit
4e9f6bd57b
22 changed files with 811 additions and 444 deletions
|
@ -17,11 +17,11 @@ const {SubscriptionStatus} = require('../../shared/lists');
|
|||
const subscriptions = require('./subscriptions');
|
||||
const segments = require('./segments');
|
||||
const senders = require('../lib/senders');
|
||||
const {LinkId} = require('./links');
|
||||
const links = require('./links');
|
||||
const feedcheck = require('../lib/feedcheck');
|
||||
const contextHelpers = require('../lib/context-helpers');
|
||||
const {convertFileURLs} = require('../lib/campaign-content');
|
||||
const {CampaignSender, MessageType} = require('../lib/campaign-sender');
|
||||
const messageSender = require('../lib/message-sender');
|
||||
const lists = require('./lists');
|
||||
|
||||
const {EntityActivityType, CampaignActivityType} = require('../../shared/activity-log');
|
||||
|
@ -298,7 +298,7 @@ async function listOpensDTAjax(context, campaignId, params) {
|
|||
return this.from('campaign_links')
|
||||
.where('campaign_links.campaign', campaignId)
|
||||
.where('campaign_links.list', cpgList.list)
|
||||
.where('campaign_links.link', LinkId.OPEN)
|
||||
.where('campaign_links.link', links.LinkId.OPEN)
|
||||
.as('related_campaign_links');
|
||||
},
|
||||
'related_campaign_links.subscription', subsTable + '.id')
|
||||
|
@ -705,16 +705,12 @@ async function getMessageByCid(messageCid, withVerpHostname = false) { // withVe
|
|||
}
|
||||
|
||||
async function getMessageByResponseId(responseId) {
|
||||
return await knex.transaction(async tx => {
|
||||
const message = await tx('campaign_messages')
|
||||
.where('campaign_messages.response_id', responseId)
|
||||
.select([
|
||||
'campaign_messages.id', 'campaign_messages.campaign', 'campaign_messages.list', 'campaign_messages.subscription', 'campaign_messages.status'
|
||||
])
|
||||
.first();
|
||||
|
||||
return message;
|
||||
});
|
||||
return await knex('campaign_messages')
|
||||
.where('campaign_messages.response_id', responseId)
|
||||
.select([
|
||||
'campaign_messages.id', 'campaign_messages.campaign', 'campaign_messages.list', 'campaign_messages.subscription', 'campaign_messages.status'
|
||||
])
|
||||
.first();
|
||||
}
|
||||
|
||||
const statusFieldMapping = {
|
||||
|
@ -747,7 +743,6 @@ async function _changeStatusByMessageTx(tx, context, message, subscriptionStatus
|
|||
}
|
||||
|
||||
async function changeStatusByCampaignCidAndSubscriptionIdTx(tx, context, campaignCid, listId, subscriptionId, subscriptionStatus) {
|
||||
const campaign = await tx('campaigns').where('cid', campaignCid);
|
||||
const message = await tx('campaign_messages')
|
||||
.innerJoin('campaigns', 'campaign_messages.campaign', 'campaigns.id')
|
||||
.where('campaigns.cid', campaignCid)
|
||||
|
@ -856,7 +851,7 @@ async function getSubscribersQueryGeneratorTx(tx, campaignId) {
|
|||
}
|
||||
}
|
||||
|
||||
async function _changeStatus(context, campaignId, permittedCurrentStates, newState, invalidStateMessage, scheduled = null) {
|
||||
async function _changeStatus(context, campaignId, permittedCurrentStates, newState, invalidStateMessage, startAt) {
|
||||
await knex.transaction(async tx => {
|
||||
const entity = await getByIdTx(tx, context, campaignId, false);
|
||||
|
||||
|
@ -866,10 +861,18 @@ async function _changeStatus(context, campaignId, permittedCurrentStates, newSta
|
|||
throw new interoperableErrors.InvalidStateError(invalidStateMessage);
|
||||
}
|
||||
|
||||
await tx('campaigns').where('id', campaignId).update({
|
||||
const updateData = {
|
||||
status: newState,
|
||||
scheduled
|
||||
});
|
||||
};
|
||||
|
||||
if (startAt !== undefined) {
|
||||
updateData.scheduled = startAt;
|
||||
if (!startAt || startAt.valueOf() < Date.now()) {
|
||||
updateData.start_at = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
await tx('campaigns').where('id', campaignId).update(updateData);
|
||||
|
||||
await activityLog.logEntityActivity('campaign', CampaignActivityType.STATUS_CHANGE, campaignId, {status: newState});
|
||||
});
|
||||
|
@ -929,8 +932,8 @@ async function getStatisticsOpened(context, id) {
|
|||
return await knex.transaction(async tx => {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'campaign', id, 'viewStats');
|
||||
|
||||
const devices = await tx('campaign_links').where('campaign', id).where('link', LinkId.OPEN).groupBy('device_type').select('device_type AS key').count('* as count');
|
||||
const countries = await tx('campaign_links').where('campaign', id).where('link', LinkId.OPEN).groupBy('country').select('country AS key').count('* as count');
|
||||
const devices = await tx('campaign_links').where('campaign', id).where('link', links.LinkId.OPEN).groupBy('device_type').select('device_type AS key').count('* as count');
|
||||
const countries = await tx('campaign_links').where('campaign', id).where('link', links.LinkId.OPEN).groupBy('country').select('country AS key').count('* as count');
|
||||
|
||||
return {
|
||||
devices,
|
||||
|
@ -959,7 +962,7 @@ async function testSend(context, data) {
|
|||
|
||||
await knex.transaction(async tx => {
|
||||
const processSubscriber = async (sendConfigurationId, listId, subscriptionId, messageData) => {
|
||||
await CampaignSender.queueMessageTx(tx, sendConfigurationId, listId, subscriptionId, MessageType.TEST, messageData);
|
||||
await messageSender.queueCampaignMessageTx(tx, sendConfigurationId, listId, subscriptionId, messageSender.MessageType.TEST, messageData);
|
||||
|
||||
await activityLog.logEntityActivity('campaign', CampaignActivityType.TEST_SEND, campaignId, {list: listId, subscription: subscriptionId});
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ async function addConfirmation(listId, action, ip, data) {
|
|||
*/
|
||||
async function takeConfirmation(cid) {
|
||||
return await knex.transaction(async tx => {
|
||||
const entry = await tx('confirmations').select(['cid', 'list', 'action', 'ip', 'data']).where('cid', cid).first();
|
||||
const entry = await tx('confirmations').select(['cid', 'list', 'action', 'ip', 'data']).where('cid', cid).forUpdate().first();
|
||||
|
||||
if (!entry) {
|
||||
return false;
|
||||
|
|
|
@ -504,7 +504,7 @@ async function serverValidate(context, listId, data) {
|
|||
async function _validateAndPreprocess(tx, listId, groupedFieldsMap, entity, meta, isCreate) {
|
||||
enforce(entity.email, 'Email must be set');
|
||||
|
||||
const existingWithKeyQuery = tx(getSubscriptionTableName(listId)).where('hash_email', hashEmail(entity.email));
|
||||
const existingWithKeyQuery = tx(getSubscriptionTableName(listId)).where('hash_email', hashEmail(entity.email)).forUpdate();
|
||||
|
||||
if (!isCreate) {
|
||||
existingWithKeyQuery.whereNot('id', entity.id);
|
||||
|
|
|
@ -153,7 +153,7 @@ async function remove(context, id) {
|
|||
|
||||
const MAX_EMAIL_COUNT = 100;
|
||||
async function sendAsTransactionalEmail(context, templateId, sendConfigurationId, emails, subject, mergeTags) {
|
||||
// TODO - Update this to use CampaignSender.queueMessageTx (with renderedHtml and renderedText)
|
||||
// TODO - Update this to use MessageSender.queueMessageTx (with renderedHtml and renderedText)
|
||||
|
||||
if (emails.length > MAX_EMAIL_COUNT) {
|
||||
throw new Error(`Cannot send more than ${MAX_EMAIL_COUNT} emails at once`);
|
||||
|
|
|
@ -12,6 +12,8 @@ const crypto = require('crypto');
|
|||
const settings = require('./settings');
|
||||
const {getTrustedUrl} = require('../lib/urls');
|
||||
const { tUI } = require('../lib/translate');
|
||||
const messageSender = require('../lib/message-sender');
|
||||
const {getSystemSendConfigurationId} = require('../../shared/send-configurations');
|
||||
|
||||
const bluebird = require('bluebird');
|
||||
|
||||
|
@ -19,8 +21,6 @@ const bcrypt = require('bcrypt-nodejs');
|
|||
const bcryptHash = bluebird.promisify(bcrypt.hash.bind(bcrypt));
|
||||
const bcryptCompare = bluebird.promisify(bcrypt.compare.bind(bcrypt));
|
||||
|
||||
const mailers = require('../lib/mailers');
|
||||
|
||||
const passport = require('../lib/passport');
|
||||
|
||||
const namespaceHelpers = require('../lib/namespace-helpers');
|
||||
|
@ -297,26 +297,31 @@ async function resetAccessToken(userId) {
|
|||
async function sendPasswordReset(locale, usernameOrEmail) {
|
||||
enforce(passport.isAuthMethodLocal, 'Local user management is required');
|
||||
|
||||
const resetToken = crypto.randomBytes(16).toString('base64').replace(/[^a-z0-9]/gi, '');
|
||||
let user;
|
||||
|
||||
await knex.transaction(async tx => {
|
||||
const user = await tx('users').where('username', usernameOrEmail).orWhere('email', usernameOrEmail).select(['id', 'username', 'email', 'name']).first();
|
||||
user = await tx('users').where('username', usernameOrEmail).orWhere('email', usernameOrEmail).select(['id', 'username', 'email', 'name']).forUpdate().first();
|
||||
|
||||
if (user) {
|
||||
const resetToken = crypto.randomBytes(16).toString('base64').replace(/[^a-z0-9]/gi, '');
|
||||
|
||||
await tx('users').where('id', user.id).update({
|
||||
reset_token: resetToken,
|
||||
reset_expire: new Date(Date.now() + 60 * 60 * 1000)
|
||||
});
|
||||
}
|
||||
// We intentionally silently ignore the situation when user is not found. This is not to reveal if a user exists in the system.
|
||||
|
||||
const { adminEmail } = await settings.get(contextHelpers.getAdminContext(), ['adminEmail']);
|
||||
});
|
||||
|
||||
const mailer = await mailers.getOrCreateMailer();
|
||||
await mailer.sendTransactionalMailBasedOnTemplate({
|
||||
to: {
|
||||
address: user.email
|
||||
},
|
||||
subject: tUI('mailerPasswordChangeRequest', locale)
|
||||
}, {
|
||||
if (user) {
|
||||
await messageSender.queueSubscriptionMessage(
|
||||
getSystemSendConfigurationId(),
|
||||
{
|
||||
address: user.email
|
||||
},
|
||||
tUI('mailerPasswordChangeRequest', locale),
|
||||
null,
|
||||
{
|
||||
html: 'users/password-reset-html.hbs',
|
||||
text: 'users/password-reset-text.hbs',
|
||||
locale,
|
||||
|
@ -326,10 +331,9 @@ async function sendPasswordReset(locale, usernameOrEmail) {
|
|||
name: user.name,
|
||||
confirmUrl: getTrustedUrl(`login/reset/${encodeURIComponent(user.username)}/${encodeURIComponent(resetToken)}`)
|
||||
}
|
||||
});
|
||||
}
|
||||
// We intentionally silently ignore the situation when user is not found. This is not to reveal if a user exists in the system.
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function isPasswordResetTokenValid(username, resetToken) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue