diff --git a/README.md b/README.md index 9e8cfa17..973ff4a7 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,7 @@ variables (e.g. `URL_BASE_TRUSTED=https://mailtrain.domain.com (and more env-var | CAS_MAILTAG | The field used to save the email (default: mail) | | CAS_NEWUSERROLE | The role of new users (default: nobody) | | CAS_NEWUSERNAMESPACEID | The namespace id of new users (default: 1) | +| LOG_LEVEL | sets log level among `silly|verbose|info|http|warn|error|silent` (default: `info`) | If you don't want to modify the original `docker-compose.yml`, you can put your overrides to another file (e.g. `docker-compose.override.yml`) -- like the one below. diff --git a/client/src/campaigns/CUD.js b/client/src/campaigns/CUD.js index 6afaf2ca..666025ac 100644 --- a/client/src/campaigns/CUD.js +++ b/client/src/campaigns/CUD.js @@ -327,7 +327,7 @@ export default class CUD extends Component { data.source = channel.source; if (channel.source === CampaignSource.CUSTOM_FROM_TEMPLATE) { - data.data_sourceTemplate = channel.sourceTemplate; + data.data_sourceTemplate = channel.data.sourceTemplate; } else if (channel.source === CampaignSource.CUSTOM_FROM_CAMPAIGN) { data.data_sourceCampaign = channel.data.sourceCampaign; diff --git a/client/src/templates/helpers.js b/client/src/templates/helpers.js index 1b2e335d..de53ed33 100644 --- a/client/src/templates/helpers.js +++ b/client/src/templates/helpers.js @@ -700,7 +700,7 @@ export function getEditForm(owner, typeKey, prefix = '') { height="400px" mode="text" label={t('templateContentPlainText')} - help={To extract the text from HTML click here. Please note that your existing plaintext in the field above will be overwritten. This feature uses the Premailer API, a third party service. Their Terms of Service and Privacy Policy apply.} + help={To extract the text from HTML click here. Please note that your existing plaintext in the field above will be overwritten.} /> ); diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index d1c55ea2..24bd4255 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -41,6 +41,7 @@ MYSQL_USER=${MYSQL_USER:-'mailtrain'} MYSQL_PASSWORD=${MYSQL_PASSWORD:-'mailtrain'} WITH_ZONE_MTA=${WITH_ZONE_MTA:-'true'} POOL_NAME=${POOL_NAME:-$(hostname)} +LOG_LEVEL=${LOG_LEVEL:-'info'} # Warning for users that already rely on the MAILTRAIN_SETTING variable # Can probably be removed in the future. @@ -88,6 +89,9 @@ builtinZoneMTA: queue: processes: 5 + +log: + level: $LOG_LEVEL EOT # Manage LDAP if enabled diff --git a/locales/de-DE/common.json b/locales/de-DE/common.json index 53d7aac5..0802c0da 100644 --- a/locales/de-DE/common.json +++ b/locales/de-DE/common.json @@ -955,7 +955,7 @@ "contentOfAnRssEntry": "Inhalt eines RSS Eintrag", "rssEntrySummary": "RSS Eintrag Zusammenfassung", "rssEntryImageUrl": "RSS Eintrag Bild URL", - "toExtractTheTextFromHtmlClickHerePlease": "<1>Hier klicken den Text aus dem HTML zu extrahieren. Hinweis: der bestehende Klartext wird überschrieben. Dieses Feature nutzt die <3>Premailer API. Es gelten die Datenschutzbestimmungen des Anbieters.", + "toExtractTheTextFromHtmlClickHerePlease": "<1>Hier klicken den Text aus dem HTML zu extrahieren. Hinweis: der bestehende Klartext wird überschrieben.", "mosaicoTemplateUpdated": "Mosaico Vorlage aktualisiert", "mosaicoTemplateCreated": "Mosaico Vorlage erstellt", "deletingMosaicoTemplate": "Mosaico Vorlage wird gelöscht ...", diff --git a/locales/en-US/common.json b/locales/en-US/common.json index eb9915ee..215b703a 100644 --- a/locales/en-US/common.json +++ b/locales/en-US/common.json @@ -961,7 +961,7 @@ "contentOfAnRssEntry": "Content of an RSS entry", "rssEntrySummary": "RSS entry summary", "rssEntryImageUrl": "RSS entry image URL", - "toExtractTheTextFromHtmlClickHerePlease": "To extract the text from HTML click <1>here. Please note that your existing plaintext in the field above will be overwritten. This feature uses the <3>Premailer API, a third party service. Their Terms of Service and Privacy Policy apply.", + "toExtractTheTextFromHtmlClickHerePlease": "To extract the text from HTML click <1>here. Please note that your existing plaintext in the field above will be overwritten.", "mosaicoTemplateUpdated": "Mosaico template updated", "mosaicoTemplateCreated": "Mosaico template created", "deletingMosaicoTemplate": "Deleting Mosaico template ...", diff --git a/locales/es-ES/common.json b/locales/es-ES/common.json index a0c072af..a7fe842d 100644 --- a/locales/es-ES/common.json +++ b/locales/es-ES/common.json @@ -985,7 +985,7 @@ "contentOfAnRssEntry": "Contenido de la entrada RSS", "rssEntrySummary": "Resumen de la entrada RSS", "rssEntryImageUrl": "Enlace a la imágen RSS", - "toExtractTheTextFromHtmlClickHerePlease": "To extract the text from HTML click <1>here. Please note that your existing plaintext in the field above will be overwritten. This feature uses the <3>Premailer API, a third party service. Their Terms of Service and Privacy Policy apply.", + "toExtractTheTextFromHtmlClickHerePlease": "To extract the text from HTML click <1>here. Please note that your existing plaintext in the field above will be overwritten.", "mosaicoTemplateUpdated": "Plantilla Mosaico actualizada", "mosaicoTemplateCreated": "Plantilla Mosaico creada", "deletingMosaicoTemplate": "Borrando plantilla Mosaico ...", diff --git a/locales/fr-FR/common.json b/locales/fr-FR/common.json index 8c7bff85..a7dbe39f 100644 --- a/locales/fr-FR/common.json +++ b/locales/fr-FR/common.json @@ -956,7 +956,7 @@ "contentOfAnRssEntry": "Contenu d'une entrée RSS", "rssEntrySummary": "Résumé de l'entrée RSS", "rssEntryImageUrl": "URL de l'image d'entrée RSS", - "toExtractTheTextFromHtmlClickHerePlease": "Pour extraire le texte de HTML, cliquez <1> ici . Veuillez noter que votre texte en clair existant dans le champ ci-dessus sera écrasé. Cette fonctionnalité utilise l '<3> API Premailer , un service tiers. Leurs conditions d'utilisation et leur politique de confidentialité s'appliquent. ", + "toExtractTheTextFromHtmlClickHerePlease": "Pour extraire le texte de HTML, cliquez <1> ici . Veuillez noter que votre texte en clair existant dans le champ ci-dessus sera écrasé.", "mosaicoTemplateUpdated": "Modèle Mosaico mis à jour", "mosaicoTemplateCreated": "Modèle Mosaico créé", "deletingMosaicoTemplate": "Suppression du modèle Mosaico ...", diff --git a/locales/pt-BR/common.json b/locales/pt-BR/common.json index 19254c1d..17d2d124 100644 --- a/locales/pt-BR/common.json +++ b/locales/pt-BR/common.json @@ -1028,7 +1028,7 @@ "contentOfAnRssEntry": "Conteúdo de uma entrada RSS", "rssEntrySummary": "Resumo da entrada do RSS", "rssEntryImageUrl": "URL da imagem de entrada RSS", - "toExtractTheTextFromHtmlClickHerePlease": "Para extrair o texto do HTML, clique <1> aqui . Observe que o texto original existente no campo acima será sobrescrito. Esse recurso usa a <3> Premailer API , uma serviço de terceiros. Os seus Termos de Serviço e Política de Privacidade são aplicáveis. ", + "toExtractTheTextFromHtmlClickHerePlease": "Para extrair o texto do HTML, clique <1> aqui . Observe que o texto original existente no campo acima será sobrescrito.", "mosaicoTemplateUpdated": "Mosaico template updated", "mosaicoTemplateUpdated - TODO: update line above and then delete this line to mark that the translation has been fixed": "Mosaico template updated", "mosaicoTemplateCreated": "Mosaico template created", diff --git a/server/package-lock.json b/server/package-lock.json index de12ae85..c233bb46 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -12162,15 +12162,6 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, - "premailer-api": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/premailer-api/-/premailer-api-1.0.4.tgz", - "integrity": "sha1-hz9A/DiN3IgG81uY3NKymTeKh08=", - "requires": { - "request": "^2.72.0", - "underscore": "^1.8.3" - } - }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", @@ -13432,11 +13423,6 @@ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" }, - "underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" - }, "underscore.string": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", diff --git a/server/package.json b/server/package.json index 3a028206..749dd8eb 100644 --- a/server/package.json +++ b/server/package.json @@ -102,7 +102,6 @@ "openpgp": "^4.7.2", "passport": "^0.4.1", "passport-local": "^1.0.0", - "premailer-api": "^1.0.4", "request": "^2.88.0", "request-promise": "^4.2.5", "serve-favicon": "^2.5.0", diff --git a/server/routes/api.js b/server/routes/api.js index aac6c2a4..aa53d4c2 100644 --- a/server/routes/api.js +++ b/server/routes/api.js @@ -18,6 +18,8 @@ const slugify = require('slugify'); const passport = require('../lib/passport'); const templates = require('../models/templates'); const campaigns = require('../models/campaigns'); +const urls = require('../lib/urls') +const { getMergeTagsForBases } = require('../../shared/templates') const {castToInteger} = require('../lib/helpers'); const {getSystemSendConfigurationId} = require('../../shared/send-configurations'); @@ -362,7 +364,9 @@ router.postAsync('/templates/:templateId/send', async (req, res) => { } const emails = input.EMAIL.split(','); - const mergeTags = input.TAGS || {}; + const mergeTagsGlobal = getMergeTagsForBases(urls.getTrustedUrl(), urls.getSandboxUrl(), urls.getPublicUrl()); + const mergeTagsLocal = input.TAGS || {}; + const mergeTags = { ...mergeTagsGlobal, ...mergeTagsLocal} const subject = input.SUBJECT || ''; const attachments = input.ATTACHMENTS || []; diff --git a/server/routes/rest/editors.js b/server/routes/rest/editors.js index 0fc5bdb3..fbdef77b 100644 --- a/server/routes/rest/editors.js +++ b/server/routes/rest/editors.js @@ -3,23 +3,14 @@ const passport = require('../../lib/passport'); const bluebird = require('bluebird'); -const premailerApi = require('premailer-api'); -const premailerPrepareAsync = bluebird.promisify(premailerApi.prepare.bind(premailerApi)); +const htmlToText = require('html-to-text'); const router = require('../../lib/router-async').create(); router.postAsync('/html-to-text', passport.loggedIn, passport.csrfProtection, async (req, res) => { - if (!req.body.html) { - return res.json({text: ''}); // Premailer crashes very hard when html is empty - } - - const email = await premailerPrepareAsync({ - html: req.body.html, - fetchHTML: false - }); - - res.json({text: email.text.replace(/%5B/g, '[').replace(/%5D/g, ']')}); + const email = htmlToText.fromString(req.body.html, {wordwrap: 130}); + res.json({text: email}); }); module.exports = router; diff --git a/server/routes/subscription.js b/server/routes/subscription.js index 36b2d1f8..bbcc1ac5 100644 --- a/server/routes/subscription.js +++ b/server/routes/subscription.js @@ -281,6 +281,11 @@ router.postAsync('/:cid/subscribe', passport.parseForm, corsOrCsrfProtection, as if (existingSubscription && existingSubscription.status === SubscriptionStatus.SUBSCRIBED) { await mailHelpers.sendAlreadySubscribed(req.locale, list, email, existingSubscription); + if (req.xhr) { + return res.status(200).json({ + msg: tUI('pleaseConfirmSubscription', req.locale) + }); + } res.redirect('/subscription/' + encodeURIComponent(req.params.cid) + '/confirm-subscription-notice'); } else { @@ -325,17 +330,18 @@ router.getAsync('/:cid/widget', cors(corsOptions), async (req, res) => { title: list.name, cid: list.cid, publicKeyUrl: getTrustedUrl('subscription/publickey'), - subscribeUrl: getTrustedUrl(`subscription/${list.cid}/subscribe`), + subscribeUrl: getPublicUrl(`subscription/${list.cid}/subscribe`), hasPubkey: !!configItems.pgpPrivateKey, customFields: await fields.forHbs(contextHelpers.getAdminContext(), list.id), - template: {}, + template: 'subscription/widget-subscribe.hbs', layout: null, }; await injectCustomFormData(req.query.fid || list.default_form, 'web_subscribe', data); - const renderAsync = bluebird.promisify(res.render.bind(res)); - const html = await renderAsync('subscription/widget-subscribe', data); + const htmlRenderer = await tools.getTemplate(data.template, req.locale); + + const html = htmlRenderer(data); const response = { data: {