Fixes of bugs caused by the public endpoint.
This commit is contained in:
parent
efbfa2b366
commit
213039c141
10 changed files with 79 additions and 52 deletions
6
TODO.md
6
TODO.md
|
@ -1,15 +1,15 @@
|
|||
### Front page
|
||||
- Some dashboard
|
||||
|
||||
### Deletion
|
||||
- Check/delete dependencies
|
||||
|
||||
### Templates
|
||||
- Add MJML template editor
|
||||
- Include GrapeJS with MJML support
|
||||
- CKEditor to sandbox
|
||||
- Add Files support to CKEditor
|
||||
|
||||
### Message delivery
|
||||
- Better integration with ZoneMTA to allow multiple send configurations (with different DKIM) against one ZoneMTA instance via different HTTP configuration of ZoneMTA. This may need an extension of ZoneMTA to provide some header entry that identifies the campaign.
|
||||
|
||||
### Campaigns
|
||||
- Statistics for a sent campaign
|
||||
- List of sent RSS campaigns (?)
|
||||
|
|
|
@ -218,13 +218,12 @@ function createApp(appType) {
|
|||
useWith404Fallback('/subscription', subscription);
|
||||
useWith404Fallback('/links', links);
|
||||
useWith404Fallback('/archive', archive);
|
||||
useWith404Fallback('/files', files);
|
||||
}
|
||||
|
||||
if (appType === AppType.TRUSTED || appType === AppType.SANDBOXED) {
|
||||
// Regular endpoints
|
||||
useWith404Fallback('/files', files);
|
||||
useWith404Fallback('/mosaico', mosaico.getRouter(appType));
|
||||
useWith404Fallback('/mosaico', mosaico.getRouter(appType));
|
||||
|
||||
if (appType === AppType.TRUSTED || appType === AppType.SANDBOXED) {
|
||||
if (config.reports && config.reports.enabled === true) {
|
||||
useWith404Fallback('/reports', reports);
|
||||
}
|
||||
|
@ -266,7 +265,7 @@ function createApp(appType) {
|
|||
app.use('/', index.getRouter(appType));
|
||||
|
||||
// Error handlers
|
||||
if (app.get('env') === 'development') {
|
||||
if (app.get('env') === 'development' || app.get('env') === 'test') {
|
||||
// development error handler
|
||||
// will print stacktrace
|
||||
app.use((err, req, res, next) => {
|
||||
|
|
|
@ -8,6 +8,7 @@ import styles from "./mosaico.scss";
|
|||
import {UntrustedContentHost, parentRPC} from './untrusted';
|
||||
import {Icon} from "./bootstrap-components";
|
||||
import {
|
||||
getPublicUrl,
|
||||
getSandboxUrl,
|
||||
getTrustedUrl
|
||||
} from "./urls";
|
||||
|
@ -105,12 +106,13 @@ export class MosaicoSandbox extends Component {
|
|||
}
|
||||
|
||||
async exportState(method, params) {
|
||||
const sandboxUrlBase = getSandboxUrl();
|
||||
const trustedUrlBase = getTrustedUrl();
|
||||
const sandboxUrlBase = getSandboxUrl();
|
||||
const publicUrlBase = getPublicUrl();
|
||||
return {
|
||||
html: unbase(this.viewModel.exportHTML(), trustedUrlBase, sandboxUrlBase, true),
|
||||
model: unbase(this.viewModel.exportJSON(), trustedUrlBase, sandboxUrlBase),
|
||||
metadata: unbase(this.viewModel.exportMetadata(), trustedUrlBase, sandboxUrlBase)
|
||||
html: unbase(this.viewModel.exportHTML(), trustedUrlBase, sandboxUrlBase, publicUrlBase, true),
|
||||
model: unbase(this.viewModel.exportJSON(), trustedUrlBase, sandboxUrlBase, publicUrlBase),
|
||||
metadata: unbase(this.viewModel.exportMetadata(), trustedUrlBase, sandboxUrlBase, publicUrlBase)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -155,10 +157,11 @@ export class MosaicoSandbox extends Component {
|
|||
strings: window.mosaicoLanguageStrings
|
||||
};
|
||||
|
||||
const sandboxUrlBase = getSandboxUrl();
|
||||
const trustedUrlBase = getTrustedUrl();
|
||||
const metadata = this.props.initialMetadata && JSON.parse(base(this.props.initialMetadata, trustedUrlBase, sandboxUrlBase));
|
||||
const model = this.props.initialModel && JSON.parse(base(this.props.initialModel, trustedUrlBase, sandboxUrlBase));
|
||||
const sandboxUrlBase = getSandboxUrl();
|
||||
const publicUrlBase = getPublicUrl();
|
||||
const metadata = this.props.initialMetadata && JSON.parse(base(this.props.initialMetadata, trustedUrlBase, sandboxUrlBase, publicUrlBase));
|
||||
const model = this.props.initialModel && JSON.parse(base(this.props.initialModel, trustedUrlBase, sandboxUrlBase, publicUrlBase));
|
||||
const template = this.props.templateId ? getSandboxUrl(`mosaico/templates/${this.props.templateId}/index.html`) : this.props.templatePath;
|
||||
|
||||
const allPlugins = plugins.concat(window.mosaicoPlugins);
|
||||
|
|
|
@ -51,7 +51,7 @@ class CampaignSender {
|
|||
}
|
||||
|
||||
if (campaign.source === CampaignSource.TEMPLATE) {
|
||||
this.template = templates.getByIdTx(tx, contextHelpers.getAdminContext(), this.campaign.data.sourceTemplate, false);
|
||||
this.template = await templates.getByIdTx(tx, contextHelpers.getAdminContext(), this.campaign.data.sourceTemplate, false);
|
||||
}
|
||||
|
||||
const attachments = await files.listTx(tx, contextHelpers.getAdminContext(), 'campaign', 'attachment', this.campaign.id);
|
||||
|
@ -111,7 +111,7 @@ class CampaignSender {
|
|||
if (replaceDataImgs) {
|
||||
// replace data: images with embedded attachments
|
||||
html = html.replace(/(<img\b[^>]* src\s*=[\s"']*)(data:[^"'>\s]+)/gi, (match, prefix, dataUri) => {
|
||||
let cid = shortid.generate() + '-attachments@' + campaign.address.split('@').pop();
|
||||
const cid = shortid.generate() + '-attachments@' + campaign.address.split('@').pop();
|
||||
attachments.push({
|
||||
path: dataUri,
|
||||
cid
|
||||
|
|
|
@ -14,6 +14,8 @@ const { formatDate, formatBirthday, parseDate, parseBirthday } = require('../sha
|
|||
const { getFieldColumn } = require('../shared/lists');
|
||||
const { cleanupFromPost } = require('../lib/helpers');
|
||||
const Handlebars = require('handlebars');
|
||||
const { getTrustedUrl, getSandboxUrl, getPublicUrl } = require('../lib/urls');
|
||||
const { getMergeTagsForBases } = require('../shared/templates');
|
||||
|
||||
|
||||
const allowedKeysCreate = new Set(['name', 'key', 'default_value', 'type', 'group', 'settings']);
|
||||
|
@ -228,7 +230,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) => value !== null && value.trim() !== '' ? formatDate(field.settings.dateFormat, value) : ''
|
||||
render: (field, value) => value !== null ? formatDate(field.settings.dateFormat, value) : ''
|
||||
};
|
||||
|
||||
fieldTypes['birthday'] = {
|
||||
|
@ -243,7 +245,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) => value !== null && value.trim() !== '' ? formatBirthday(field.settings.dateFormat, value) : ''
|
||||
render: (field, value) => value !== null ? formatBirthday(field.settings.dateFormat, value) : ''
|
||||
};
|
||||
|
||||
const groupedTypes = Object.keys(fieldTypes).filter(key => fieldTypes[key].grouped);
|
||||
|
@ -694,7 +696,8 @@ async function forHbs(context, listId, subscription) { // assumes grouped subscr
|
|||
|
||||
function getMergeTags(fieldsGrouped, subscription) { // assumes grouped subscription
|
||||
const mergeTags = {
|
||||
'EMAIL': subscription.email
|
||||
'EMAIL': subscription.email,
|
||||
...getMergeTagsForBases(getTrustedUrl(), getSandboxUrl(), getPublicUrl())
|
||||
};
|
||||
|
||||
for (const fld of fieldsGrouped) {
|
||||
|
|
|
@ -8,7 +8,7 @@ const fs = require('fs-extra-promise');
|
|||
const path = require('path');
|
||||
const interoperableErrors = require('../shared/interoperable-errors');
|
||||
const entitySettings = require('../lib/entity-settings');
|
||||
const {getTrustedUrl} = require('../lib/urls');
|
||||
const {getPublicUrl} = require('../lib/urls');
|
||||
|
||||
const crypto = require('crypto');
|
||||
const bluebird = require('bluebird');
|
||||
|
@ -29,7 +29,7 @@ function getFilePath(type, subType, entityId, filename) {
|
|||
}
|
||||
|
||||
function getFileUrl(context, type, subType, entityId, filename) {
|
||||
return getTrustedUrl(`files/${type}/${subType}/${entityId}/${filename}`, context)
|
||||
return getPublicUrl(`files/${type}/${subType}/${entityId}/${filename}`, context)
|
||||
}
|
||||
|
||||
function getFilesTable(type, subType) {
|
||||
|
@ -109,7 +109,7 @@ async function getFileByFilename(context, type, subType, entityId, name) {
|
|||
}
|
||||
|
||||
async function getFileByUrl(context, url) {
|
||||
const urlPrefix = getTrustedUrl('files/', context);
|
||||
const urlPrefix = getPublicUrl('files/', context);
|
||||
if (url.startsWith(urlPrefix)) {
|
||||
const path = url.substring(urlPrefix.length);
|
||||
const pathElem = path.split('/');
|
||||
|
|
|
@ -15,16 +15,14 @@ router.get('/:campaign/:list/:subscription', (req, res, next) => {
|
|||
res.render('partials/tracking-scripts', {
|
||||
layout: 'archive/layout-raw'
|
||||
}, (err, scripts) => {
|
||||
console.log(scripts);
|
||||
console.log(err);
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
html = scripts ? html.replace(/<\/body\b/i, match => scripts + match) : html;
|
||||
const htmlWithScripts = scripts ? html.replace(/<\/body\b/i, match => scripts + match) : html;
|
||||
|
||||
res.render('archive/view', {
|
||||
layout: 'archive/layout-raw',
|
||||
message: html
|
||||
message: htmlWithScripts
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ const mosaicoTemplates = require('../models/mosaico-templates');
|
|||
const contextHelpers = require('../lib/context-helpers');
|
||||
const interoperableErrors = require('../shared/interoperable-errors');
|
||||
|
||||
const { getTrustedUrl, getSandboxUrl } = require('../lib/urls');
|
||||
const { getTrustedUrl, getSandboxUrl, getPublicUrl } = require('../lib/urls');
|
||||
const { base } = require('../shared/templates');
|
||||
const { AppType } = require('../shared/app');
|
||||
|
||||
|
@ -134,7 +134,7 @@ function getRouter(appType) {
|
|||
const tmpl = await mosaicoTemplates.getById(req.context, castToInteger(req.params.mosaicoTemplateId));
|
||||
|
||||
res.set('Content-Type', 'text/html');
|
||||
res.send(base(tmpl.data.html, getTrustedUrl(), getSandboxUrl('', req.context)));
|
||||
res.send(base(tmpl.data.html, getTrustedUrl(), getSandboxUrl('', req.context), getPublicUrl()));
|
||||
});
|
||||
|
||||
// Mosaico looks for block thumbnails in edres folder relative to index.html of the template. We respond to such requests here.
|
||||
|
@ -153,7 +153,7 @@ function getRouter(appType) {
|
|||
});
|
||||
|
||||
// This is a fallback to versafix-1 if the block thumbnail is not defined by the template
|
||||
router.use('/templates/:mosaicoTemplateId/edres', express.static(path.join(__dirname, '..', 'client', 'public', 'mosaico', 'templates', 'versafix-1', 'edres')));
|
||||
router.use('/templates/:mosaicoTemplateId/edres', express.static(path.join(__dirname, '..', 'client', 'static', 'mosaico', 'templates', 'versafix-1', 'edres')));
|
||||
|
||||
|
||||
fileHelpers.installUploadHandler(router, '/upload/:type/:entityId', files.ReplacementBehavior.RENAME, null, 'file');
|
||||
|
@ -185,7 +185,7 @@ function getRouter(appType) {
|
|||
if (config.language && config.language !== 'en') {
|
||||
const lang = config.language.split('_')[0];
|
||||
try {
|
||||
const file = path.join(__dirname, '..', 'client', 'public', 'mosaico', 'lang', 'mosaico-' + lang + '.json');
|
||||
const file = path.join(__dirname, '..', 'client', 'static', 'mosaico', 'lang', 'mosaico-' + lang + '.json');
|
||||
languageStrings = await fsReadFile(file, 'utf8');
|
||||
} catch (err) {
|
||||
}
|
||||
|
@ -205,7 +205,8 @@ function getRouter(appType) {
|
|||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
} else if (appType === AppType.TRUSTED || appType === AppType.PUBLIC) { // Mosaico editor loads the images from TRUSTED endpoint. This is hard to change because the index.html has to come from TRUSTED.
|
||||
// So we serve /mosaico/img under both endpoints. There is no harm in it.
|
||||
router.getAsync('/img', async (req, res) => {
|
||||
const method = req.query.method;
|
||||
const params = req.query.params;
|
||||
|
@ -214,6 +215,7 @@ function getRouter(appType) {
|
|||
|
||||
|
||||
// FIXME - cache the generated files !!!
|
||||
|
||||
if (method === 'placeholder') {
|
||||
width = sanitizeSize(width, 1, 2048, 600, false);
|
||||
height = sanitizeSize(height, 1, 2048, 300, false);
|
||||
|
@ -228,7 +230,7 @@ function getRouter(appType) {
|
|||
|
||||
const mosaicoLegacyUrlPrefix = getTrustedUrl(`mosaico/uploads/`);
|
||||
if (url.startsWith(mosaicoLegacyUrlPrefix)) {
|
||||
filePath = path.join(__dirname, '..', 'client', 'public' , 'mosaico', 'uploads', url.substring(mosaicoLegacyUrlPrefix.length));
|
||||
filePath = path.join(__dirname, '..', 'client', 'static' , 'mosaico', 'uploads', url.substring(mosaicoLegacyUrlPrefix.length));
|
||||
} else {
|
||||
const file = await files.getFileByUrl(contextHelpers.getAdminContext(), url);
|
||||
filePath = file.path;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
function base(text, trustedBaseUrl, sandboxBaseUrl) {
|
||||
function _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl) {
|
||||
if (trustedBaseUrl.endsWith('/')) {
|
||||
trustedBaseUrl = trustedBaseUrl.substring(0, trustedBaseUrl.length - 1);
|
||||
}
|
||||
|
@ -9,32 +9,54 @@ function base(text, trustedBaseUrl, sandboxBaseUrl) {
|
|||
sandboxBaseUrl = sandboxBaseUrl.substring(0, sandboxBaseUrl.length - 1);
|
||||
}
|
||||
|
||||
text = text.split('[URL_BASE]').join(trustedBaseUrl);
|
||||
text = text.split('[SANDBOX_URL_BASE]').join(sandboxBaseUrl);
|
||||
text = text.split('[ENCODED_URL_BASE]').join(encodeURIComponent(trustedBaseUrl));
|
||||
text = text.split('[ENCODED_SANDBOX_URL_BASE]').join(encodeURIComponent(sandboxBaseUrl));
|
||||
if (publicBaseUrl.endsWith('/')) {
|
||||
publicBaseUrl = publicBaseUrl.substring(0, publicBaseUrl.length - 1);
|
||||
}
|
||||
|
||||
return {trustedBaseUrl, sandboxBaseUrl, publicBaseUrl};
|
||||
}
|
||||
|
||||
function getMergeTagsForBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl) {
|
||||
const bases = _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl);
|
||||
|
||||
return {
|
||||
URL_BASE: bases.publicBaseUrl,
|
||||
TRUSTED_URL_BASE: bases.trustedBaseUrl,
|
||||
SANDBOX_URL_BASE: bases.sandboxBaseUrl,
|
||||
ENCODED_URL_BASE: encodeURIComponent(bases.publicBaseUrl),
|
||||
ENCODED_TRUSTED_URL_BASE: encodeURIComponent(bases.trustedBaseUrl),
|
||||
ENCODED_SANDBOX_URL_BASE: encodeURIComponent(bases.sandboxBaseUrl)
|
||||
};
|
||||
}
|
||||
|
||||
function base(text, trustedBaseUrl, sandboxBaseUrl, publicBaseUrl) {
|
||||
const bases = _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl);
|
||||
|
||||
text = text.split('[URL_BASE]').join(bases.publicBaseUrl);
|
||||
text = text.split('[TRUSTED_URL_BASE]').join(bases.trustedBaseUrl);
|
||||
text = text.split('[SANDBOX_URL_BASE]').join(bases.sandboxBaseUrl);
|
||||
text = text.split('[ENCODED_URL_BASE]').join(encodeURIComponent(bases.publicBaseUrl));
|
||||
text = text.split('[ENCODED_TRUSTED_URL_BASE]').join(encodeURIComponent(bases.trustedBaseUrl));
|
||||
text = text.split('[ENCODED_SANDBOX_URL_BASE]').join(encodeURIComponent(bases.sandboxBaseUrl));
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function unbase(text, trustedBaseUrl, sandboxBaseUrl, treatSandboxAsTrusted = false) {
|
||||
if (trustedBaseUrl.endsWith('/')) {
|
||||
trustedBaseUrl = trustedBaseUrl.substring(0, trustedBaseUrl.length - 1);
|
||||
}
|
||||
function unbase(text, trustedBaseUrl, sandboxBaseUrl, publicBaseUrl, treatAllAsPublic = false) {
|
||||
const bases = _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl);
|
||||
|
||||
if (sandboxBaseUrl.endsWith('/')) {
|
||||
sandboxBaseUrl = sandboxBaseUrl.substring(0, sandboxBaseUrl.length - 1);
|
||||
}
|
||||
|
||||
text = text.split(trustedBaseUrl).join('[URL_BASE]');
|
||||
text = text.split(sandboxBaseUrl).join(treatSandboxAsTrusted ? '[URL_BASE]' : '[SANDBOX_URL_BASE]');
|
||||
text = text.split(encodeURIComponent(trustedBaseUrl)).join('[ENCODED_URL_BASE]');
|
||||
text = text.split(encodeURIComponent(sandboxBaseUrl)).join(treatSandboxAsTrusted ? '[ENCODED_URL_BASE]' : '[ENCODED_SANDBOX_URL_BASE]');
|
||||
text = text.split(bases.publicBaseUrl).join('[URL_BASE]');
|
||||
text = text.split(bases.trustedBaseUrl).join(treatAllAsPublic ? '[URL_BASE]' : '[TRUSTED_URL_BASE]');
|
||||
text = text.split(bases.sandboxBaseUrl).join(treatAllAsPublic ? '[URL_BASE]' : '[SANDBOX_URL_BASE]');
|
||||
text = text.split(encodeURIComponent(bases.publicBaseUrl)).join('[ENCODED_URL_BASE]');
|
||||
text = text.split(encodeURIComponent(bases.trustedBaseUrl)).join(treatAllAsPublic ? '[ENCODED_URL_BASE]' : '[ENCODED_TRUSTED_URL_BASE]');
|
||||
text = text.split(encodeURIComponent(bases.sandboxBaseUrl)).join(treatAllAsPublic ? '[ENCODED_URL_BASE]' : '[ENCODED_SANDBOX_URL_BASE]');
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
base,
|
||||
unbase
|
||||
unbase,
|
||||
getMergeTagsForBases
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const anonymousRestrictedAccessToken = 'public';
|
||||
const anonymousRestrictedAccessToken = 'anonymous';
|
||||
|
||||
module.exports = {
|
||||
anonymousRestrictedAccessToken
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue