Work in progress on introducing tag language. Not tested yet.

This commit is contained in:
Tomas Bures 2019-07-03 11:58:58 +02:00
parent 450b930cc5
commit 00e328a914
21 changed files with 2154 additions and 1909 deletions

View file

@ -36,6 +36,11 @@ editors:
- ckeditor4
- codeeditor
# Enabled tag languages
tagLanguages:
- simple # e.g. [FIRST_NAME] - this the style of merge tags found in Mailtrain v1
- hbs # e.g. {{#if FIRST_NAME}}Hello {{firstName}}!{{else}}Hello!{{/if}} - this syntax uses Handlebars templating language (http://handlebarsjs.com)
# Default language to use
defaultLanguage: en-US

View file

@ -44,6 +44,7 @@ async function getAuthenticatedConfig(context) {
},
globalPermissions,
editors: config.editors,
tagLanguages: config.tagLanguages,
mosaico: config.mosaico,
verpEnabled: config.verp.enabled,
reportsEnabled: config.reports.enabled,

View file

@ -10,6 +10,7 @@ const shares = require('./shares');
const namespaceHelpers = require('../lib/namespace-helpers');
const files = require('./files');
const templates = require('./templates');
const { allTagLanguages } = require('../../shared/templates');
const { CampaignStatus, CampaignSource, CampaignType, getSendConfigurationPermissionRequiredForSend } = require('../../shared/campaigns');
const sendConfigurations = require('./send-configurations');
const triggers = require('./triggers');
@ -445,6 +446,10 @@ async function _validateAndPreprocess(tx, context, entity, isCreate, content) {
await shares.enforceEntityPermissionTx(tx, context, 'sendConfiguration', entity.send_configuration, 'viewPublic');
}
if ((isCreate && entity.source === CampaignSource.CUSTOM) || (content === Content.ONLY_SOURCE_CUSTOM)) {
enforce(allTagLanguages.includes(entity.data.sourceCustom.tag_language), `Invalid tag language '${entity.data.sourceCustom.tag_language}'`);
}
}
async function _createTx(tx, context, entity, content) {
@ -462,6 +467,7 @@ async function _createTx(tx, context, entity, content) {
entity.data.sourceCustom = {
type: template.type,
tag_language: template.tag_language,
data: template.data,
html: template.html,
text: template.text

View file

@ -9,8 +9,9 @@ const namespaceHelpers = require('../lib/namespace-helpers');
const shares = require('./shares');
const files = require('./files');
const dependencyHelpers = require('../lib/dependency-helpers');
const { allTagLanguages } = require('../../shared/templates');
const allowedKeys = new Set(['name', 'description', 'type', 'data', 'namespace']);
const allowedKeys = new Set(['name', 'description', 'type', 'tag_language', 'data', 'namespace']);
function hash(entity) {
return hasher.hash(filterObject(entity, allowedKeys));
@ -32,11 +33,25 @@ async function listDTAjax(context, params) {
[{ entityTypeId: 'mosaicoTemplate', requiredOperations: ['view'] }],
params,
builder => builder.from('mosaico_templates').innerJoin('namespaces', 'namespaces.id', 'mosaico_templates.namespace'),
[ 'mosaico_templates.id', 'mosaico_templates.name', 'mosaico_templates.description', 'mosaico_templates.type', 'mosaico_templates.created', 'namespaces.name' ]
[ 'mosaico_templates.id', 'mosaico_templates.name', 'mosaico_templates.description', 'mosaico_templates.type', 'mosaico_templates.tag_language', 'mosaico_templates.created', 'namespaces.name' ]
);
}
async function listByTagLanguageDTAjax(context, tagLanguage, params) {
return await dtHelpers.ajaxListWithPermissions(
context,
[{ entityTypeId: 'mosaicoTemplate', requiredOperations: ['view'] }],
params,
builder => builder.from('mosaico_templates')
.innerJoin('namespaces', 'namespaces.id', 'mosaico_templates.namespace')
.where('mosaico_templates.tag_language', tagLanguage),
[ 'mosaico_templates.id', 'mosaico_templates.name', 'mosaico_templates.description', 'mosaico_templates.type', 'mosaico_templates.tag_language', 'mosaico_templates.created', 'namespaces.name' ]
);
}
async function _validateAndPreprocess(tx, entity) {
enforce(allTagLanguages.includes(entity.tag_language), `Invalid tag language '${entity.tag_language}'`);
entity.data = JSON.stringify(entity.data);
await namespaceHelpers.validateEntity(tx, entity);
}
@ -119,6 +134,7 @@ async function remove(context, id) {
module.exports.hash = hash;
module.exports.getById = getById;
module.exports.listDTAjax = listDTAjax;
module.exports.listByTagLanguageDTAjax = listByTagLanguageDTAjax;
module.exports.create = create;
module.exports.updateWithConsistencyCheck = updateWithConsistencyCheck;
module.exports.remove = remove;

View file

@ -14,11 +14,11 @@ const {convertFileURLs} = require('../lib/campaign-content');
const mailers = require('../lib/mailers');
const tools = require('../lib/tools');
const sendConfigurations = require('./send-configurations');
const { getMergeTagsForBases } = require('../../shared/templates');
const { getMergeTagsForBases, allTagLanguages } = require('../../shared/templates');
const { getTrustedUrl, getSandboxUrl, getPublicUrl } = require('../lib/urls');
const htmlToText = require('html-to-text');
const allowedKeys = new Set(['name', 'description', 'type', 'data', 'html', 'text', 'namespace']);
const allowedKeys = new Set(['name', 'description', 'type', 'tag_language', 'data', 'html', 'text', 'namespace']);
function hash(entity) {
return hasher.hash(filterObject(entity, allowedKeys));
@ -54,7 +54,7 @@ async function _listDTAjax(context, namespaceId, params) {
}
return builder;
},
[ 'templates.id', 'templates.name', 'templates.description', 'templates.type', 'templates.created', 'namespaces.name' ]
[ 'templates.id', 'templates.name', 'templates.description', 'templates.type', 'templates.tag_language', 'templates.created', 'namespaces.name' ]
);
}
@ -69,6 +69,8 @@ async function listByNamespaceDTAjax(context, namespaceId, params) {
async function _validateAndPreprocess(tx, entity) {
await namespaceHelpers.validateEntity(tx, entity);
enforce(allTagLanguages.includes(entity.tag_language), `Invalid tag language '${entity.tag_language}'`);
// We don't check contents of the "data" because it is processed solely on the client. The client generates the HTML code we use when sending out campaigns.
entity.data = JSON.stringify(entity.data);
@ -82,6 +84,7 @@ async function create(context, entity) {
const template = await getByIdTx(tx, context, entity.sourceTemplate, false);
entity.type = template.type;
entity.tag_language = template.tag_language;
entity.data = template.data;
entity.html = template.html;
entity.text = template.text;

View file

@ -33,4 +33,9 @@ router.postAsync('/mosaico-templates-table', passport.loggedIn, async (req, res)
return res.json(await mosaicoTemplates.listDTAjax(req.context, req.body));
});
router.postAsync('/mosaico-templates-by-tag-language-table/:tagLanguage', passport.loggedIn, async (req, res) => {
return res.json(await mosaicoTemplates.listByTagLanguageDTAjax(req.context, req.params.tagLanguage, req.body));
});
module.exports = router;

View file

@ -2,6 +2,7 @@ const { CampaignSource, CampaignType} = require('../../../../shared/campaigns');
const files = require('../../../models/files');
const contextHelpers = require('../../../lib/context-helpers');
const mosaicoTemplates = require('../../../../shared/mosaico-templates');
const {TagLanguages} = require('../../../../shared/templates');
const {getGlobalNamespaceId} = require('../../../../shared/namespaces');
const {getAdminId} = require('../../../../shared/users');
const { MailerType, ZoneMTAType, getSystemSendConfigurationId, getSystemSendConfigurationCid } = require('../../../../shared/send-configurations');
@ -905,7 +906,7 @@ async function addMosaicoTemplates(knex) {
type: 'html',
namespace: 1,
data: JSON.stringify({
html: mosaicoTemplates.getVersafix()
html: mosaicoTemplates.getVersafix(TagLanguages.SIMPLE)
})
};

View file

@ -7,7 +7,7 @@ exports.up = (knex, Promise) => (async() => {
data.listId = queuedEntry.list;
data.subscriptionId = queuedEntry.subscription;
knex('queued')
await knex('queued')
.where('id', queuedEntry.id)
.update({
data: JSON.stringify(data)

View file

@ -0,0 +1,41 @@
const { CampaignSource } = require('../../../../shared/campaigns');
const { TagLanguages } = require('../../../../shared/templates');
exports.up = (knex, Promise) => (async() => {
await knex.schema.table('templates', table => {
table.string('tag_language', 48);
});
await knex('templates').update({
tag_language: 'simple'
});
await knex.schema.table('templates', table => {
table.string('tag_language', 48).notNullable().index().alter();
});
await knex.schema.table('mosaico_templates', table => {
table.string('tag_language', 48);
});
await knex('mosaico_templates').update({
tag_language: TagLanguages.SIMPLE
});
await knex.schema.table('mosaico_templates', table => {
table.string('tag_language', 48).notNullable().index().alter();
});
const rows = await knex('campaigns').whereIn('source', [CampaignSource.CUSTOM, CampaignSource.CUSTOM_FROM_CAMPAIGN, CampaignSource.CUSTOM_FROM_TEMPLATE]);
for (const row of rows) {
const data = JSON.parse(row.data);
data.sourceCustom.tag_language = TagLanguages.SIMPLE;
await knex('campaigns').where('id', row.id).update({data: JSON.stringify(data)});
}
})();
exports.down = (knex, Promise) => (async() => {
})();