This commit is contained in:
Tomas Bures 2018-09-27 23:37:50 +02:00
parent 1448d9e914
commit bc818aaee2
11 changed files with 35 additions and 27 deletions

View file

@ -119,19 +119,18 @@ class SendControls extends Component {
state.setIn(['date', 'error'], null);
state.setIn(['time', 'error'], null);
if (!state.getIn(['sendLater', 'value'])) {
const dateValue = state.getIn(['date', 'value']);
if (state.getIn(['sendLater', 'value'])) {
const dateValue = state.getIn(['date', 'value']).trim();
if (!dateValue) {
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'));
}
const timeValue = state.getIn(['time', 'value']);
const time = moment.utc(timeValue, 'HH:mm').isValid();
const timeValue = state.getIn(['time', 'value']).trim();
if (!timeValue) {
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'));
}
}
@ -144,8 +143,8 @@ class SendControls extends Component {
const date = moment(entity.scheduled);
this.populateFormValues({
sendLater: true,
date: date.utc().format('YYYY-MM-DD'),
time: date.utc().format('HH:mm')
date: date.format('YYYY-MM-DD'),
time: date.format('HH:mm')
});
} else {
@ -176,15 +175,15 @@ class SendControls extends Component {
async scheduleAsync() {
if (this.isFormWithoutErrors()) {
const data = this.getFormValues();
const date = moment.utc(data.date);
const time = moment.utc(date.time);
const date = moment(data.date, 'YYYY-MM-DD');
const time = moment(data.time, 'HH:mm');
date.hour(time.hour());
date.minute(time.minute());
date.second(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 {
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)) {
const subscrInfo = entity.subscriptionsTotal === undefined ? '' : ` (${entity.subscriptionsTotal} ${t('subscribers')})`;
const subscrInfo = entity.subscriptionsTotal === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers')})`;
return (
<div>
@ -223,7 +222,7 @@ class SendControls extends Component {
</AlignedRow>
<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') &&
<div>
<DatePicker id="date" label={t('Date')} />
@ -254,13 +253,15 @@ class SendControls extends Component {
);
} else if (entity.status === CampaignStatus.FINISHED) {
const subscrInfo = entity.subscriptionsTotal === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers')})`;
return (
<div>
<AlignedRow label={t('Send status')}>
{t('All messages sent! Hit "Continue" if you you want to send this campaign to new subscribers.')}
</AlignedRow>
<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}/>
</ButtonRow>
</div>

View file

@ -20,7 +20,8 @@ export function getCampaignLabels(t) {
[CampaignStatus.FINISHED]: t('Finished'),
[CampaignStatus.PAUSED]: t('Paused'),
[CampaignStatus.INACTIVE]: t('Inactive'),
[CampaignStatus.ACTIVE]: t('Active')
[CampaignStatus.ACTIVE]: t('Active'),
[CampaignStatus.SENDING]: t('Sending')
};

View file

@ -226,7 +226,7 @@ async function _createTransport(sendConfiguration) {
transport.mailer = {
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)
};

View file

@ -1,6 +1,6 @@
'use strict';
const log = require('./log');
const log = require('npmlog');
const fields = require('../models/fields');
const settings = require('../models/settings');
const {getTrustedUrl} = require('./urls');
@ -128,7 +128,7 @@ async function _sendMail(list, email, template, subject, relativeUrls, subscript
type: 'mjml'
};
if (list.default_form !== null) {
if (list.default_form) {
const form = await forms.getById(contextHelpers.getAdminContext(), list.default_form);
text.template = form['mail_' + template + '_text'] || text.template;

View file

@ -40,7 +40,7 @@ async function getTemplate(template) {
}
if (template.type === 'mjml') {
const compiled = mjml.mjml2html(source);
const compiled = mjml(source);
if (compiled.errors.length) {
throw new Error(compiled.errors[0].message || compiled.errors[0]);

View file

@ -198,7 +198,7 @@ async function rawGetByTx(tx, key, id) {
.select([
'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.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`)
])
.first();
@ -682,6 +682,8 @@ async function _changeStatus(context, campaignId, permittedCurrentStates, newSta
throw new interoperableErrors.InvalidStateError(invalidStateMessage);
}
console.log(scheduled);
await tx('campaigns').where('id', campaignId).update({
status: newState,
scheduled
@ -693,7 +695,7 @@ async function _changeStatus(context, campaignId, permittedCurrentStates, newSta
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) {

View file

@ -96,6 +96,10 @@ fieldTypes.json = {
parsePostValue: (field, value) => value,
render: (field, value) => {
try {
if (value === null || value.trim() === '') {
return '';
}
let parsed = JSON.parse(value);
if (Array.isArray(parsed)) {
parsed = {
@ -224,7 +228,7 @@ fieldTypes['date'] = {
getHbsType: field => 'typeDate' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
forHbs: (field, value) => formatDate(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'] = {
@ -239,7 +243,7 @@ fieldTypes['birthday'] = {
getHbsType: field => 'typeBirthday' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
forHbs: (field, value) => formatBirthday(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);

View file

@ -217,7 +217,7 @@ function checkForMjmlErrors(form) {
let compiled;
try {
compiled = mjml.mjml2html(source);
compiled = mjml(source);
} catch (err) {
return err;
}

View file

@ -6,7 +6,7 @@ const { enforce } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers');
const entitySettings = require('../lib/entity-settings');
const interoperableErrors = require('../shared/interoperable-errors');
const log = require('../lib/log');
const log = require('npmlog');
const {getGlobalNamespaceId} = require('../shared/namespaces');
const {getAdminId} = require('../shared/users');

View file

@ -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) => {
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))));
});

View file

@ -505,7 +505,7 @@ router.getAsync('/:lcid/unsubscribe/:ucid', passport.csrfProtection, async (req,
const autoUnsubscribe = req.query.auto === 'yes';
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 ||
list.unsubscription_mode === lists.UnsubscriptionMode.ONE_STEP_WITH_FORM ||