parent
564c83720b
commit
ca615a86a5
6 changed files with 119 additions and 103 deletions
|
@ -74,7 +74,7 @@ class PreviewForTestUserModalDialog extends Component {
|
|||
const accessToken = result.data;
|
||||
window.open(getSandboxUrl(`cpgs/rss-preview/${campaignCid}/${listCid}/${subscriptionCid}`, accessToken, {withLocale: true}), '_blank');
|
||||
|
||||
} else if (entity.type === CampaignType.REGULAR) {
|
||||
} else if (entity.type === CampaignType.REGULAR || entity.type === CampaignType.RSS_ENTRY) {
|
||||
window.open(getPublicUrl(`archive/${campaignCid}/${listCid}/${subscriptionCid}`, {withLocale: true}), '_blank');
|
||||
|
||||
} else {
|
||||
|
@ -322,6 +322,7 @@ class SendControls extends Component {
|
|||
|
||||
const dialogs = (
|
||||
<>
|
||||
PreviewForTestUserModalDialog
|
||||
<TestSendModalDialog
|
||||
mode={TestSendModalDialogMode.CAMPAIGN_STATUS}
|
||||
visible={this.state.showTestSendModal}
|
||||
|
@ -627,7 +628,7 @@ export default class Status extends Component {
|
|||
|
||||
if (perms.includes('view')) {
|
||||
actions.push({
|
||||
label: <Icon icon="send" title={t('status')}/>,
|
||||
label: <Icon icon="envelope" title={t('status')}/>,
|
||||
link: `/campaigns/${data[0]}/status`
|
||||
});
|
||||
}
|
||||
|
@ -659,7 +660,7 @@ export default class Status extends Component {
|
|||
<hr/>
|
||||
<h3>RSS Entries</h3>
|
||||
<p>{t('ifANewEntryIsFoundFromCampaignFeedANew')}</p>
|
||||
<Table withHeader dataUrl={`rest/campaigns-children/${this.props.entity.id}`} columns={campaignsChildrenColumns} />
|
||||
<Table withHeader dataUrl={`rest/campaigns-children/${this.props.entity.id}`} columns={campaignsChildrenColumns} order={[3, 'desc']}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -57,9 +57,14 @@ async function fetch(url) {
|
|||
|
||||
const entries = [];
|
||||
for (const item of items) {
|
||||
let date = item.date || item.pubdate || item.pubDate;
|
||||
if (date) {
|
||||
date = (new Date(date)).toISOString();
|
||||
}
|
||||
|
||||
const entry = {
|
||||
title: item.title,
|
||||
date: item.date || item.pubdate || item.pubDate || new Date(),
|
||||
date: date,
|
||||
guid: item.guid || item.link,
|
||||
link: item.link,
|
||||
content: item.description || item.summary,
|
||||
|
@ -84,7 +89,7 @@ async function getEntryForPreview(url) {
|
|||
if (entries.length === 0) {
|
||||
entry = {
|
||||
title: "Lorem Ipsum",
|
||||
date: new Date(),
|
||||
date: (new Date()).toISOString(),
|
||||
guid: "c21bc6c8-d351-4000-aa1f-e7ff928084cd",
|
||||
link: "http://www.example.com/sample-item.html",
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer gravida a purus in commodo. Sed risus eros, pharetra sit amet sagittis vel, porta nec magna. Sed sollicitudin blandit ornare. Pellentesque a lacinia dui. Etiam ullamcorper, nisl at pharetra fringilla, enim nunc blandit quam, nec vestibulum purus lorem in urna.",
|
||||
|
|
|
@ -741,14 +741,14 @@ async function queueSubscriptionMessage(sendConfigurationId, to, subject, encryp
|
|||
senders.scheduleCheck();
|
||||
}
|
||||
|
||||
async function getMessage(campaignCid, listCid, subscriptionCid, settings) {
|
||||
async function getMessage(campaignCid, listCid, subscriptionCid, settings, isTest = false) {
|
||||
const cs = new MessageSender();
|
||||
await cs._init({type: MessageType.REGULAR, campaignCid, listCid, ...settings});
|
||||
|
||||
const campaign = cs.campaign;
|
||||
const list = cs.listsByCid.get(listCid);
|
||||
|
||||
const subscriptionGrouped = await subscriptions.getByCid(contextHelpers.getAdminContext(), list.id, subscriptionCid);
|
||||
const subscriptionGrouped = await subscriptions.getByCid(contextHelpers.getAdminContext(), list.id, subscriptionCid, true, isTest);
|
||||
|
||||
let listOk = false;
|
||||
|
||||
|
|
|
@ -166,6 +166,10 @@ function _formatTemplateSimple(source, mergeTags, isHTML) {
|
|||
}
|
||||
}
|
||||
|
||||
if (value === undefined) { // in RSS it may happen that the key is present, but the value is undefined
|
||||
return '';
|
||||
}
|
||||
|
||||
const containsHTML = /<[a-z][\s\S]*>/.test(value);
|
||||
return isHTML ? he.encode((containsHTML ? value : value.replace(/(?:\r\n|\r|\n)/g, '<br/>')), {
|
||||
useNamedReferences: true,
|
||||
|
|
|
@ -530,6 +530,7 @@ async function _createTx(tx, context, entity, content) {
|
|||
filteredEntity.status = CampaignStatus.ACTIVE;
|
||||
} else if (filteredEntity.type === CampaignType.RSS_ENTRY) {
|
||||
filteredEntity.status = CampaignStatus.SCHEDULED;
|
||||
filteredEntity.start_at = new Date();
|
||||
} else {
|
||||
filteredEntity.status = CampaignStatus.IDLE;
|
||||
}
|
||||
|
@ -635,7 +636,7 @@ async function updateWithConsistencyCheck(context, entity, content) {
|
|||
});
|
||||
}
|
||||
|
||||
async function _removeTx(tx, context, id, existing = null) {
|
||||
async function _removeTx(tx, context, id, existing = null, overrideTypeCheck = false) {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'campaign', id, 'delete');
|
||||
|
||||
if (!existing) {
|
||||
|
@ -646,11 +647,13 @@ async function _removeTx(tx, context, id, existing = null) {
|
|||
return new interoperableErrors.InvalidStateError;
|
||||
}
|
||||
|
||||
enforce(existing.type === CampaignType.REGULAR || existing.type === CampaignType.RSS || existing.type === CampaignType.TRIGGERED, 'This campaign cannot be removed by user.');
|
||||
if (!overrideTypeCheck) {
|
||||
enforce(existing.type === CampaignType.REGULAR || existing.type === CampaignType.RSS || existing.type === CampaignType.TRIGGERED, 'This campaign cannot be removed by user.');
|
||||
}
|
||||
|
||||
const childCampaigns = await tx('campaigns').where('parent', id).select(['id', 'status', 'type']);
|
||||
for (const childCampaign of childCampaigns) {
|
||||
await _removeTx(tx, contect, childCampaign.id, childCampaign);
|
||||
await _removeTx(tx, context, childCampaign.id, childCampaign, true);
|
||||
}
|
||||
|
||||
await files.removeAllTx(tx, context, 'campaign', 'file', id);
|
||||
|
@ -1104,21 +1107,12 @@ async function getRssPreview(context, campaignCid, listCid, subscriptionCid) {
|
|||
|
||||
enforce(campaign.type === CampaignType.RSS);
|
||||
|
||||
const list = await lists.getByCid(context, listCid);
|
||||
await shares.enforceEntityPermission(context, 'list', list.id, 'viewTestSubscriptions');
|
||||
|
||||
const subscription = await subscriptions.getByCid(context, list.id, subscriptionCid);
|
||||
|
||||
if (!subscription.is_test) {
|
||||
shares.throwPermissionDenied();
|
||||
}
|
||||
|
||||
const settings = {
|
||||
campaign, // this prevents message sender from fetching the campaign again
|
||||
rssEntry: await feedcheck.getEntryForPreview(campaign.data.feedUrl)
|
||||
};
|
||||
|
||||
return await messageSender.getMessage(campaignCid, listCid, subscriptionCid, settings);
|
||||
return await messageSender.getMessage(campaignCid, listCid, subscriptionCid, settings, true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
const config = require('../lib/config');
|
||||
const process = require('process');
|
||||
const log = require('../lib/log');
|
||||
const knex = require('../lib/knex');
|
||||
const senders = require('../lib/senders');
|
||||
const { CampaignType, CampaignStatus, CampaignSource } = require('../../shared/campaigns');
|
||||
const campaigns = require('../models/campaigns');
|
||||
const contextHelpers = require('../lib/context-helpers');
|
||||
|
@ -26,106 +28,116 @@ async function run() {
|
|||
|
||||
running = true;
|
||||
|
||||
let rssCampaignIdRow;
|
||||
try {
|
||||
let rssCampaignIdRow;
|
||||
|
||||
while (rssCampaignIdRow = await knex('campaigns')
|
||||
.where('type', CampaignType.RSS)
|
||||
.where('status', CampaignStatus.ACTIVE)
|
||||
.where(qry => qry.whereNull('last_check').orWhere('last_check', '<', new Date(Date.now() - feedCheckInterval)))
|
||||
.select('id')
|
||||
.first()) {
|
||||
while (rssCampaignIdRow = await knex('campaigns')
|
||||
.where('type', CampaignType.RSS)
|
||||
.where('status', CampaignStatus.ACTIVE)
|
||||
.where(qry => qry.whereNull('last_check').orWhere('last_check', '<', new Date(Date.now() - feedCheckInterval)))
|
||||
.select('id')
|
||||
.first()) {
|
||||
|
||||
const rssCampaign = await campaigns.getById(contextHelpers.getAdminContext(), rssCampaignIdRow.id, false);
|
||||
const rssCampaign = await campaigns.getById(contextHelpers.getAdminContext(), rssCampaignIdRow.id, false);
|
||||
|
||||
let checkStatus = null;
|
||||
let checkStatus = null;
|
||||
|
||||
try {
|
||||
const entries = await fetch(rssCampaign.data.feedUrl);
|
||||
try {
|
||||
const entries = await fetch(rssCampaign.data.feedUrl);
|
||||
|
||||
let added = 0;
|
||||
let added = 0;
|
||||
|
||||
for (const entry of entries) {
|
||||
let entryId = null;
|
||||
for (const entry of entries) {
|
||||
let entryId = null;
|
||||
|
||||
await knex.transaction(async tx => {
|
||||
const existingEntry = await tx('rss').where({
|
||||
parent: rssCampaign.id,
|
||||
guid: entry.guid
|
||||
}).first();
|
||||
await knex.transaction(async tx => {
|
||||
const existingEntry = await tx('rss').where({
|
||||
parent: rssCampaign.id,
|
||||
guid: entry.guid
|
||||
}).first();
|
||||
|
||||
if (!existingEntry) {
|
||||
const campaignData = {};
|
||||
if (!existingEntry) {
|
||||
const campaignData = {};
|
||||
|
||||
let source = rssCampaign.source;
|
||||
if (source === CampaignSource.CUSTOM_FROM_TEMPLATE || source === CampaignSource.CUSTOM) {
|
||||
source = CampaignSource.CUSTOM_FROM_CAMPAIGN;
|
||||
campaignData.sourceCampaign = rssCampaign.id;
|
||||
} else {
|
||||
Object.assign(campaignData, rssCampaign.data);
|
||||
let source = rssCampaign.source;
|
||||
if (source === CampaignSource.CUSTOM_FROM_TEMPLATE || source === CampaignSource.CUSTOM) {
|
||||
source = CampaignSource.CUSTOM_FROM_CAMPAIGN;
|
||||
campaignData.sourceCampaign = rssCampaign.id;
|
||||
} else {
|
||||
Object.assign(campaignData, rssCampaign.data);
|
||||
}
|
||||
|
||||
campaignData.rssEntry = entry;
|
||||
|
||||
const campaign = {
|
||||
parent: rssCampaign.id,
|
||||
type: CampaignType.RSS_ENTRY,
|
||||
source,
|
||||
name: entry.title || `RSS entry ${entry.guid.substr(0, 67)}`,
|
||||
lists: rssCampaign.lists,
|
||||
namespace: rssCampaign.namespace,
|
||||
send_configuration: rssCampaign.send_configuration,
|
||||
|
||||
from_name_override: rssCampaign.from_name_override,
|
||||
from_email_override: rssCampaign.from_email_override,
|
||||
reply_to_override: rssCampaign.reply_to_override,
|
||||
subject: rssCampaign.subject,
|
||||
data: campaignData,
|
||||
|
||||
click_tracking_disabled: rssCampaign.click_tracking_disabled,
|
||||
open_tracking_disabled: rssCampaign.open_tracking_disabled,
|
||||
unsubscribe_url: rssCampaign.unsubscribe_url
|
||||
};
|
||||
|
||||
const ids = await campaigns.createRssTx(tx, contextHelpers.getAdminContext(), campaign);
|
||||
const campaignId = ids[0];
|
||||
|
||||
await tx('rss').insert({
|
||||
parent: rssCampaign.id,
|
||||
campaign: campaignId,
|
||||
guid: entry.guid,
|
||||
pubdate: entry.date ? new Date(entry.date) : null,
|
||||
});
|
||||
|
||||
added += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
campaignData.rssEntry = entry;
|
||||
if (added > 0) {
|
||||
checkStatus = tLog('foundAddedMessagesNewCampaignMessages', {
|
||||
addedMessages: added,
|
||||
campaignId: rssCampaign.id
|
||||
});
|
||||
log.verbose('Feed', `Found ${added} new campaigns messages from feed ${rssCampaign.id}`);
|
||||
|
||||
const campaign = {
|
||||
parent: rssCampaign.id,
|
||||
type: CampaignType.RSS_ENTRY,
|
||||
source,
|
||||
name: entry.title || `RSS entry ${entry.guid.substr(0, 67)}`,
|
||||
lists: rssCampaign.lists,
|
||||
namespace: rssCampaign.namespace,
|
||||
send_configuration: rssCampaign.send_configuration,
|
||||
process.send({
|
||||
type: 'entries-added'
|
||||
});
|
||||
} else {
|
||||
checkStatus = tLog('foundNothingNewFromTheFeed');
|
||||
}
|
||||
|
||||
from_name_override: rssCampaign.from_name_override,
|
||||
from_email_override: rssCampaign.from_email_override,
|
||||
reply_to_override: rssCampaign.reply_to_override,
|
||||
subject: rssCampaign.subject,
|
||||
data: campaignData,
|
||||
rssCampaign.data.checkStatus = checkStatus;
|
||||
await knex('campaigns').where('id', rssCampaign.id).update({
|
||||
last_check: new Date(),
|
||||
data: JSON.stringify(rssCampaign.data)
|
||||
});
|
||||
|
||||
click_tracking_disabled: rssCampaign.click_tracking_disabled,
|
||||
open_tracking_disabled: rssCampaign.open_tracking_disabled,
|
||||
unsubscribe_url: rssCampaign.unsubscribe_url
|
||||
};
|
||||
|
||||
const ids = await campaigns.createRssTx(tx, contextHelpers.getAdminContext(), campaign);
|
||||
const campaignId = ids[0];
|
||||
|
||||
await tx('rss').insert({
|
||||
parent: rssCampaign.id,
|
||||
campaign: campaignId,
|
||||
guid: entry.guid,
|
||||
pubdate: entry.date,
|
||||
});
|
||||
|
||||
added += 1;
|
||||
}
|
||||
} catch (err) {
|
||||
log.error('Feed', err.message);
|
||||
log.verbose(err.stack);
|
||||
rssCampaign.data.checkStatus = err.message;
|
||||
await knex('campaigns').where('id', rssCampaign.id).update({
|
||||
last_check: new Date(),
|
||||
data: JSON.stringify(rssCampaign.data)
|
||||
});
|
||||
}
|
||||
|
||||
if (added > 0) {
|
||||
checkStatus = tLog('foundAddedMessagesNewCampaignMessages', {addedMessages: added, campaignId: rssCampaign.id});
|
||||
log.verbose('Feed', `Found ${added} new campaigns messages from feed ${rssCampaign.id}`);
|
||||
|
||||
process.send({
|
||||
type: 'entries-added'
|
||||
});
|
||||
} else {
|
||||
checkStatus = tLog('foundNothingNewFromTheFeed');
|
||||
}
|
||||
|
||||
rssCampaign.data.checkStatus = checkStatus;
|
||||
await knex('campaigns').where('id', rssCampaign.id).update({
|
||||
last_check: new Date(),
|
||||
data: JSON.stringify(rssCampaign.data)
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
log.error('Feed', err.message);
|
||||
rssCampaign.data.checkStatus = err.message;
|
||||
await knex('campaigns').where('id', rssCampaign.id).update({
|
||||
last_check: new Date(),
|
||||
data: JSON.stringify(rssCampaign.data)
|
||||
});
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
log.error('Feed', `Feedcheck failed with error: ${err.message}`);
|
||||
log.verbose(err.stack);
|
||||
}
|
||||
|
||||
running = false;
|
||||
|
|
Loading…
Reference in a new issue