New project structure

Beta of extract.js for extracting english locale
This commit is contained in:
Tomas Bures 2018-11-18 15:38:52 +01:00
parent e18d2b2f84
commit 2edbd67205
247 changed files with 6405 additions and 4237 deletions

13
.gitignore vendored
View file

@ -4,19 +4,6 @@
node_modules node_modules
npm-debug.log npm-debug.log
.DS_Store .DS_Store
config/development.*
config/production.*
config/test.*
workers/reports/config/development.*
workers/reports/config/production.*
workers/reports/config/test.*
dump.rdb dump.rdb
# generate POT file every time you want to update your PO file
languages/mailtrain.pot
config/production.toml
workers/reports/config/production.toml
docker-compose.override.yml docker-compose.override.yml
/files

View file

@ -1,19 +0,0 @@
# Crowdfunding Backers of Mailtrain v1
Mailtrain v1 received funding from a [crowdfunding campaign](https://www.indiegogo.com/at/mailtrain/8720095).
This was to enable me to spend the time required to get automation support into Mailtrain v1. These are the people who contributed to this fund raiser.
* iRedMail - free, open source mail server solution <[www.iredmail.org](http://www.iredmail.org/)>
* Richard Adleta
* Wes Bos
* Christophe Lombart
* Anselm Hannemann
* Jens Carroll
* Anonymous
* Brett Nelson
* Jason Pelker
* Leif Singer
* Eve Land
* Diana Espino
* Moussa Clarke
* Carl Hauschke

View file

@ -1,149 +1,5 @@
# Changelog # Changelog
## 1.23.2 2017-04-04 ## 2.0.0 2018-11-23
* Allow skipping DNS check for imports * This is a complete rewrite of Mailtrain v1 with many features added. Just check it out.
* Added option to use subscription widgets
## 1.23.0 2017-03-19
* Fixed security issue where description tags were able to include script tags. Reported by Andreas Lindh. Fixed with [ae6affda](https://github.com/Mailtrain-org/mailtrain/commit/ae6affda8193f034e06f7e095ee23821a83d5190)
* Fixed security issue where templates that looked like file paths loaded content from arbitrary files. Reported by Andreas Lindh. Fixed with [0879fa41](https://github.com/Mailtrain-org/mailtrain/commit/0879fa412a2d4a417aeca5cd5092a8f86531e7ef)
* Fixed security issue where users were able to use html tags in subscription values. Reported by Andreas Lindh. Fixed with [9d5fb816](https://github.com/Mailtrain-org/mailtrain/commit/9d5fb816c937114966d4f589e1ad4e164ff3a187)
* Support for multiple HTML editors (Mosaico, Grapesjs, Summernote, HTML code)
## 1.22.0 2017-03-02
* Reverted license back to GPL-v3 to support Mosaico
## 1.21.0 2017-02-17
* Changed license from MIT to EUPL-1.1
* Added support for sending mail using AWS SES
## 1.20.0 2016-12-11
* Added option to distribute sending queue between multiple processes to speed up delivery
## 1.19.0 2016-09-15
* Changed license from GPL-V3 to MIT
## 1.18.0 2016-09-08
* Updated installation script to bundle ZoneMTA as the default sending engine
* Added new option to disable clicked and opened tracking
* Store remote IP for subscription confirmations
## 1.17.0 2016-08-29
* Added new custom field for JSON data that is rendered using Handlebars when included in an email
## 1.16.0 2016-08-29
* Render list values using Handlebars templates
* Added new API method to create custom fields
* Added LDAP authentication support
## 1.15.0 2016-07-28
* Check SMTP settings using AJAX instead of posting entire form
## 1.14.0 2016-07-09
* Fixed ANY match segments with range queries
* Added an option to disable un/subscribe confirmation messages
* Added support for throttling when sending messages
* Added preview links in message lists
## 1.13.0 2016-06-23
* Added API method to delete subscribers
* Added a counter to triggers with a view to list all subscribers that caused this trigger to fire
## 1.12.1 2016-06-23
* Fixed invalid base SQL dump
## 1.12.0 2016-06-22
* Automation support. Create triggers that send a campaign once fired
* Fixed an issue with unresolved URL redirects
* Added support for relative date ranges in segments
## 1.11.0 2016-05-31
* Retry transactional mail if failed with soft error (4xx)
* New feature to preview campaigns using selected test users
## 1.10.1 2016-05-26
* Fix a bug with SMTP transport instance where campaign sending stalled until server was restarted
## 1.10.0 2016-05-25
* Fetch multiple unsent messages at once to speed up delivery
* Fixed a bug of counting unsubscribers correctly
* Use LONGTEXT for template text fields (messages might include inlined images which are larger than 64kB)
## 1.9.0 2016-05-16
* New look
* Added views for bounced/unsubscribed/complained etc.
## 1.8.2 2016-05-13
* Added missing views for subscribers who clicked on any link and subscribers who opened the message
## 1.8.1 2016-05-13
* Fixed an issue in API
## 1.8.0 2016-05-13
* Show details about subscribers who clicked on a specific link
## 1.7.0 2016-05-11
* Updated API, added new option **REQUIRE_CONFIRMATION** for subscriptions to send confirmation email before subscribing
## 1.6.0 2016-05-07
* Added simple API support for adding and removing list subscriptions
## 1.5.0 2016-05-05
* Fixed a bug in unsubscribing through the admin interface
* Added individual link click stats
## 1.4.1 2016-05-04
* Added support for RSS templates
## 1.4.0 2016-05-04
* Added support for RSS campaigns
* Subscribers get timezone attached to their profile
* Outgoing messages are preprocessed using juice
* Added installation script for easier setup
## 1.3.0 2016-04-29
* Added option to use an URL as message source (when message needs to be rendered a POST request with Merge Tags as the POST body is made against that URL)
* Added option to schedule sending. You can set optional delay time when starting campaign sending. Once this time is reached sending starts automatically
* Show meaningful MySQL error when connection fails
## 1.2.0 2016-04-25
* Rewrite merge tags in links (allows using links like `http://example.com/?u=[FIRST_NAME]` in messages)
* Added view for Imports to list failed addresses
* Automatic SQL table creation on initial run (no need for the `mysql` command anymore)
* Automatic SQL table updates on startup
* Send welcome and unsubscribe confirmation emails for subscribers
* Added support for GPG encryption for outgoing messages (requires custom field "GPG Key" set up for the list)
* Added new SMTP option: allow self-signed certs
* Added new setting: Disable WYSIWG editor (allows better handling of complex HTML templates)
* Allow downgrading user when server started as root (user is downgraded once all ports are bound)
* Added Nitrous.io one-click install button for easy try-out
* Added Max Post Size option to allow larger payloads from bounce webhooks
* Added VERP support to catch bounces using built in VERP smtp-server (disabled by default)

View file

@ -1,18 +0,0 @@
'use strict';
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
eslint: {
all: ['lib/**/*.js', 'test/**/*.js', 'config/**/*.js', 'services/**/*.js', 'Gruntfile.js', 'app.js', 'index.js', 'routes/editorapi.js']
}
});
// Load the plugin(s)
grunt.loadNpmTasks('grunt-eslint');
grunt.task.loadTasks('tasks');
// Tasks
grunt.registerTask('default', ['eslint']);
};

View file

@ -1,6 +1,6 @@
# Mailtrain # Mailtrain
[Mailtrain](http://mailtrain.org) is a self hosted newsletter application built on Node.js (v7+) and MySQL (v5.5+ or MariaDB). [Mailtrain](http://mailtrain.org) is a self hosted newsletter application built on Node.js (v10+) and MySQL (v8+) or MariaDB (v10+).
![](http://mailtrain.org/mailtrain.png) ![](http://mailtrain.org/mailtrain.png)
@ -9,14 +9,16 @@
* Subscriber list management * Subscriber list management
* List segmentation * List segmentation
* Custom fields * Custom fields
* Email templates * Email templates (including MJML-based templates)
* Large CSV list import files * Large CSV list import files
* Custom reports
Subscribe to Mailtrain Newsletter [here](https://mailtrain.org/subscription/S18sew2wM) (uses Mailtrain obviously) * Automation (triggered and RSS campaigns)
* Multiple users with granular user permissions and flexible sharing
* Hierarchical namespaces for enterprise-level situations
## Hardware Requirements ## Hardware Requirements
* 1 vCPU * 1 vCPU
* 1024 MB RAM * 2048 MB RAM
## Quick Start - Deploy with Docker ## Quick Start - Deploy with Docker
#### Requirements: #### Requirements:
@ -39,7 +41,7 @@ Depending on how you have configured your system and Docker you may need to prep
## Quick Start - Manual Install (any OS that supports Node.js) ## Quick Start - Manual Install (any OS that supports Node.js)
### Requirements: ### Requirements:
* Mailtrain requires at least **Node.js v7**. If you want to use an older version of Node.js then you should use version v1.24 of Mailtrain. You can either download it [here](https://github.com/Mailtrain-org/mailtrain/archive/v1.24.0.zip) or if using git then run `git checkout v1.24.0` before starting it * Mailtrain requires at least **Node.js v10**.
1. Download Mailtrain files using git: `git clone git://github.com/Mailtrain-org/mailtrain.git` (or download [zipped repo](https://github.com/Mailtrain-org/mailtrain/archive/master.zip)) and open Mailtrain folder `cd mailtrain` 1. Download Mailtrain files using git: `git clone git://github.com/Mailtrain-org/mailtrain.git` (or download [zipped repo](https://github.com/Mailtrain-org/mailtrain/archive/master.zip)) and open Mailtrain folder `cd mailtrain`
2. Run `npm install --production` in the Mailtrain folder to install required dependencies 2. Run `npm install --production` in the Mailtrain folder to install required dependencies
@ -56,7 +58,4 @@ For more information, please [read the docs](http://docs.mailtrain.org/).
## License ## License
* Versions 1.22.0 and up **GPL-V3.0** **GPL-V3.0**
* Versions 1.21.0 and up: **EUPL-1.1**
* Versions 1.19.0 and up: **MIT**
* Up to versions 1.18.0 **GPL-V3.0**

View file

@ -1,18 +1,9 @@
### Front page ### Front page
- Some dashboard - Some dashboard
### Templates
- Add MJML template editor
- Include Grapesjs with MJML support
- CKEditor to sandbox
- Add Files support to CKEditor
### Message delivery ### 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. - 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.
### Lists
- CSV Export
### Campaigns ### Campaigns
- Statistics for a sent campaign - Statistics for a sent campaign
- List of sent RSS campaigns (?) - List of sent RSS campaigns (?)

View file

@ -1,6 +1,6 @@
{ {
"name": "mailtrain-client", "name": "mailtrain-client",
"version": "1.0.0", "version": "2.0.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -5319,7 +5319,6 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "mailtrain-client", "name": "mailtrain-client",
"version": "1.0.0", "version": "2.0.0",
"description": "Self hosted email newsletter app - client components", "description": "Self hosted email newsletter app - client components",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@ -11,7 +11,6 @@
"type": "git", "type": "git",
"url": "git://github.com/Mailtrain-org/mailtrain.git" "url": "git://github.com/Mailtrain-org/mailtrain.git"
}, },
"author": "",
"license": "GPL-3.0", "license": "GPL-3.0",
"homepage": "https://mailtrain.org/", "homepage": "https://mailtrain.org/",
"dependencies": { "dependencies": {

View file

@ -43,9 +43,9 @@ export function getMailerTypes(t) {
function validateNumber(state, field, label, emptyAllowed = false) { function validateNumber(state, field, label, emptyAllowed = false) {
const value = state.getIn([field, 'value']); const value = state.getIn([field, 'value']);
if (typeof value === 'string' && value.trim() === '' && !emptyAllowed) { // After load, the numerical values can be still numbers if (typeof value === 'string' && value.trim() === '' && !emptyAllowed) { // After load, the numerical values can be still numbers
state.setIn([field, 'error'], t(`${label} must not be empty`)); state.setIn([field, 'error'], t('{{label}} must not be empty', {label}));
} else if (isNaN(value)) { } else if (isNaN(value)) {
state.setIn([field, 'error'], t(`${label} must be a number`)); state.setIn([field, 'error'], t('{{label}} must be a number', {label}));
} else { } else {
state.setIn([field, 'error'], null); state.setIn([field, 'error'], null);
} }

View file

@ -578,6 +578,9 @@ export function getEditForm(owner, typeKey, prefix = '') {
{owner.templateTypes[typeKey].getHTMLEditor(owner)} {owner.templateTypes[typeKey].getHTMLEditor(owner)}
<ACEEditor id={prefix + 'text'} height="400px" mode="text" label={t('Template content (plain text)')} help={<Trans>To extract the text from HTML click <ActionLink onClickAsync={::owner.extractPlainText}>here</ActionLink>. Please note that your existing plaintext in the field above will be overwritten. This feature uses the <a href="http://premailer.dialect.ca/api">Premailer API</a>, a third party service. Their Terms of Service and Privacy Policy apply.</Trans>}/> <ACEEditor id={prefix + 'text'} height="400px" mode="text" label={t('Template content (plain text)')} help={<Trans>To extract the text from HTML click <ActionLink onClickAsync={::owner.extractPlainText}>here</ActionLink>. Please note that your existing plaintext in the field above will be overwritten. This feature uses the <a href="http://premailer.dialect.ca/api">Premailer API</a>, a third party service. Their Terms of Service and Privacy Policy apply.</Trans>}/>
/*prefix:helpers*/<Trans i18nKey="userMessagesUnread" count={count}>
Hello <strong title={t('nameTitle')}>{{name}}</strong>, you have {{count}} unread message. <Link to="/msgs">Go to messages</Link>.
</Trans>
</div>; </div>;
} }

View file

@ -1,13 +1,13 @@
FROM node:8.6 FROM node:8.6
# First install dependencies # First install dependencies
COPY ./package.json ./app/ COPY ../server/package.json ./app/
WORKDIR /app/ WORKDIR /app/
ENV NODE_ENV production ENV NODE_ENV production
RUN npm install --no-progress --production && npm install --no-progress passport-ldapjs passport-ldapauth RUN npm install --no-progress --production && npm install --no-progress passport-ldapjs passport-ldapauth
# Later, copy the app files. That improves development speed as buiding the Docker image will not have # Later, copy the app files. That improves development speed as buiding the Docker image will not have
# to download and install all the NPM dependencies every time there's a change in the source code # to download and install all the NPM dependencies every time there's a change in the source code
COPY . /app COPY .. /app
EXPOSE 3000 EXPOSE 3000
ENTRYPOINT ["bash", "/app/docker-entrypoint.sh"] ENTRYPOINT ["bash", "/app/docker-entrypoint.sh"]
CMD ["node", "index.js"] CMD ["node", "index.js"]

View file

@ -1,10 +1,11 @@
# Mailtrain # Mailtrain v2
[Mailtrain](http://mailtrain.org) is a self hosted newsletter application built on Node.js (v7+) and MySQL (v5.5+ or MariaDB). [Mailtrain](http://mailtrain.org) is a self hosted newsletter application built on Node.js (v10+) and MySQL (v8+) or MariaDB (v10+).
![](http://mailtrain.org/mailtrain.png) ![](http://mailtrain.org/mailtrain.png)
> Mailtrain requires at least **Node.js v7**. If you want to use an older version of Node.js then you should use version v1.24 of Mailtrain. You can either download it [here](https://github.com/Mailtrain-org/mailtrain/archive/v1.24.0.zip) or if using git then run `git checkout v1.24.0` before starting it FIXME: The info below needs to be updated !!!
## Features ## Features

View file

@ -95,58 +95,6 @@
"namespace": { "namespace": {
"mustBeSelected": "Namespace must be selected" "mustBeSelected": "Namespace must be selected"
}, },
"": {
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": ""
},
"": {
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": ""
},
"": {
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": ""
},
"": {
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": ""
},
"close": "Close", "close": "Close",
"name": "Name", "name": "Name",
@ -158,7 +106,6 @@
"loading": "Loading ...", "loading": "Loading ...",
"email": "Email", "email": "Email",
"update": "Update", "update": "Update",
"": "",
"namespace": "Namespace", "namespace": "Namespace",
"namespace_plural": "Namespaces", "namespace_plural": "Namespaces",
@ -190,17 +137,7 @@
"validationInProgress": "Validation is in progress...", "validationInProgress": "Validation is in progress...",
"errorsInForm": "There are errors in the form. Please fix them and submit again.", "errorsInForm": "There are errors in the form. Please fix them and submit again.",
"updatesCannotBeSaved": "Your updates cannot be saved.", "updatesCannotBeSaved": "Your updates cannot be saved.",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"": "",
"mjml": "MJML", "mjml": "MJML",
"html": "HTML", "html": "HTML"
"": "",
"": "",
"": ""
} }

297
locales/extract.js Normal file
View file

@ -0,0 +1,297 @@
'use strict';
// Example:
// tUI(/*prefix:account*/'account.passwordChangeRequest', language)
// /*prefix:helpers*/<Trans i18nKey="userMessagesUnread" count={count}>Hello <strong title={t('nameTitle')}>{{name}}</strong>, you have {{count}} unread message. <Link to="/msgs">Go to messages</Link>.</Trans>
const fs = require('fs');
const path = require('path');
const klawSync = require('klaw-sync');
const acorn = require("acorn");
const acornJsx = require("acorn-jsx");
const ellipsize = require('ellipsize');
const camelCase = require('camelcase');
const slugify = require('slugify');
const readline = require('readline');
const localeFile = 'common/en.json';
const searchDirs = [
'../client/src',
'../server',
'../shared'
];
function findInDict(dict, key) {
const keyElems = key.split('.');
let val = dict;
for (const keyElem of keyElems) {
if (val) {
val = val[keyElem];
} else {
return undefined;
}
}
return val;
}
function setInDict(dict, key, value) {
const keyElems = key.split('.');
let val = dict;
for (const keyElem of keyElems.slice(0, -1)) {
if (val[keyElem]) {
if (typeof val[keyElem] === 'string') {
throw new Error(`Overlapping key ${key}`);
}
} else {
val[keyElem] = {}
}
val = val[keyElem];
}
val[keyElems[keyElems.length - 1]] = value;
}
const assignedKeys = new Map();
function getKeyFromValue(spec, value) {
let key = value.replace(/<\/?[0-9]+>/g, ''); // Remove Trans markup
key = slugify(key, { replacement: ' ', remove: /[()"':.,;\[\]\{\}*+-]/g, lower: false });
key = camelCase(key);
key = ellipsize(key, 40, {
chars: [...Array(26)].map((_, i) => String.fromCharCode('A'.charCodeAt(0) + i)) /* This is an array of characters A-Z */,
ellipse: ''
});
if (spec.prefix) {
key = spec.prefix + '.' + key;
}
let idx = 0;
while (true) {
const keyExt = key + (idx ? '-' + idx : '')
if (assignedKeys.has(keyExt)) {
if (assignedKeys.get(keyExt) === value) {
assignedKeys.set(key, value);
return keyExt;
}
} else {
assignedKeys.set(key, value);
return keyExt;
}
idx++;
}
}
function allowedDirOrFile(item) {
const pp = path.parse(item.path)
return (
(item.stats.isDirectory() &&
pp.base !== 'node_modules'
) ||
(item.stats.isFile() &&
( pp.ext === '.js' || pp.ext === '.jsx')
)
);
}
function parseSpec(specStr) {
const spec = {};
if (specStr) {
const entryMatcher = /([a-zA-Z]*)\s*:\s*(.*)/
const entries = specStr.split(/\s*,\s*/);
for (const entry of entries) {
const elems = entry.match(entryMatcher);
if (elems) {
spec[elems[1]] = elems[2];
}
}
}
return spec;
}
// see http://blog.stevenlevithan.com/archives/match-quoted-string
const tMatcher = /(^|[ {+(=])((?:tUI|tLog|t|tMark)\s*\(\s*(?:\/\*(.*?)\*\/)?\s*)(["'])((?:(?!\1)[^\\]|\\.)*)(\4)/;
const transMatcher = /(\/\*(.*?)\*\/\s*)?(\<Trans[ >][\s\S]*?\<\/Trans\>)/;
const jsxParser = acorn.Parser.extend(acornJsx());
function parseTrans(fragment) {
const match = fragment.match(transMatcher);
const spec = parseSpec(match[2]);
const jsxStr = match[3];
const jsxStrSmpl = jsxStr.replace('{::', '{ '); // Acorn does not handle bind (::) operator. So we just leave it out because we are not interested in the code anyway.
const ast = jsxParser.parse(jsxStrSmpl);
function convertChildren(children) {
const entries = [];
let childNo = 0;
for (const child of children) {
const type = child.type;
if (type === 'JSXText') {
entries.push(child.value);
childNo++;
} else if (type === 'JSXElement') {
const inner = convertChildren(child.children);
entries.push(`<${childNo}>${convertChildren(child.children)}</${childNo}>`);
childNo++;
} else if (type === 'JSXExpressionContainer') {
entries.push(jsxStr.substring(child.start, child.end));
childNo++;
} else {
throw new Error('Unknown JSX node: ' + child);
}
}
return entries.join('');
}
const expr = ast.body[0].expression;
let originalKey;
for (const attr of expr.openingElement.attributes) {
const name = attr.name.name;
if (name === 'i18nKey') {
originalKey = attr.value.value;
}
}
const convValue = convertChildren(expr.children);
if (originalKey === undefined) {
originalKey = convValue;
}
let value;
const originalValue = findInDict(originalResDict, originalKey);
if (originalValue === undefined) {
value = convValue;
} else {
value = originalValue;
}
const key = getKeyFromValue(spec, value);
const replacement = `${match[1] || ''}<Trans i18nKey="${key}">${jsxStr.substring(expr.openingElement.end, expr.closingElement.start)}</Trans>`;
return { key, originalKey, value, replacement };
}
function parseT(fragment) {
const match = fragment.match(tMatcher);
const originalKey = match[5];
const spec = parseSpec(match[3]);
// console.log(`${file}: ${line}`);
// console.log(` |${match[1]}|${match[2]}|${match[4]}|${match[5]}|${match[6]}| - ${JSON.stringify(spec)}`);
let value;
const originalValue = findInDict(originalResDict, originalKey);
if (originalValue === undefined) {
value = originalKey;
} else {
value = originalValue;
}
const key = getKeyFromValue(spec, value);
const replacement = `${match[1]}${match[2]}${match[4]}${key}${match[6]}`;
return { key, originalKey, value, originalValue, replacement };
}
const renamedKeys = new Map();
const resDict = {};
let anyUpdatesToResDict = false;
function processFile(file) {
let source = fs.readFileSync(file, 'utf8');
let anyUpdates = false;
function update(fragments, parseFun) {
if (fragments) {
for (const fragment of fragments) {
const {key, originalKey, value, originalValue, replacement} = parseFun(fragment);
console.log(`${key} <- ${originalKey} | ${value} <- ${originalValue} | ${fragment} -> ${replacement}`);
source = source.split(fragment).join(replacement);
setInDict(resDict, key, value);
if (originalKey) {
renamedKeys.set(originalKey, key);
}
}
}
}
const lines = source.split(/\r?\n/g);
for (const line of lines) {
const fragments = line.match(new RegExp(tMatcher, 'g'));
update(fragments, parseT);
}
const fragments = source.match(new RegExp(transMatcher, 'g'));
update(fragments, parseTrans);
if (false) {
console.log(`Updating ${file}`);
fs.writeFileSync(file, source);
anyUpdatesToResDict = true;
}
}
const originalResDict = JSON.parse(fs.readFileSync(localeFile));
function run() {
/*
for (const dir of searchDirs) {
const files = klawSync(dir, { nodir: true, filter: allowedDirOrFile })
for (const file of files) {
processFile(file.path);
}
}
*/
processFile('../client/src/templates/helpers.js');
if (anyUpdatesToResDict) {
console.log(`Updating ${localeFile}`);
fs.writeFileSync(localeFile, JSON.stringify(resDict));
}
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
run();
/*
console.log('This script does modifications in the source tree. You should first commit all your files in git before proceeding.');
rl.question('To proceed type YES: ', (answer) => {
if (answer === 'YES') {
run();
}
rl.close();
});
*/

46
locales/package-lock.json generated Normal file
View file

@ -0,0 +1,46 @@
{
"name": "mailtrain-locales-extractor",
"version": "2.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"acorn": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz",
"integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg=="
},
"acorn-jsx": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.0.tgz",
"integrity": "sha512-XkB50fn0MURDyww9+UYL3c1yLbOBz0ZFvrdYlGB8l+Ije1oSC75qAqrzSPjYQbdnQUzhlUGNKuesryAv0gxZOg=="
},
"camelcase": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA=="
},
"ellipsize": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ellipsize/-/ellipsize-0.1.0.tgz",
"integrity": "sha1-nUNoLUS5GtFuvYQmisEDFwplU/g="
},
"graceful-fs": {
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
},
"klaw-sync": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
"requires": {
"graceful-fs": "^4.1.11"
}
},
"slugify": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.3.tgz",
"integrity": "sha512-aFvcXobuowA7RqU4IBVJvqmhkREDIqsj4oIJKk6JuZ5EO1PCwtAAwDCl8TdsMs4J9zCoDAVkB9FLUElDjNcRSg=="
}
}
}

21
locales/package.json Normal file
View file

@ -0,0 +1,21 @@
{
"name": "mailtrain-locales-extractor",
"private": true,
"version": "2.0.0",
"description": "Extractor for t-functions in the code (client and server)",
"main": "extract.js",
"scripts": {},
"license": "GPL-3.0",
"homepage": "https://mailtrain.org/",
"engines": {
"node": ">=10.0.0"
},
"dependencies": {
"acorn": "^6.0.4",
"acorn-jsx": "^5.0.0",
"camelcase": "^5.0.0",
"ellipsize": "^0.1.0",
"klaw-sync": "^6.0.0",
"slugify": "^1.3.3"
}
}

7
server/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
/config/development.*
/config/production.*
/config/test.*
/workers/reports/config/development.*
/workers/reports/config/production.*
/workers/reports/config/test.*
/files

29
server/Gruntfile.js Normal file
View file

@ -0,0 +1,29 @@
'use strict';
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
eslint: {
all: [
'lib/**/*.js',
'models/**/*.js',
'routes/**/*.js',
'services/**/*.js',
'lib/**/*.js',
'test/**/*.js',
'workers/**/*.js',
'app-builder.js',
'index.js',
'Gruntfile.js',
]
}
});
// Load the plugin(s)
grunt.loadNpmTasks('grunt-eslint');
grunt.task.loadTasks('tasks');
// Tasks
grunt.registerTask('default', ['eslint']);
};

View file

@ -57,10 +57,10 @@ const settingsRest = require('./routes/rest/settings');
const index = require('./routes/index'); const index = require('./routes/index');
const interoperableErrors = require('./shared/interoperable-errors'); const interoperableErrors = require('../shared/interoperable-errors');
const { getTrustedUrl } = require('./lib/urls'); const { getTrustedUrl } = require('./lib/urls');
const { AppType } = require('./shared/app'); const { AppType } = require('../shared/app');
hbs.registerPartials(__dirname + '/views/partials'); hbs.registerPartials(__dirname + '/views/partials');
hbs.registerPartials(__dirname + '/views/subscription/partials/'); hbs.registerPartials(__dirname + '/views/subscription/partials/');

24
server/config/test.toml Normal file
View file

@ -0,0 +1,24 @@
[www]
port=3000
[mysql]
user="mailtrain_test"
password="bahquaiphoor"
database="mailtrain_test"
[testServer]
enabled=true
[seleniumWebDriver]
browser="phantomjs"
[ldap]
# enable to use ldap user backend
enabled=false
host="localhost"
port=3002
baseDN="ou=users,dc=example"
filter="(|(username={{username}})(mail={{username}}))"
#Username field in LDAP (uid/cn/username)
uidTag="username"
# nameTag identifies the attribute to be used for user's full name
nameTag="username"
passwordresetlink="xxx"
[reports]
enabled=true

View file

@ -18,7 +18,7 @@ const executor = require('./lib/executor');
const privilegeHelpers = require('./lib/privilege-helpers'); const privilegeHelpers = require('./lib/privilege-helpers');
const knex = require('./lib/knex'); const knex = require('./lib/knex');
const shares = require('./models/shares'); const shares = require('./models/shares');
const { AppType } = require('./shared/app'); const { AppType } = require('../shared/app');
const trustedPort = config.www.trustedPort; const trustedPort = config.www.trustedPort;
const sandboxPort = config.www.sandboxPort; const sandboxPort = config.www.sandboxPort;

View file

@ -1,23 +1,23 @@
'use strict'; 'use strict';
const config = require('config'); const config = require('config');
const mailers = require('../lib/mailers'); const mailers = require('./mailers');
const knex = require('../lib/knex'); const knex = require('./knex');
const subscriptions = require('../models/subscriptions'); const subscriptions = require('../models/subscriptions');
const contextHelpers = require('../lib/context-helpers'); const contextHelpers = require('./context-helpers');
const campaigns = require('../models/campaigns'); const campaigns = require('../models/campaigns');
const templates = require('../models/templates'); const templates = require('../models/templates');
const lists = require('../models/lists'); const lists = require('../models/lists');
const fields = require('../models/fields'); const fields = require('../models/fields');
const sendConfigurations = require('../models/send-configurations'); const sendConfigurations = require('../models/send-configurations');
const links = require('../models/links'); const links = require('../models/links');
const {CampaignSource, CampaignType} = require('../shared/campaigns'); const {CampaignSource, CampaignType} = require('../../shared/campaigns');
const {SubscriptionStatus} = require('../shared/lists'); const {SubscriptionStatus} = require('../../shared/lists');
const tools = require('../lib/tools'); const tools = require('./tools');
const request = require('request-promise'); const request = require('request-promise');
const files = require('../models/files'); const files = require('../models/files');
const htmlToText = require('html-to-text'); const htmlToText = require('html-to-text');
const {getPublicUrl} = require('../lib/urls'); const {getPublicUrl} = require('./urls');
const blacklist = require('../models/blacklist'); const blacklist = require('../models/blacklist');
const libmime = require('libmime'); const libmime = require('libmime');

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const knex = require('../lib/knex'); const knex = require('./knex');
function getRequestContext(req) { function getRequestContext(req) {
const context = { const context = {

View file

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const knex = require('./knex'); const knex = require('./knex');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const entitySettings = require('./entity-settings'); const entitySettings = require('./entity-settings');
const shares = require('../models/shares'); const shares = require('../models/shares');
const { enforce } = require('./helpers'); const { enforce } = require('./helpers');

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const knex = require('../lib/knex'); const knex = require('./knex');
const entitySettings = require('./entity-settings'); const entitySettings = require('./entity-settings');
async function ajaxListTx(tx, params, queryFun, columns, options) { async function ajaxListTx(tx, params, queryFun, columns, options) {

View file

@ -4,7 +4,7 @@ const knex = require('./knex');
const fork = require('child_process').fork; const fork = require('child_process').fork;
const log = require('./log'); const log = require('./log');
const path = require('path'); const path = require('path');
const {ImportStatus, RunStatus} = require('../shared/imports'); const {ImportStatus, RunStatus} = require('../../shared/imports');
let messageTid = 0; let messageTid = 0;
let importerProcess; let importerProcess;

View file

@ -2,7 +2,7 @@
const config = require('config'); const config = require('config');
const knex = require('knex')({ const knex = require('server/lib/knex')({
client: 'mysql2', client: 'mysql2',
connection: config.mysql, connection: config.mysql,
migrations: { migrations: {

View file

@ -2,7 +2,7 @@
const { enforce } = require('./helpers'); const { enforce } = require('./helpers');
const shares = require('../models/shares'); const shares = require('../models/shares');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
async function validateEntity(tx, entity) { async function validateEntity(tx, entity) {
enforce(entity.namespace, 'Entity namespace not set'); enforce(entity.namespace, 'Entity namespace not set');

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const nodeify = require('nodeify'); const nodeify = require('server/lib/nodeify');
module.exports.nodeifyPromise = nodeify; module.exports.nodeifyPromise = nodeify;

View file

@ -5,7 +5,7 @@ const log = require('./log');
const _ = require('./translate')._; const _ = require('./translate')._;
const util = require('util'); const util = require('util');
const passport = require('passport'); const passport = require('server/lib/passport');
const LocalStrategy = require('passport-local').Strategy; const LocalStrategy = require('passport-local').Strategy;
const csrf = require('csurf'); const csrf = require('csurf');
@ -13,7 +13,7 @@ const bodyParser = require('body-parser');
const users = require('../models/users'); const users = require('../models/users');
const { nodeifyFunction, nodeifyPromise } = require('./nodeify'); const { nodeifyFunction, nodeifyPromise } = require('./nodeify');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const contextHelpers = require('./context-helpers'); const contextHelpers = require('./context-helpers');
let authMode = 'local'; let authMode = 'local';

View file

@ -3,7 +3,7 @@
const log = require('./log'); const log = require('./log');
const reports = require('../models/reports'); const reports = require('../models/reports');
const executor = require('./executor'); const executor = require('./executor');
const contextHelpers = require('../lib/context-helpers'); const contextHelpers = require('./context-helpers');
let runningWorkersCount = 0; let runningWorkersCount = 0;
let maxWorkersCount = 1; let maxWorkersCount = 1;

View file

@ -3,8 +3,8 @@
const fork = require('child_process').fork; const fork = require('child_process').fork;
const log = require('./log'); const log = require('./log');
const path = require('path'); const path = require('path');
const knex = require('../lib/knex'); const knex = require('./knex');
const {CampaignStatus} = require('../shared/campaigns'); const {CampaignStatus} = require('../../shared/campaigns');
let messageTid = 0; let messageTid = 0;
let senderProcess; let senderProcess;

View file

@ -4,10 +4,10 @@ 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, getPublicUrl} = require('./urls'); const {getTrustedUrl, getPublicUrl} = require('./urls');
const { tUI } = require('./translate'); const { tUI, tMark } = require('./translate');
const util = require('util'); const util = require('util');
const contextHelpers = require('./context-helpers'); const contextHelpers = require('./context-helpers');
const {getFieldColumn} = require('../shared/lists'); const {getFieldColumn} = require('../../shared/lists');
const forms = require('../models/forms'); const forms = require('../models/forms');
const mailers = require('./mailers'); const mailers = require('./mailers');
@ -26,7 +26,7 @@ async function sendSubscriptionConfirmed(lang, list, email, subscription) {
unsubscribeUrl: '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid unsubscribeUrl: '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid
}; };
await _sendMail(list, email, 'subscription_confirmed', lang, 'subscription.confirmed', relativeUrls, subscription); await _sendMail(list, email, 'subscription_confirmed', lang, tMark('subscription.confirmed'), relativeUrls, subscription);
} }
async function sendAlreadySubscribed(lang, list, email, subscription) { async function sendAlreadySubscribed(lang, list, email, subscription) {
@ -34,35 +34,35 @@ async function sendAlreadySubscribed(lang, list, email, subscription) {
preferencesUrl: '/subscription/' + list.cid + '/manage/' + subscription.cid, preferencesUrl: '/subscription/' + list.cid + '/manage/' + subscription.cid,
unsubscribeUrl: '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid unsubscribeUrl: '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid
}; };
await _sendMail(list, email, 'already_subscribed', lang, 'subscription.alreadyRegistered', relativeUrls, subscription); await _sendMail(list, email, 'already_subscribed', lang, tMark('subscription.alreadyRegistered'), relativeUrls, subscription);
} }
async function sendConfirmAddressChange(lang, list, email, cid, subscription) { async function sendConfirmAddressChange(lang, list, email, cid, subscription) {
const relativeUrls = { const relativeUrls = {
confirmUrl: '/subscription/confirm/change-address/' + cid confirmUrl: '/subscription/confirm/change-address/' + cid
}; };
await _sendMail(list, email, 'confirm_address_change', lang, 'subscription.confirmEmailChange', relativeUrls, subscription); await _sendMail(list, email, 'confirm_address_change', lang, tMark('subscription.confirmEmailChange'), relativeUrls, subscription);
} }
async function sendConfirmSubscription(lang, list, email, cid, subscription) { async function sendConfirmSubscription(lang, list, email, cid, subscription) {
const relativeUrls = { const relativeUrls = {
confirmUrl: '/subscription/confirm/subscribe/' + cid confirmUrl: '/subscription/confirm/subscribe/' + cid
}; };
await _sendMail(list, email, 'confirm_subscription', lang, 'subscription.confirmSubscription', relativeUrls, subscription); await _sendMail(list, email, 'confirm_subscription', lang, tMark('subscription.confirmSubscription'), relativeUrls, subscription);
} }
async function sendConfirmUnsubscription(lang, list, email, cid, subscription) { async function sendConfirmUnsubscription(lang, list, email, cid, subscription) {
const relativeUrls = { const relativeUrls = {
confirmUrl: '/subscription/confirm/unsubscribe/' + cid confirmUrl: '/subscription/confirm/unsubscribe/' + cid
}; };
await _sendMail(list, email, 'confirm_unsubscription', lang, 'subscription.confirmUnsubscription', relativeUrls, subscription); await _sendMail(list, email, 'confirm_unsubscription', lang, tMark('subscription.confirmUnsubscription'), relativeUrls, subscription);
} }
async function sendUnsubscriptionConfirmed(lang, list, email, subscription) { async function sendUnsubscriptionConfirmed(lang, list, email, subscription) {
const relativeUrls = { const relativeUrls = {
subscribeUrl: '/subscription/' + list.cid + '?cid=' + subscription.cid subscribeUrl: '/subscription/' + list.cid + '?cid=' + subscription.cid
}; };
await _sendMail(list, email, 'unsubscription_confirmed', lang, 'subscription.unsubscriptionConfirmed', relativeUrls, subscription); await _sendMail(list, email, 'unsubscription_confirmed', lang, tMark('subscription.unsubscriptionConfirmed'), relativeUrls, subscription);
} }
function getDisplayName(flds, subscription) { function getDisplayName(flds, subscription) {
@ -148,7 +148,7 @@ async function _sendMail(list, email, template, language, subjectKey, relativeUr
name: getDisplayName(flds, subscription), name: getDisplayName(flds, subscription),
address: email address: email
}, },
subject: tUI(language, subjectKey, { list: list.name }), subject: tUI(subjectKey, language, { list: list.name }),
encryptionKeys encryptionKeys
}, { }, {
html, html,

View file

@ -93,7 +93,7 @@ async function validateEmail(address) {
function validateEmailGetMessage(result, address, language) { function validateEmailGetMessage(result, address, language) {
let t; let t;
if (language) { if (language) {
t = (key, args) => tUI(language, key, args); t = (key, args) => tUI(key, language, args);
} else { } else {
t = (key, args) => tLog(key, args); t = (key, args) => tLog(key, args);
} }

View file

@ -34,7 +34,7 @@ function tLog(key, args) {
return JSON.stringify([key, args]); return JSON.stringify([key, args]);
} }
function tUI(lang, key, args) { function tUI(key, lang, args) {
if (!args) { if (!args) {
args = {}; args = {};
} }
@ -42,5 +42,10 @@ function tUI(lang, key, args) {
return i18n.t(key, { ...args, defaultValue, lng: lang }); return i18n.t(key, { ...args, defaultValue, lng: lang });
} }
function tMark(key) {
return key;
}
module.exports.tLog = tLog; module.exports.tLog = tLog;
module.exports.tUI = tUI; module.exports.tUI = tUI;
module.exports.tMark = tMark;

View file

@ -2,7 +2,7 @@
const config = require('config'); const config = require('config');
const urllib = require('url'); const urllib = require('url');
const {anonymousRestrictedAccessToken} = require('../shared/urls'); const {anonymousRestrictedAccessToken} = require('../../shared/urls');
function getTrustedUrlBase() { function getTrustedUrlBase() {
return urllib.resolve(config.www.trustedUrlBase, ''); return urllib.resolve(config.www.trustedUrlBase, '');

View file

@ -3,17 +3,17 @@
const knex = require('../lib/knex'); const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shortid = require('shortid'); const shortid = require('shortid');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const shares = require('./shares'); const shares = require('./shares');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const files = require('./files'); const files = require('./files');
const templates = require('./templates'); const templates = require('./templates');
const { CampaignStatus, CampaignSource, CampaignType, getSendConfigurationPermissionRequiredForSend} = require('../shared/campaigns'); const { CampaignStatus, CampaignSource, CampaignType, getSendConfigurationPermissionRequiredForSend} = require('../../shared/campaigns');
const sendConfigurations = require('./send-configurations'); const sendConfigurations = require('./send-configurations');
const triggers = require('./triggers'); const triggers = require('./triggers');
const {SubscriptionStatus} = require('../shared/lists'); const {SubscriptionStatus} = require('../../shared/lists');
const subscriptions = require('./subscriptions'); const subscriptions = require('./subscriptions');
const segments = require('./segments'); const segments = require('./segments');
const senders = require('../lib/senders'); const senders = require('../lib/senders');

View file

@ -5,17 +5,17 @@ const hasher = require('node-object-hash')();
const slugify = require('slugify'); const slugify = require('slugify');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const validators = require('../shared/validators'); const validators = require('../../shared/validators');
const shortid = require('shortid'); const shortid = require('shortid');
const segments = require('./segments'); const segments = require('./segments');
const { formatDate, formatBirthday, parseDate, parseBirthday } = require('../shared/date'); const { formatDate, formatBirthday, parseDate, parseBirthday } = require('../../shared/date');
const { getFieldColumn } = require('../shared/lists'); const { getFieldColumn } = require('../../shared/lists');
const { cleanupFromPost } = require('../lib/helpers'); const { cleanupFromPost } = require('../lib/helpers');
const Handlebars = require('handlebars'); const Handlebars = require('handlebars');
const { getTrustedUrl, getSandboxUrl, getPublicUrl } = require('../lib/urls'); const { getTrustedUrl, getSandboxUrl, getPublicUrl } = require('../lib/urls');
const { getMergeTagsForBases } = require('../shared/templates'); const { getMergeTagsForBases } = require('../../shared/templates');
const allowedKeysCreate = new Set(['name', 'key', 'default_value', 'type', 'group', 'settings']); const allowedKeysCreate = new Set(['name', 'key', 'default_value', 'type', 'group', 'settings']);

View file

@ -6,7 +6,7 @@ const dtHelpers = require('../lib/dt-helpers');
const shares = require('./shares'); const shares = require('./shares');
const fs = require('fs-extra-promise'); const fs = require('fs-extra-promise');
const path = require('path'); const path = require('path');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const entitySettings = require('../lib/entity-settings'); const entitySettings = require('../lib/entity-settings');
const {getPublicUrl} = require('../lib/urls'); const {getPublicUrl} = require('../lib/urls');

View file

@ -4,7 +4,7 @@ const knex = require('../lib/knex');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const bluebird = require('bluebird'); const bluebird = require('bluebird');

View file

@ -3,7 +3,7 @@
const knex = require('../lib/knex'); const knex = require('../lib/knex');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
async function getById(context, listId, importId, id) { async function getById(context, listId, importId, id) {

View file

@ -4,9 +4,9 @@ const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const {ImportSource, MappingType, ImportStatus, RunStatus, prepFinished, prepFinishedAndNotInProgress, runInProgress} = require('../shared/imports'); const {ImportSource, MappingType, ImportStatus, RunStatus, prepFinished, prepFinishedAndNotInProgress, runInProgress} = require('../../shared/imports');
const fs = require('fs-extra-promise'); const fs = require('fs-extra-promise');
const path = require('path'); const path = require('path');
const importer = require('../lib/importer'); const importer = require('../lib/importer');

View file

@ -5,7 +5,7 @@ const hasher = require('node-object-hash')();
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const shortid = require('shortid'); const shortid = require('shortid');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const fields = require('./fields'); const fields = require('./fields');
@ -14,7 +14,7 @@ const imports = require('./imports');
const entitySettings = require('../lib/entity-settings'); const entitySettings = require('../lib/entity-settings');
const dependencyHelpers = require('../lib/dependency-helpers'); const dependencyHelpers = require('../lib/dependency-helpers');
const UnsubscriptionMode = require('../shared/lists').UnsubscriptionMode; const UnsubscriptionMode = require('../../shared/lists').UnsubscriptionMode;
const allowedKeys = new Set(['name', 'description', 'default_form', 'public_subscribe', 'unsubscription_mode', 'contact_email', 'homepage', 'namespace', 'to_name', 'listunsubscribe_disabled']); const allowedKeys = new Set(['name', 'description', 'default_form', 'public_subscribe', 'unsubscription_mode', 'contact_email', 'homepage', 'namespace', 'to_name', 'listunsubscribe_disabled']);

View file

@ -4,7 +4,7 @@ const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const shares = require('./shares'); const shares = require('./shares');
const files = require('./files'); const files = require('./files');

View file

@ -3,7 +3,7 @@
const knex = require('../lib/knex'); const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const entitySettings = require('../lib/entity-settings'); const entitySettings = require('../lib/entity-settings');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');

View file

@ -4,7 +4,7 @@ const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const shares = require('./shares'); const shares = require('./shares');
const reports = require('./reports'); const reports = require('./reports');

View file

@ -4,14 +4,14 @@ const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const fields = require('./fields'); const fields = require('./fields');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const shares = require('./shares'); const shares = require('./shares');
const reportHelpers = require('../lib/report-helpers'); const reportHelpers = require('../lib/report-helpers');
const fs = require('fs-extra-promise'); const fs = require('fs-extra-promise');
const ReportState = require('../shared/reports').ReportState; const ReportState = require('../../shared/reports').ReportState;
const allowedKeys = new Set(['name', 'description', 'report_template', 'params', 'namespace']); const allowedKeys = new Set(['name', 'description', 'report_template', 'params', 'namespace']);

View file

@ -2,7 +2,7 @@
const knex = require('../lib/knex'); const knex = require('../lib/knex');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
@ -11,7 +11,7 @@ const fields = require('./fields');
const subscriptions = require('./subscriptions'); const subscriptions = require('./subscriptions');
const dependencyHelpers = require('../lib/dependency-helpers'); const dependencyHelpers = require('../lib/dependency-helpers');
const { parseDate, parseBirthday, DateFormat } = require('../shared/date'); const { parseDate, parseBirthday, DateFormat } = require('../../shared/date');
const allowedKeys = new Set(['name', 'settings']); const allowedKeys = new Set(['name', 'settings']);

View file

@ -5,10 +5,10 @@ const hasher = require('node-object-hash')();
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const shortid = require('shortid'); const shortid = require('shortid');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const {MailerType, getSystemSendConfigurationId} = require('../shared/send-configurations'); const {MailerType, getSystemSendConfigurationId} = require('../../shared/send-configurations');
const contextHelpers = require('../lib/context-helpers'); const contextHelpers = require('../lib/context-helpers');
const mailers = require('../lib/mailers'); const mailers = require('../lib/mailers');
const senders = require('../lib/senders'); const senders = require('../lib/senders');

View file

@ -5,10 +5,10 @@ const config = require('config');
const { enforce } = require('../lib/helpers'); 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('../lib/log');
const {getGlobalNamespaceId} = require('../shared/namespaces'); const {getGlobalNamespaceId} = require('../../shared/namespaces');
const {getAdminId} = require('../shared/users'); const {getAdminId} = require('../../shared/users');
// TODO: This would really benefit from some permission cache connected to rebuildPermissions // TODO: This would really benefit from some permission cache connected to rebuildPermissions
// A bit of the problem is that the cache would have to expunged as the result of other processes modifying entites/permissions // A bit of the problem is that the cache would have to expunged as the result of other processes modifying entites/permissions

View file

@ -4,14 +4,14 @@ const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const shortid = require('shortid'); const shortid = require('shortid');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const fields = require('./fields'); const fields = require('./fields');
const { SubscriptionStatus, getFieldColumn } = require('../shared/lists'); const { SubscriptionStatus, getFieldColumn } = require('../../shared/lists');
const segments = require('./segments'); const segments = require('./segments');
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const moment = require('moment'); const moment = require('moment');
const { formatDate, formatBirthday } = require('../shared/date'); const { formatDate, formatBirthday } = require('../../shared/date');
const crypto = require('crypto'); const crypto = require('crypto');
const campaigns = require('./campaigns'); const campaigns = require('./campaigns');
const lists = require('./lists'); const lists = require('./lists');

View file

@ -4,7 +4,7 @@ const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const namespaceHelpers = require('../lib/namespace-helpers'); const namespaceHelpers = require('../lib/namespace-helpers');
const shares = require('./shares'); const shares = require('./shares');
const reports = require('./reports'); const reports = require('./reports');

View file

@ -4,9 +4,9 @@ const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const shares = require('./shares'); const shares = require('./shares');
const {EntityVals, EventVals, Entity} = require('../shared/triggers'); const {EntityVals, EventVals, Entity} = require('../../shared/triggers');
const campaigns = require('./campaigns'); const campaigns = require('./campaigns');
const allowedKeys = new Set(['name', 'description', 'entity', 'event', 'seconds', 'enabled', 'source_campaign']); const allowedKeys = new Set(['name', 'description', 'entity', 'event', 'seconds', 'enabled', 'source_campaign']);

View file

@ -4,8 +4,8 @@ const config = require('config');
const knex = require('../lib/knex'); const knex = require('../lib/knex');
const hasher = require('node-object-hash')(); const hasher = require('node-object-hash')();
const { enforce, filterObject } = require('../lib/helpers'); const { enforce, filterObject } = require('../lib/helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const passwordValidator = require('../shared/password-validator')(); const passwordValidator = require('../../shared/password-validator')();
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const tools = require('../lib/tools'); const tools = require('../lib/tools');
const crypto = require('crypto'); const crypto = require('crypto');
@ -310,7 +310,7 @@ async function sendPasswordReset(language, usernameOrEmail) {
to: { to: {
address: user.email address: user.email
}, },
subject: tUI(language, 'account.passwordChangeRequest') subject: tUI('account.passwordChangeRequest', language)
}, { }, {
html: 'emails/password-reset-html.hbs', html: 'emails/password-reset-html.hbs',
text: 'emails/password-reset-text.hbs', text: 'emails/password-reset-text.hbs',

View file

@ -907,11 +907,6 @@
} }
} }
}, },
"brorand": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
},
"browser-process-hrtime": { "browser-process-hrtime": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
@ -1325,24 +1320,6 @@
} }
} }
}, },
"compressjs": {
"version": "github:openpgpjs/compressjs#bfbb371a34d1750afa34bfa49156461acdab79a9",
"from": "github:openpgpjs/compressjs",
"requires": {
"amdefine": "~1.0.0",
"commander": "~2.8.1"
},
"dependencies": {
"commander": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"requires": {
"graceful-readlink": ">= 1.0.0"
}
}
}
},
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -1888,19 +1865,6 @@
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
}, },
"elliptic": {
"version": "github:openpgpjs/elliptic#e187e706e11fa51bcd20e46e5119054be4e2a4a6",
"from": "github:openpgpjs/elliptic",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
}
},
"email-addresses": { "email-addresses": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.0.1.tgz", "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.0.1.tgz",
@ -2906,11 +2870,13 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true "bundled": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -2923,15 +2889,18 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -3034,7 +3003,8 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true "bundled": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -3044,6 +3014,7 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -3056,17 +3027,20 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true "bundled": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.2.4", "version": "2.2.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -3083,6 +3057,7 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -3155,7 +3130,8 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -3165,6 +3141,7 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -3270,6 +3247,7 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -3569,11 +3547,6 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
}, },
"graceful-readlink": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
},
"growl": { "growl": {
"version": "1.10.5", "version": "1.10.5",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
@ -3959,16 +3932,6 @@
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
}, },
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
"requires": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.1"
}
},
"homedir-polyfill": { "homedir-polyfill": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
@ -5415,11 +5378,6 @@
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
}, },
"minimalistic-crypto-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
},
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@ -6271,6 +6229,35 @@
"ieee754": "^1.1.4" "ieee754": "^1.1.4"
} }
}, },
"commander": {
"version": "2.8.1",
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"requires": {
"graceful-readlink": ">= 1.0.0"
}
},
"compressjs": {
"version": "github:openpgpjs/compressjs#bfbb371a34d1750afa34bfa49156461acdab79a9",
"from": "github:openpgpjs/compressjs#bfbb371a34d1750afa34bfa49156461acdab79a9",
"requires": {
"amdefine": "~1.0.0",
"commander": "~2.8.1"
}
},
"elliptic": {
"version": "github:openpgpjs/elliptic#e187e706e11fa51bcd20e46e5119054be4e2a4a6",
"from": "github:openpgpjs/elliptic#e187e706e11fa51bcd20e46e5119054be4e2a4a6",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
}
},
"openpgp": { "openpgp": {
"version": "3.0.11", "version": "3.0.11",
"resolved": "https://registry.npmjs.org/openpgp/-/openpgp-3.0.11.tgz", "resolved": "https://registry.npmjs.org/openpgp/-/openpgp-3.0.11.tgz",
@ -6281,8 +6268,6 @@
"asn1.js": "^5.0.0", "asn1.js": "^5.0.0",
"bn.js": "^4.11.8", "bn.js": "^4.11.8",
"buffer": "^5.0.8", "buffer": "^5.0.8",
"compressjs": "github:openpgpjs/compressjs#bfbb371a34d1750afa34bfa49156461acdab79a9",
"elliptic": "github:openpgpjs/elliptic#e187e706e11fa51bcd20e46e5119054be4e2a4a6",
"hash.js": "^1.1.3", "hash.js": "^1.1.3",
"node-fetch": "^1.7.3", "node-fetch": "^1.7.3",
"node-localstorage": "~1.3.0", "node-localstorage": "~1.3.0",
@ -7466,22 +7451,18 @@
"requires": { "requires": {
"@mattiasbuelens/web-streams-polyfill": "0.1.0-alpha.4", "@mattiasbuelens/web-streams-polyfill": "0.1.0-alpha.4",
"address-rfc2822": "^2.0.3", "address-rfc2822": "^2.0.3",
"asmcrypto.js": "github:openpgpjs/asmcrypto#6e4e407b9b8ae317925a9e677cc7b4de3e447e83",
"asn1.js": "^5.0.0", "asn1.js": "^5.0.0",
"bn.js": "^4.11.8", "bn.js": "^4.11.8",
"buffer": "^5.0.8", "buffer": "^5.0.8",
"elliptic": "github:openpgpjs/elliptic#e187e706e11fa51bcd20e46e5119054be4e2a4a6",
"hash.js": "^1.1.3", "hash.js": "^1.1.3",
"node-fetch": "^2.1.2", "node-fetch": "^2.1.2",
"node-localstorage": "~1.3.0", "node-localstorage": "~1.3.0",
"pako": "^1.0.6", "pako": "^1.0.6"
"seek-bzip": "github:openpgpjs/seek-bzip#3aca608ffedc055a1da1d898ecb244804ef32209",
"web-stream-tools": "github:openpgpjs/web-stream-tools#9ab800d46add161db496506d67338202ad0114ce"
}, },
"dependencies": { "dependencies": {
"asmcrypto.js": { "asmcrypto.js": {
"version": "github:openpgpjs/asmcrypto#6e4e407b9b8ae317925a9e677cc7b4de3e447e83", "version": "github:openpgpjs/asmcrypto#6e4e407b9b8ae317925a9e677cc7b4de3e447e83",
"from": "github:openpgpjs/asmcrypto" "from": "github:openpgpjs/asmcrypto#6e4e407b9b8ae317925a9e677cc7b4de3e447e83"
}, },
"buffer": { "buffer": {
"version": "5.2.1", "version": "5.2.1",
@ -7492,10 +7473,42 @@
"ieee754": "^1.1.4" "ieee754": "^1.1.4"
} }
}, },
"commander": {
"version": "2.8.1",
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"requires": {
"graceful-readlink": ">= 1.0.0"
}
},
"elliptic": {
"version": "github:openpgpjs/elliptic#e187e706e11fa51bcd20e46e5119054be4e2a4a6",
"from": "github:openpgpjs/elliptic#e187e706e11fa51bcd20e46e5119054be4e2a4a6",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
}
},
"node-fetch": { "node-fetch": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz",
"integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA=="
},
"seek-bzip": {
"version": "github:openpgpjs/seek-bzip#3aca608ffedc055a1da1d898ecb244804ef32209",
"from": "github:openpgpjs/seek-bzip#3aca608ffedc055a1da1d898ecb244804ef32209",
"requires": {
"commander": "~2.8.1"
}
},
"web-stream-tools": {
"version": "github:openpgpjs/web-stream-tools#9ab800d46add161db496506d67338202ad0114ce",
"from": "github:openpgpjs/web-stream-tools#9ab800d46add161db496506d67338202ad0114ce"
} }
} }
}, },
@ -8354,23 +8367,6 @@
"xmlchars": "^1.3.1" "xmlchars": "^1.3.1"
} }
}, },
"seek-bzip": {
"version": "github:openpgpjs/seek-bzip#3aca608ffedc055a1da1d898ecb244804ef32209",
"from": "github:openpgpjs/seek-bzip",
"requires": {
"commander": "~2.8.1"
},
"dependencies": {
"commander": {
"version": "2.8.1",
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"requires": {
"graceful-readlink": ">= 1.0.0"
}
}
}
},
"selenium-webdriver": { "selenium-webdriver": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz",
@ -9420,10 +9416,6 @@
} }
} }
}, },
"web-stream-tools": {
"version": "github:openpgpjs/web-stream-tools#9ab800d46add161db496506d67338202ad0114ce",
"from": "github:openpgpjs/web-stream-tools"
},
"webidl-conversions": { "webidl-conversions": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",

View file

@ -2,10 +2,9 @@
"name": "mailtrain", "name": "mailtrain",
"private": true, "private": true,
"version": "2.0.0", "version": "2.0.0",
"description": "Self hosted email newsletter app", "description": "Self hosted email newsletter app - server",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "grunt",
"start": "node index.js", "start": "node index.js",
"sqlinit": "node setup/sql/init.js", "sqlinit": "node setup/sql/init.js",
"sqldump": "node setup/sql/dump.js | sed -e '/^\\/\\*.*\\*\\/;$/d' -e 's/.[0-9]\\{4\\}-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]./NOW()/g' > setup/sql/mailtrain${DUMP_NAME_SUFFIX}.sql", "sqldump": "node setup/sql/dump.js | sed -e '/^\\/\\*.*\\*\\/;$/d' -e 's/.[0-9]\\{4\\}-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]./NOW()/g' > setup/sql/mailtrain${DUMP_NAME_SUFFIX}.sql",

View file

@ -5,13 +5,13 @@ const lists = require('../models/lists');
const tools = require('../lib/tools'); const tools = require('../lib/tools');
const blacklist = require('../models/blacklist'); const blacklist = require('../models/blacklist');
const fields = require('../models/fields'); const fields = require('../models/fields');
const { SubscriptionStatus, SubscriptionSource } = require('../shared/lists'); const { SubscriptionStatus, SubscriptionSource } = require('../../shared/lists');
const subscriptions = require('../models/subscriptions'); const subscriptions = require('../models/subscriptions');
const confirmations = require('../models/confirmations'); const confirmations = require('../models/confirmations');
const log = require('../lib/log'); const log = require('../lib/log');
const router = require('../lib/router-async').create(); const router = require('../lib/router-async').create();
const mailHelpers = require('../lib/subscription-mail-helpers'); const mailHelpers = require('../lib/subscription-mail-helpers');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const contextHelpers = require('../lib/context-helpers'); const contextHelpers = require('../lib/context-helpers');
const shares = require('../models/shares'); const shares = require('../models/shares');
const slugify = require('slugify'); const slugify = require('slugify');

View file

@ -4,7 +4,7 @@ const passport = require('../lib/passport');
const _ = require('../lib/translate')._; const _ = require('../lib/translate')._;
const clientHelpers = require('../lib/client-helpers'); const clientHelpers = require('../lib/client-helpers');
const { getTrustedUrl } = require('../lib/urls'); const { getTrustedUrl } = require('../lib/urls');
const { AppType } = require('../shared/app'); const { AppType } = require('../../shared/app');
const routerFactory = require('../lib/router-async'); const routerFactory = require('../lib/router-async');

View file

@ -4,7 +4,7 @@ const log = require('../lib/log');
const config = require('config'); const config = require('config');
const router = require('../lib/router-async').create(); const router = require('../lib/router-async').create();
const links = require('../models/links'); const links = require('../models/links');
const interoperableErrors = require('../shared/interoperable-errors'); const interoperableErrors = require('../../shared/interoperable-errors');
const trackImg = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64'); const trackImg = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64');

Some files were not shown because too many files have changed in this diff Show more