Bugfixes
This commit is contained in:
parent
1448d9e914
commit
bc818aaee2
11 changed files with 35 additions and 27 deletions
|
@ -119,19 +119,18 @@ class SendControls extends Component {
|
||||||
state.setIn(['date', 'error'], null);
|
state.setIn(['date', 'error'], null);
|
||||||
state.setIn(['time', 'error'], null);
|
state.setIn(['time', 'error'], null);
|
||||||
|
|
||||||
if (!state.getIn(['sendLater', 'value'])) {
|
if (state.getIn(['sendLater', 'value'])) {
|
||||||
const dateValue = state.getIn(['date', 'value']);
|
const dateValue = state.getIn(['date', 'value']).trim();
|
||||||
if (!dateValue) {
|
if (!dateValue) {
|
||||||
state.setIn(['date', 'error'], t('Date must not be empty'));
|
state.setIn(['date', 'error'], t('Date must not be empty'));
|
||||||
} else if (!moment.utc(dateValue, 'YYYY-MM-DD').isValid()) {
|
} else if (!moment(dateValue, 'YYYY-MM-DD', true).isValid()) {
|
||||||
state.setIn(['date', 'error'], t('Date is invalid'));
|
state.setIn(['date', 'error'], t('Date is invalid'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeValue = state.getIn(['time', 'value']);
|
const timeValue = state.getIn(['time', 'value']).trim();
|
||||||
const time = moment.utc(timeValue, 'HH:mm').isValid();
|
|
||||||
if (!timeValue) {
|
if (!timeValue) {
|
||||||
state.setIn(['time', 'error'], t('Time must not be empty'));
|
state.setIn(['time', 'error'], t('Time must not be empty'));
|
||||||
} else if (!time) {
|
} else if (!moment(timeValue, 'HH:mm', true).isValid()) {
|
||||||
state.setIn(['time', 'error'], t('Time is invalid'));
|
state.setIn(['time', 'error'], t('Time is invalid'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,8 +143,8 @@ class SendControls extends Component {
|
||||||
const date = moment(entity.scheduled);
|
const date = moment(entity.scheduled);
|
||||||
this.populateFormValues({
|
this.populateFormValues({
|
||||||
sendLater: true,
|
sendLater: true,
|
||||||
date: date.utc().format('YYYY-MM-DD'),
|
date: date.format('YYYY-MM-DD'),
|
||||||
time: date.utc().format('HH:mm')
|
time: date.format('HH:mm')
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,15 +175,15 @@ class SendControls extends Component {
|
||||||
async scheduleAsync() {
|
async scheduleAsync() {
|
||||||
if (this.isFormWithoutErrors()) {
|
if (this.isFormWithoutErrors()) {
|
||||||
const data = this.getFormValues();
|
const data = this.getFormValues();
|
||||||
const date = moment.utc(data.date);
|
const date = moment(data.date, 'YYYY-MM-DD');
|
||||||
const time = moment.utc(date.time);
|
const time = moment(data.time, 'HH:mm');
|
||||||
|
|
||||||
date.hour(time.hour());
|
date.hour(time.hour());
|
||||||
date.minute(time.minute());
|
date.minute(time.minute());
|
||||||
date.second(0);
|
date.second(0);
|
||||||
date.millisecond(0);
|
date.millisecond(0);
|
||||||
|
|
||||||
await this.postAndMaskStateError(`rest/campaign-start-at/${this.props.entity.id}/${date.toDate()}`);
|
await this.postAndMaskStateError(`rest/campaign-start-at/${this.props.entity.id}/${date.valueOf()}`);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.showFormValidation();
|
this.showFormValidation();
|
||||||
|
@ -214,7 +213,7 @@ class SendControls extends Component {
|
||||||
|
|
||||||
if (entity.status === CampaignStatus.IDLE || entity.status === CampaignStatus.PAUSED || (entity.status === CampaignStatus.SCHEDULED && entity.scheduled)) {
|
if (entity.status === CampaignStatus.IDLE || entity.status === CampaignStatus.PAUSED || (entity.status === CampaignStatus.SCHEDULED && entity.scheduled)) {
|
||||||
|
|
||||||
const subscrInfo = entity.subscriptionsTotal === undefined ? '' : ` (${entity.subscriptionsTotal} ${t('subscribers')})`;
|
const subscrInfo = entity.subscriptionsTotal === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers')})`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -223,7 +222,7 @@ class SendControls extends Component {
|
||||||
</AlignedRow>
|
</AlignedRow>
|
||||||
|
|
||||||
<Form stateOwner={this}>
|
<Form stateOwner={this}>
|
||||||
<CheckBox id="sendLater" label={t('Send later')} text={t('Schedule deliver at particular date/time')}/>
|
<CheckBox id="sendLater" label={t('Send later')} text={t('Schedule delivery at a particular date/time')}/>
|
||||||
{this.getFormValue('sendLater') &&
|
{this.getFormValue('sendLater') &&
|
||||||
<div>
|
<div>
|
||||||
<DatePicker id="date" label={t('Date')} />
|
<DatePicker id="date" label={t('Date')} />
|
||||||
|
@ -254,13 +253,15 @@ class SendControls extends Component {
|
||||||
);
|
);
|
||||||
|
|
||||||
} else if (entity.status === CampaignStatus.FINISHED) {
|
} else if (entity.status === CampaignStatus.FINISHED) {
|
||||||
|
const subscrInfo = entity.subscriptionsTotal === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers')})`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AlignedRow label={t('Send status')}>
|
<AlignedRow label={t('Send status')}>
|
||||||
{t('All messages sent! Hit "Continue" if you you want to send this campaign to new subscribers.')}
|
{t('All messages sent! Hit "Continue" if you you want to send this campaign to new subscribers.')}
|
||||||
</AlignedRow>
|
</AlignedRow>
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button className="btn-primary" icon="play" label={t('Continue')} onClickAsync={::this.startAsync}/>
|
<Button className="btn-primary" icon="play" label={t('Continue') + subscrInfo} onClickAsync={::this.startAsync}/>
|
||||||
<Button className="btn-primary" icon="refresh" label={t('Reset')} onClickAsync={::this.resetAsync}/>
|
<Button className="btn-primary" icon="refresh" label={t('Reset')} onClickAsync={::this.resetAsync}/>
|
||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,7 +20,8 @@ export function getCampaignLabels(t) {
|
||||||
[CampaignStatus.FINISHED]: t('Finished'),
|
[CampaignStatus.FINISHED]: t('Finished'),
|
||||||
[CampaignStatus.PAUSED]: t('Paused'),
|
[CampaignStatus.PAUSED]: t('Paused'),
|
||||||
[CampaignStatus.INACTIVE]: t('Inactive'),
|
[CampaignStatus.INACTIVE]: t('Inactive'),
|
||||||
[CampaignStatus.ACTIVE]: t('Active')
|
[CampaignStatus.ACTIVE]: t('Active'),
|
||||||
|
[CampaignStatus.SENDING]: t('Sending')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ async function _createTransport(sendConfiguration) {
|
||||||
|
|
||||||
transport.mailer = {
|
transport.mailer = {
|
||||||
throttleWait: bluebird.promisify(throttleWait),
|
throttleWait: bluebird.promisify(throttleWait),
|
||||||
sendTransationalMail: async (mail, template) => await _sendTransactionalMail(transport, mail, template),
|
sendTransactionalMail: async (mail, template) => await _sendTransactionalMail(transport, mail, template),
|
||||||
sendMassMail: async (mail, template) => await _sendMail(transport, mail)
|
sendMassMail: async (mail, template) => await _sendMail(transport, mail)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const log = require('./log');
|
const log = require('npmlog');
|
||||||
const fields = require('../models/fields');
|
const fields = require('../models/fields');
|
||||||
const settings = require('../models/settings');
|
const settings = require('../models/settings');
|
||||||
const {getTrustedUrl} = require('./urls');
|
const {getTrustedUrl} = require('./urls');
|
||||||
|
@ -128,7 +128,7 @@ async function _sendMail(list, email, template, subject, relativeUrls, subscript
|
||||||
type: 'mjml'
|
type: 'mjml'
|
||||||
};
|
};
|
||||||
|
|
||||||
if (list.default_form !== null) {
|
if (list.default_form) {
|
||||||
const form = await forms.getById(contextHelpers.getAdminContext(), list.default_form);
|
const form = await forms.getById(contextHelpers.getAdminContext(), list.default_form);
|
||||||
|
|
||||||
text.template = form['mail_' + template + '_text'] || text.template;
|
text.template = form['mail_' + template + '_text'] || text.template;
|
||||||
|
|
|
@ -40,7 +40,7 @@ async function getTemplate(template) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (template.type === 'mjml') {
|
if (template.type === 'mjml') {
|
||||||
const compiled = mjml.mjml2html(source);
|
const compiled = mjml(source);
|
||||||
|
|
||||||
if (compiled.errors.length) {
|
if (compiled.errors.length) {
|
||||||
throw new Error(compiled.errors[0].message || compiled.errors[0]);
|
throw new Error(compiled.errors[0].message || compiled.errors[0]);
|
||||||
|
|
|
@ -198,7 +198,7 @@ async function rawGetByTx(tx, key, id) {
|
||||||
.select([
|
.select([
|
||||||
'campaigns.id', 'campaigns.cid', 'campaigns.name', 'campaigns.description', 'campaigns.namespace', 'campaigns.status', 'campaigns.type', 'campaigns.source',
|
'campaigns.id', 'campaigns.cid', 'campaigns.name', 'campaigns.description', 'campaigns.namespace', 'campaigns.status', 'campaigns.type', 'campaigns.source',
|
||||||
'campaigns.send_configuration', 'campaigns.from_name_override', 'campaigns.from_email_override', 'campaigns.reply_to_override', 'campaigns.subject_override',
|
'campaigns.send_configuration', 'campaigns.from_name_override', 'campaigns.from_email_override', 'campaigns.reply_to_override', 'campaigns.subject_override',
|
||||||
'campaigns.data', 'campaigns.click_tracking_disabled', 'campaigns.open_tracking_disabled', 'campaigns.unsubscribe_url',
|
'campaigns.data', 'campaigns.click_tracking_disabled', 'campaigns.open_tracking_disabled', 'campaigns.unsubscribe_url', 'campaigns.scheduled',
|
||||||
knex.raw(`GROUP_CONCAT(CONCAT_WS(\':\', campaign_lists.list, campaign_lists.segment) ORDER BY campaign_lists.id SEPARATOR \';\') as lists`)
|
knex.raw(`GROUP_CONCAT(CONCAT_WS(\':\', campaign_lists.list, campaign_lists.segment) ORDER BY campaign_lists.id SEPARATOR \';\') as lists`)
|
||||||
])
|
])
|
||||||
.first();
|
.first();
|
||||||
|
@ -682,6 +682,8 @@ async function _changeStatus(context, campaignId, permittedCurrentStates, newSta
|
||||||
throw new interoperableErrors.InvalidStateError(invalidStateMessage);
|
throw new interoperableErrors.InvalidStateError(invalidStateMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(scheduled);
|
||||||
|
|
||||||
await tx('campaigns').where('id', campaignId).update({
|
await tx('campaigns').where('id', campaignId).update({
|
||||||
status: newState,
|
status: newState,
|
||||||
scheduled
|
scheduled
|
||||||
|
@ -693,7 +695,7 @@ async function _changeStatus(context, campaignId, permittedCurrentStates, newSta
|
||||||
|
|
||||||
|
|
||||||
async function start(context, campaignId, startAt) {
|
async function start(context, campaignId, startAt) {
|
||||||
await _changeStatus(context, campaignId, [CampaignStatus.IDLE, CampaignStatus.PAUSED, CampaignStatus.FINISHED], CampaignStatus.SCHEDULED, 'Cannot start campaign until it is in IDLE or PAUSED state', startAt);
|
await _changeStatus(context, campaignId, [CampaignStatus.IDLE, CampaignStatus.SCHEDULED, CampaignStatus.PAUSED, CampaignStatus.FINISHED], CampaignStatus.SCHEDULED, 'Cannot start campaign until it is in IDLE or PAUSED state', startAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stop(context, campaignId) {
|
async function stop(context, campaignId) {
|
||||||
|
|
|
@ -96,6 +96,10 @@ fieldTypes.json = {
|
||||||
parsePostValue: (field, value) => value,
|
parsePostValue: (field, value) => value,
|
||||||
render: (field, value) => {
|
render: (field, value) => {
|
||||||
try {
|
try {
|
||||||
|
if (value === null || value.trim() === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
let parsed = JSON.parse(value);
|
let parsed = JSON.parse(value);
|
||||||
if (Array.isArray(parsed)) {
|
if (Array.isArray(parsed)) {
|
||||||
parsed = {
|
parsed = {
|
||||||
|
@ -224,7 +228,7 @@ fieldTypes['date'] = {
|
||||||
getHbsType: field => 'typeDate' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
|
getHbsType: field => 'typeDate' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
|
||||||
forHbs: (field, value) => formatDate(field.settings.dateFormat, value),
|
forHbs: (field, value) => formatDate(field.settings.dateFormat, value),
|
||||||
parsePostValue: (field, value) => parseDate(field.settings.dateFormat, value),
|
parsePostValue: (field, value) => parseDate(field.settings.dateFormat, value),
|
||||||
render: (field, value) => formatDate(field.settings.dateFormat, value)
|
render: (field, value) => value !== null && value.trim() !== '' ? formatDate(field.settings.dateFormat, value) : ''
|
||||||
};
|
};
|
||||||
|
|
||||||
fieldTypes['birthday'] = {
|
fieldTypes['birthday'] = {
|
||||||
|
@ -239,7 +243,7 @@ fieldTypes['birthday'] = {
|
||||||
getHbsType: field => 'typeBirthday' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
|
getHbsType: field => 'typeBirthday' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
|
||||||
forHbs: (field, value) => formatBirthday(field.settings.dateFormat, value),
|
forHbs: (field, value) => formatBirthday(field.settings.dateFormat, value),
|
||||||
parsePostValue: (field, value) => parseBirthday(field.settings.dateFormat, value),
|
parsePostValue: (field, value) => parseBirthday(field.settings.dateFormat, value),
|
||||||
render: (field, value) => formatBirthday(field.settings.dateFormat, value)
|
render: (field, value) => value !== null && value.trim() !== '' ? formatBirthday(field.settings.dateFormat, value) : ''
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupedTypes = Object.keys(fieldTypes).filter(key => fieldTypes[key].grouped);
|
const groupedTypes = Object.keys(fieldTypes).filter(key => fieldTypes[key].grouped);
|
||||||
|
|
|
@ -217,7 +217,7 @@ function checkForMjmlErrors(form) {
|
||||||
let compiled;
|
let compiled;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
compiled = mjml.mjml2html(source);
|
compiled = mjml(source);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ const { enforce } = require('../lib/helpers');
|
||||||
const dtHelpers = require('../lib/dt-helpers');
|
const dtHelpers = require('../lib/dt-helpers');
|
||||||
const entitySettings = require('../lib/entity-settings');
|
const entitySettings = require('../lib/entity-settings');
|
||||||
const interoperableErrors = require('../shared/interoperable-errors');
|
const interoperableErrors = require('../shared/interoperable-errors');
|
||||||
const log = require('../lib/log');
|
const log = require('npmlog');
|
||||||
const {getGlobalNamespaceId} = require('../shared/namespaces');
|
const {getGlobalNamespaceId} = require('../shared/namespaces');
|
||||||
const {getAdminId} = require('../shared/users');
|
const {getAdminId} = require('../shared/users');
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ router.postAsync('/campaign-start/:campaignId', passport.loggedIn, passport.csrf
|
||||||
});
|
});
|
||||||
|
|
||||||
router.postAsync('/campaign-start-at/:campaignId/:dateTime', passport.loggedIn, passport.csrfProtection, async (req, res) => {
|
router.postAsync('/campaign-start-at/:campaignId/:dateTime', passport.loggedIn, passport.csrfProtection, async (req, res) => {
|
||||||
return res.json(await campaigns.start(req.context, req.params.campaignId, new Date(req.params.dateTime)));
|
return res.json(await campaigns.start(req.context, req.params.campaignId, new Date(Number.parseInt(req.params.dateTime))));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -505,7 +505,7 @@ router.getAsync('/:lcid/unsubscribe/:ucid', passport.csrfProtection, async (req,
|
||||||
const autoUnsubscribe = req.query.auto === 'yes';
|
const autoUnsubscribe = req.query.auto === 'yes';
|
||||||
|
|
||||||
if (autoUnsubscribe) {
|
if (autoUnsubscribe) {
|
||||||
await handleUnsubscribe(list, req.params.ucid, autoUnsubscribe, req.query.c, req.ip, res, next);
|
await handleUnsubscribe(list, req.params.ucid, autoUnsubscribe, req.query.c, req.ip, res);
|
||||||
|
|
||||||
} else if (req.query.formTest ||
|
} else if (req.query.formTest ||
|
||||||
list.unsubscription_mode === lists.UnsubscriptionMode.ONE_STEP_WITH_FORM ||
|
list.unsubscription_mode === lists.UnsubscriptionMode.ONE_STEP_WITH_FORM ||
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue