Merge branch 'development' of github.com:Mailtrain-org/mailtrain into development
This commit is contained in:
commit
c44ed4f7fa
33 changed files with 1492 additions and 242 deletions
|
@ -1 +1,9 @@
|
|||
node_modules
|
||||
node_modules/
|
||||
docs/
|
||||
Dockerfile
|
||||
*.md
|
||||
.git
|
||||
.gitignore
|
||||
.gitmodules
|
||||
docker-compose.yml
|
||||
docker-compose-local.yml
|
35
Dockerfile
35
Dockerfile
|
@ -1,8 +1,12 @@
|
|||
FROM node:10.14-alpine
|
||||
# Mutistaged Node.js Build
|
||||
FROM node:10-alpine as builder
|
||||
|
||||
RUN apk add --update pwgen netcat-openbsd python make gcc git g++ bash imagemagick
|
||||
# Install system dependencies
|
||||
RUN set -ex; \
|
||||
apk add --update --no-cache \
|
||||
make gcc g++ git python
|
||||
|
||||
# First install dependencies
|
||||
# Copy package.json dependencies
|
||||
COPY server/package.json /app/server/package.json
|
||||
COPY server/package-lock.json /app/server/package-lock.json
|
||||
COPY client/package.json /app/client/package.json
|
||||
|
@ -12,15 +16,32 @@ COPY shared/package-lock.json /app/shared/package-lock.json
|
|||
COPY zone-mta/package.json /app/zone-mta/package.json
|
||||
COPY zone-mta/package-lock.json /app/zone-mta/package-lock.json
|
||||
|
||||
WORKDIR /app/
|
||||
|
||||
RUN for idx in client shared server zone-mta; do (cd $idx && npm install); done
|
||||
# Install dependencies in each directory
|
||||
RUN cd /app/client && npm install
|
||||
RUN cd /app/shared && npm install --production
|
||||
RUN cd /app/server && npm install --production
|
||||
RUN cd /app/zone-mta && npm install --production
|
||||
|
||||
# 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
|
||||
COPY . /app
|
||||
|
||||
RUN cd client && npm run build
|
||||
RUN set -ex; \
|
||||
cd /app/client && \
|
||||
npm run build && \
|
||||
rm -rf node_modules
|
||||
|
||||
# Final Image
|
||||
FROM node:10-alpine
|
||||
|
||||
WORKDIR /app/
|
||||
|
||||
# Install system dependencies
|
||||
RUN set -ex; \
|
||||
apk add --update --no-cache \
|
||||
pwgen netcat-openbsd bash imagemagick
|
||||
|
||||
COPY --from=builder /app/ /app/
|
||||
|
||||
EXPOSE 3000 3003 3004
|
||||
ENTRYPOINT ["bash", "/app/docker-entrypoint.sh"]
|
||||
|
|
28
README.md
28
README.md
|
@ -193,17 +193,35 @@ These are the steps to start Mailtrain via docker-compose:
|
|||
docker-compose up
|
||||
```
|
||||
|
||||
You can specify Mailtrain's URL bases via the `MAILTRAIN_SETTINGS` environment variable as follows. The `--withProxy` parameter is to be used when Mailtrain is put behind a reverse proxy.
|
||||
```
|
||||
MAILTRAIN_SETTINGS="--trustedUrlBase https://mailtrain.example.com --sandboxUrlBase https://sbox.mailtrain.example.com --publicUrlBase https://lists.example.com --withProxy" docker-compose up
|
||||
```
|
||||
|
||||
3. Open the trusted endpoint http://localhost:3000
|
||||
|
||||
4. Authenticate as `admin`:`test`
|
||||
|
||||
The instructions above use an automatically built Docker image on DockerHub (https://hub.docker.com/r/mailtrain/mailtrain). If you want to build the Docker image yourself (e.g. when doing development), use the `docker-compose-local.yml` located in the project's root directory.
|
||||
|
||||
### Docker Environment Variables
|
||||
|
||||
| Parameter | Description |
|
||||
| --------- | ----------- |
|
||||
| URL_BASE_TRUSTED | sets the trusted url of the instance (default: http://localhost:3000) |
|
||||
| URL_BASE_SANDBOX | sets the sandbox url of the instance (default: http://localhost:3003) |
|
||||
| URL_BASE_PUBLIC | sets the public url of the instance (default: http://localhost:3004) |
|
||||
| WITH_PROXY | use if Mailtrain is behind an http reverse proxy |
|
||||
| MONGO_HOST | sets mongo host (default: mongo) |
|
||||
| REDIS_HOST | sets redis host (default: redis) |
|
||||
| MYSQL_HOST | sets mysql host (default: mysql) |
|
||||
| MYSQL_DATABASE | sets mysql database (default: mailtrain) |
|
||||
| MYSQL_USER | sets mysql user (default: mailtrain) |
|
||||
| MYSQL_PASSWORD | sets mysql password (default: mailtrain) |
|
||||
| WITH_LDAP | use if you want to enable LDAP authentication |
|
||||
| LDAP_HOST | LDAP Host for authentication (default: ldap) |
|
||||
| LDAP_PORT | LDAP port (default: 389) |
|
||||
| LDAP_SECURE | use if you want to use LDAP with ldaps protocol |
|
||||
| LDAP_BIND_USER | User for LDAP connexion |
|
||||
| LDAP_BIND_PASS | Password for LDAP connexion |
|
||||
| LDAP_FILTER | LDAP filter |
|
||||
| LDAP_BASEDN | LDAP base DN |
|
||||
| LDAP_UIDTAG | LDAP UID tag (e.g. uid/cn/username) |
|
||||
|
||||
## License
|
||||
|
||||
|
|
234
client/package-lock.json
generated
234
client/package-lock.json
generated
|
@ -2013,6 +2013,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
|
||||
"integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
|
@ -2121,6 +2127,21 @@
|
|||
"integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
|
||||
"dev": true
|
||||
},
|
||||
"array-union": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
||||
"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-uniq": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"array-uniq": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
|
||||
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
|
||||
"dev": true
|
||||
},
|
||||
"array-unique": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
|
||||
|
@ -3285,6 +3306,143 @@
|
|||
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
|
||||
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
|
||||
},
|
||||
"copy-webpack-plugin": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.5.tgz",
|
||||
"integrity": "sha512-7N68eIoQTyudAuxkfPT7HzGoQ+TsmArN/I3HFwG+lVE3FNzqvZKIiaxtYh4o3BIznioxUvx9j26+Rtsc9htQUQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^12.0.3",
|
||||
"find-cache-dir": "^2.1.0",
|
||||
"glob-parent": "^3.1.0",
|
||||
"globby": "^7.1.1",
|
||||
"is-glob": "^4.0.1",
|
||||
"loader-utils": "^1.2.3",
|
||||
"minimatch": "^3.0.4",
|
||||
"normalize-path": "^3.0.0",
|
||||
"p-limit": "^2.2.1",
|
||||
"schema-utils": "^1.0.0",
|
||||
"serialize-javascript": "^2.1.0",
|
||||
"webpack-log": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"cacache": {
|
||||
"version": "12.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
|
||||
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.5.5",
|
||||
"chownr": "^1.1.1",
|
||||
"figgy-pudding": "^3.5.1",
|
||||
"glob": "^7.1.4",
|
||||
"graceful-fs": "^4.1.15",
|
||||
"infer-owner": "^1.0.3",
|
||||
"lru-cache": "^5.1.1",
|
||||
"mississippi": "^3.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"move-concurrently": "^1.0.1",
|
||||
"promise-inflight": "^1.0.1",
|
||||
"rimraf": "^2.6.3",
|
||||
"ssri": "^6.0.1",
|
||||
"unique-filename": "^1.1.1",
|
||||
"y18n": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^3.1.0",
|
||||
"path-dirname": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-glob": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
|
||||
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
|
||||
"integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.0.tgz",
|
||||
"integrity": "sha512-a/mxFfU00QT88umAJQsNWOnUKckhNCqOl028N48e7wFmo2/EHpTo9Wso+iJJCMrQnmFvcjto5RJdAHEvVhcyUQ==",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz",
|
||||
|
@ -3645,6 +3803,32 @@
|
|||
"randombytes": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
|
||||
"integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-type": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"path-type": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pify": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"dnd-core": {
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-7.7.0.tgz",
|
||||
|
@ -5262,6 +5446,34 @@
|
|||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
|
||||
"dev": true
|
||||
},
|
||||
"globby": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
|
||||
"integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^1.0.1",
|
||||
"dir-glob": "^2.0.0",
|
||||
"glob": "^7.1.2",
|
||||
"ignore": "^3.3.5",
|
||||
"pify": "^3.0.0",
|
||||
"slash": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
},
|
||||
"slash": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
||||
"integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"globule": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
|
||||
|
@ -5614,6 +5826,12 @@
|
|||
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
||||
"dev": true
|
||||
},
|
||||
"ignore": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
|
||||
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
|
||||
"dev": true
|
||||
},
|
||||
"ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
|
@ -5673,6 +5891,12 @@
|
|||
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
|
||||
"dev": true
|
||||
},
|
||||
"infer-owner": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
|
||||
"integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
|
||||
"dev": true
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
|
@ -12169,6 +12393,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"webpack-log": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
|
||||
"integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-colors": "^3.0.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"webpack-sources": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz",
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"clean-css-cli": "^4.2.1",
|
||||
"copy-webpack-plugin": "^5.0.5",
|
||||
"css-loader": "^2.1.0",
|
||||
"file-loader": "^3.0.1",
|
||||
"node-sass": "^4.12.0",
|
||||
|
|
|
@ -292,8 +292,8 @@ export default class API extends Component {
|
|||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/blacklist/add?access_token={accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com&'</pre>
|
||||
<pre>curl -XPOST '{getUrl(`api/blacklist/add?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com'</pre>
|
||||
|
||||
<h4>POST /api/blacklist/delete – {t('deleteEmailFromBlacklist')}</h4>
|
||||
|
||||
|
@ -320,7 +320,7 @@ export default class API extends Component {
|
|||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/blacklist/delete?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com&'</pre>
|
||||
--data 'EMAIL=test@example.com'</pre>
|
||||
|
||||
<h4>GET /api/lists/:email – {t('getTheListsAUserHasSubscribedTo')}</h4>
|
||||
|
||||
|
|
|
@ -401,7 +401,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
if (!state.getIn(['data_sourceCustom_tag_language', 'value'])) {
|
||||
state.setIn(['data_sourceCustom_tag_language', 'error'], t('Tag language must be selected'));
|
||||
state.setIn(['data_sourceCustom_tag_language', 'error'], t('tagLanguageMustBeSelected'));
|
||||
}
|
||||
|
||||
if (customTemplateTypeKey) {
|
||||
|
@ -732,7 +732,7 @@ export default class CUD extends Component {
|
|||
|
||||
templateEdit = <div>
|
||||
<Dropdown id="data_sourceCustom_type" label={t('type')} options={this.customTemplateTypeOptions}/>
|
||||
<Dropdown id="data_sourceCustom_tag_language" label={t('Tag language')} options={this.customTemplateTagLanguageOptions} disabled={isEdit}/>
|
||||
<Dropdown id="data_sourceCustom_tag_language" label={t('tagLanguage')} options={this.customTemplateTagLanguageOptions} disabled={isEdit}/>
|
||||
|
||||
{customTemplateTypeForm}
|
||||
</div>;
|
||||
|
|
|
@ -131,7 +131,7 @@ export default class CustomContent extends Component {
|
|||
const t = this.props.t;
|
||||
|
||||
if (!state.getIn(['data_sourceCustom_tag_language', 'value'])) {
|
||||
state.setIn(['data_sourceCustom_tag_language', 'error'], t('Tag language must be selected'));
|
||||
state.setIn(['data_sourceCustom_tag_language', 'error'], t('tagLanguageMustBeSelected'));
|
||||
} else {
|
||||
state.setIn(['data_sourceCustom_tag_language', 'error'], null);
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ export default class CustomContent extends Component {
|
|||
{customTemplateTypeKey && this.templateTypes[customTemplateTypeKey].typeName}
|
||||
</StaticField>
|
||||
|
||||
<Dropdown id="data_sourceCustom_tag_language" label={t('Tag language')} options={this.customTemplateTagLanguageOptions} disabled={true}/>
|
||||
<Dropdown id="data_sourceCustom_tag_language" label={t('tagLanguage')} options={this.customTemplateTagLanguageOptions} disabled={true}/>
|
||||
|
||||
{customTemplateTypeKey && getTypeForm(this, customTemplateTypeKey, true)}
|
||||
|
||||
|
|
|
@ -12,12 +12,13 @@ import {createComponentMixin} from "./decorator-helpers";
|
|||
import lang_en_US_common from "../../../locales/en-US/common";
|
||||
import lang_es_ES_common from "../../../locales/es-ES/common";
|
||||
import lang_pt_BR_common from "../../../locales/pt-BR/common";
|
||||
|
||||
import lang_de_DE_common from "../../../locales/de-DE/common";
|
||||
|
||||
const resourcesCommon = {
|
||||
'en-US': lang_en_US_common,
|
||||
'es-ES': lang_es_ES_common,
|
||||
'pt-BR': lang_pt_BR_common,
|
||||
'de-DE': lang_de_DE_common,
|
||||
'fk-FK': convertToFake(lang_en_US_common)
|
||||
};
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ export default class CUD extends Component {
|
|||
const label = matches[2].trim();
|
||||
options.push({ key, label });
|
||||
} else {
|
||||
errors.push(t('errrorOnLineLine', { line: lineIdx + 1}));
|
||||
errors.push(t('errorOnLineLine', { line: lineIdx + 1}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ export default class CUD extends Component {
|
|||
|
||||
<InputField id="key" label={t('mergeTag-1')}/>
|
||||
|
||||
<TextArea id="help" label={t('Help text')}/>
|
||||
<TextArea id="help" label={t('helpText')}/>
|
||||
|
||||
{fieldSettings}
|
||||
|
||||
|
|
|
@ -291,7 +291,7 @@ export function getMailerTypes(t) {
|
|||
<Fieldset label={t('mailerSettings')}>
|
||||
<Dropdown id="mailer_type" label={t('mailerType')} options={typeOptions}/>
|
||||
<InputField id="sesKey" label={t('accessKey')} placeholder={t('awsAccessKeyId')}/>
|
||||
<InputField id="sesSecret" label={t('port')} placeholder={t('awsSecretAccessKey')}/>
|
||||
<InputField id="sesSecret" label={t('accessSecret')} placeholder={t('awsSecretAccessKey')} type="password"/>
|
||||
<Dropdown id="sesRegion" label={t('region')} options={sesRegionOptions}/>
|
||||
</Fieldset>
|
||||
<Fieldset label={t('advancedMailerSettings')}>
|
||||
|
|
|
@ -171,7 +171,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
if (!state.getIn(['tag_language', 'value'])) {
|
||||
state.setIn(['tag_language', 'error'], t('Tag language must be selected'));
|
||||
state.setIn(['tag_language', 'error'], t('tagLanguageMustBeSelected'));
|
||||
}
|
||||
|
||||
if (typeKey) {
|
||||
|
@ -320,7 +320,7 @@ export default class CUD extends Component {
|
|||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('description') },
|
||||
{ data: 3, title: t('type'), render: data => this.templateTypes[data].typeName },
|
||||
{ data: 4, title: t('Tag language'), render: data => this.tagLanguages[data].name },
|
||||
{ data: 4, title: t('tagLanguage'), render: data => this.tagLanguages[data].name },
|
||||
{ data: 5, title: t('created'), render: data => moment(data).fromNow() },
|
||||
{ data: 6, title: t('namespace') },
|
||||
];
|
||||
|
@ -376,7 +376,7 @@ export default class CUD extends Component {
|
|||
|
||||
{typeForm}
|
||||
|
||||
<Dropdown id="tag_language" label={t('Tag language')} options={tagLanguageOptions} disabled={isEdit}/>
|
||||
<Dropdown id="tag_language" label={t('tagLanguage')} options={tagLanguageOptions} disabled={isEdit}/>
|
||||
</>
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ export default class List extends Component {
|
|||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('description') },
|
||||
{ data: 3, title: t('type'), render: data => this.templateTypes[data].typeName },
|
||||
{ data: 4, title: t('Tag language'), render: data => this.tagLanguages[data].name },
|
||||
{ data: 4, title: t('tagLanguage'), render: data => this.tagLanguages[data].name },
|
||||
{ data: 5, title: t('created'), render: data => moment(data).fromNow() },
|
||||
{ data: 6, title: t('namespace') },
|
||||
{
|
||||
|
|
|
@ -132,7 +132,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
if (!state.getIn(['tag_language', 'value'])) {
|
||||
state.setIn(['tag_language', 'error'], t('Tag language must be selected'));
|
||||
state.setIn(['tag_language', 'error'], t('tagLanguageMustBeSelected'));
|
||||
} else {
|
||||
state.setIn(['tag_language', 'error'], null);
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ export default class CUD extends Component {
|
|||
<Dropdown id="type" label={t('type')} options={this.typeOptions}/>
|
||||
}
|
||||
|
||||
<Dropdown id="tag_language" label={t('Tag language')} options={tagLanguageOptions}/>
|
||||
<Dropdown id="tag_language" label={t('tagLanguage')} options={tagLanguageOptions}/>
|
||||
|
||||
<NamespaceSelect/>
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ export default class List extends Component {
|
|||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('description') },
|
||||
{ data: 3, title: t('type'), render: data => this.templateTypes[data].typeName },
|
||||
{ data: 4, title: t('Tag language'), render: data => this.tagLanguages[data].name },
|
||||
{ data: 4, title: t('tagLanguage'), render: data => this.tagLanguages[data].name },
|
||||
{ data: 5, title: t('created'), render: data => moment(data).fromNow() },
|
||||
{ data: 6, title: t('namespace') },
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const webpack = require('webpack');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
|
@ -97,7 +98,13 @@ module.exports = {
|
|||
mailtrainConfig: 'mailtrainConfig'
|
||||
},
|
||||
plugins: [
|
||||
// new webpack.optimize.UglifyJsPlugin(),
|
||||
new CopyPlugin([
|
||||
{ from: './node_modules/jquery/dist/jquery.min.js', to: path.resolve(__dirname, 'dist') },
|
||||
{ from: './node_modules/popper.js/dist/popper.min.js', to: path.resolve(__dirname, 'dist') },
|
||||
{ from: './node_modules/bootstrap/dist/js/bootstrap.min.js', to: path.resolve(__dirname, 'dist') },
|
||||
{ from: './node_modules/@coreui/coreui/dist/js/coreui.min.js', to: path.resolve(__dirname, 'dist') },
|
||||
{ from: './node_modules/@fortawesome/fontawesome-free/webfonts/', to: path.resolve(__dirname, 'dist', 'webfonts'), toType: 'dir'}
|
||||
]),
|
||||
],
|
||||
watchOptions: {
|
||||
ignored: 'node_modules/',
|
||||
|
|
|
@ -23,7 +23,6 @@ services:
|
|||
|
||||
mailtrain:
|
||||
build: .
|
||||
command: ${MAILTRAIN_SETTINGS}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3003:3003"
|
||||
|
|
|
@ -23,7 +23,6 @@ services:
|
|||
|
||||
mailtrain:
|
||||
image: mailtrain/mailtrain:latest
|
||||
command: ${MAILTRAIN_SETTINGS}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3003:3003"
|
||||
|
|
|
@ -1,201 +1,120 @@
|
|||
#!/bin/bash
|
||||
# Entrypoint for Docker Container
|
||||
|
||||
set -e
|
||||
|
||||
function printHelp {
|
||||
cat <<EOF
|
||||
|
||||
Optional parameters:
|
||||
--trustedUrlBase XXX - sets the trusted url of the instance (default: http://localhost:3000)
|
||||
--sandboxUrlBase XXX - sets the sandbox url of the instance (default: http://localhost:3003)
|
||||
--publicUrlBase XXX - sets the public url of the instance (default: http://localhost:3004)
|
||||
--withProxy - use if Mailtrain is behind an http reverse proxy
|
||||
--mongoHost XXX - sets mongo host (default: mongo)
|
||||
--redisHost XXX - sets redis host (default: redis)
|
||||
--mySqlHost XXX - sets mysql host (default: mysql)
|
||||
--withLdap - use if you want to enable LDAP authentication
|
||||
--ldapHost XXX - LDAP Host for authentication (default: ldap)
|
||||
--ldapPort XXX - LDAP port (default: 389)
|
||||
--ldapSecure - use if you want to use LDAP with ldaps protocol
|
||||
--ldapBindUser XXX - User for LDAP connexion
|
||||
--ldapBindPass XXX - Password for LDAP connexion
|
||||
--ldapFilter XXX - LDAP filter
|
||||
--ldapBaseDN XXX - LDAP base DN
|
||||
--ldapUidTag XXX - LDAP UID tag (e.g. uid/cn/username)
|
||||
EOF
|
||||
URL_BASE_TRUSTED=${URL_BASE_TRUSTED:-'http://localhost:3000'}
|
||||
URL_BASE_SANDBOX=${URL_BASE_SANDBOX:-'http://localhost:3003'}
|
||||
URL_BASE_PUBLIC=${URL_BASE_PUBLIC:-'http://localhost:3004'}
|
||||
WWW_PROXY=${WWW_PROXY:-'false'}
|
||||
WITH_LDAP=${WITH_LDAP:-'false'}
|
||||
LDAP_HOST=${LDAP_HOST:-'ldap'}
|
||||
LDAP_PORT=${LDAP_PORT:-'389'}
|
||||
LDAP_SECURE=${LDAP_SECURE:-'false'}
|
||||
LDAP_BIND_USER=${LDAP_BIND_USER:-}
|
||||
LDAP_BIND_PASS=${LDAP_BIND_PASS:-}
|
||||
LDAP_FILTER=${LDAP_FILTER:-}
|
||||
LDAP_BASEDN=${LDAP_BASEDN:-}
|
||||
LDAP_UIDTAG=${LDAP_UIDTAG:-}
|
||||
MONGO_HOST=${MONG_HOST:-'mongo'}
|
||||
REDIS_HOST=${REDIS_HOST:-'redis'}
|
||||
MYSQL_HOST=${MYSQL_HOST:-'mysql'}
|
||||
MYSQL_DATABASE=${MYSQL_DATABASE:-'mailtrain'}
|
||||
MYSQL_USER=${MYSQL_USER:-'mailtrain'}
|
||||
MYSQL_PASSWORD=${MYSQL_PASSWORD:-'mailtrain'}
|
||||
|
||||
# Warning for users that already rely on the MAILTRAIN_SETTING variable
|
||||
# Can probably be removed in the future.
|
||||
MAILTRAIN_SETTING=${MAILTRAIN_SETTINGS:-}
|
||||
if [ ! -z "$MAILTRAIN_SETTING" ]; then
|
||||
echo 'Error: MAILTRAIN_SETTINGS is no longer supported. See README'
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
urlBaseTrusted=http://localhost:3000
|
||||
urlBaseSandbox=http://localhost:3003
|
||||
urlBasePublic=http://localhost:3004
|
||||
wwwProxy=false
|
||||
withLdap=false
|
||||
ldapHost=ldap
|
||||
ldapPort=389
|
||||
ldapSecure=false
|
||||
ldapBindUser=""
|
||||
ldapBindPass=""
|
||||
ldapFilter=""
|
||||
ldapBaseDN=""
|
||||
ldapUidTag=""
|
||||
mongoHost=mongo
|
||||
redisHost=redis
|
||||
mySqlHost=mysql
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--help)
|
||||
printHelp
|
||||
;;
|
||||
--trustedUrlBase)
|
||||
urlBaseTrusted="$2"
|
||||
shift 2
|
||||
;;
|
||||
--sandboxUrlBase)
|
||||
urlBaseSandbox="$2"
|
||||
shift 2
|
||||
;;
|
||||
--publicUrlBase)
|
||||
urlBasePublic="$2"
|
||||
shift 2
|
||||
;;
|
||||
--withProxy)
|
||||
wwwProxy=true
|
||||
shift 1
|
||||
;;
|
||||
--mongoHost)
|
||||
mongoHost="$2"
|
||||
shift 2
|
||||
;;
|
||||
--redisHost)
|
||||
redisHost="$2"
|
||||
shift 2
|
||||
;;
|
||||
--mySqlHost)
|
||||
mySqlHost="$2"
|
||||
shift 2
|
||||
;;
|
||||
--withLdap)
|
||||
withLdap=true
|
||||
shift 1
|
||||
;;
|
||||
--ldapHost)
|
||||
ldapHost="$2"
|
||||
shift 2
|
||||
;;
|
||||
--ldapPort)
|
||||
ldapPort="$2"
|
||||
shift 2
|
||||
;;
|
||||
--ldapSecure)
|
||||
ldapSecure=true
|
||||
shift 1
|
||||
;;
|
||||
--ldapBindUser)
|
||||
ldapBindUser="$2"
|
||||
shift 2
|
||||
;;
|
||||
--ldapBindPass)
|
||||
ldapBindPass="$2"
|
||||
shift 2
|
||||
;;
|
||||
--ldapFilter)
|
||||
ldapFilter="$2"
|
||||
shift 2
|
||||
;;
|
||||
--ldapBaseDN)
|
||||
ldapBaseDN="$2"
|
||||
shift 2
|
||||
;;
|
||||
--ldapUidTag)
|
||||
ldapUidTag="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Error: unrecognized option $1."
|
||||
printHelp
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$ldapBindUser" == "" ]; then
|
||||
ldapBindUserLine=""
|
||||
else
|
||||
ldapBindUserLine="bindUser: $ldapBindUser"
|
||||
fi
|
||||
if [ "$ldapBindPass" == "" ]; then
|
||||
ldapBindPassLine=""
|
||||
else
|
||||
ldapBindPassLine="bindPassword: $ldapBindPass"
|
||||
fi
|
||||
if [ "$ldapFilter" == "" ]; then
|
||||
ldapFilterLine=""
|
||||
else
|
||||
ldapFilterLine="filter: $ldapFilter"
|
||||
fi
|
||||
if [ "$ldapBaseDN" == "" ]; then
|
||||
ldapBaseDNLine=""
|
||||
else
|
||||
ldapBaseDNLine="baseDN: $ldapBaseDN"
|
||||
fi
|
||||
if [ "$ldapUidTag" == "" ]; then
|
||||
ldapUidTagLine=""
|
||||
else
|
||||
ldapUidTagLine="uidTag: $ldapUidTag"
|
||||
fi
|
||||
|
||||
cat > server/config/production.yaml <<EOT
|
||||
www:
|
||||
host: 0.0.0.0
|
||||
proxy: $wwwProxy
|
||||
secret: "`pwgen -1`"
|
||||
trustedUrlBase: $urlBaseTrusted
|
||||
sandboxUrlBase: $urlBaseSandbox
|
||||
publicUrlBase: $urlBasePublic
|
||||
if [ -f application/config/config.php ]; then
|
||||
echo 'Info: application/production.yaml already provisioned'
|
||||
else
|
||||
echo 'Info: Generating application/production.yaml'
|
||||
|
||||
mysql:
|
||||
host: $mySqlHost
|
||||
# Basic configuration
|
||||
cat > server/config/production.yaml <<EOT
|
||||
www:
|
||||
host: 0.0.0.0
|
||||
proxy: $WWW_PROXY
|
||||
secret: "`pwgen -1`"
|
||||
trustedUrlBase: $URL_BASE_TRUSTED
|
||||
sandboxUrlBase: $URL_BASE_SANDBOX
|
||||
publicUrlBase: $URL_BASE_PUBLIC
|
||||
|
||||
redis:
|
||||
enabled: true
|
||||
host: $redisHost
|
||||
mysql:
|
||||
host: $MYSQL_HOST
|
||||
database: $MYSQL_DATABASE
|
||||
user: $MYSQL_USER
|
||||
password: $MYSQL_PASSWORD
|
||||
|
||||
log:
|
||||
level: info
|
||||
redis:
|
||||
enabled: true
|
||||
host: $REDIS_HOST
|
||||
|
||||
builtinZoneMTA:
|
||||
log:
|
||||
level: warn
|
||||
mongo: mongodb://${mongoHost}:27017/zone-mta
|
||||
redis: redis://${redisHost}:6379/2
|
||||
log:
|
||||
level: info
|
||||
|
||||
queue:
|
||||
processes: 5
|
||||
builtinZoneMTA:
|
||||
log:
|
||||
level: warn
|
||||
mongo: mongodb://${MONGO_HOST}:27017/zone-mta
|
||||
redis: redis://${REDIS_HOST}:6379/2
|
||||
|
||||
ldap:
|
||||
enabled: $withLdap
|
||||
host: $ldapHost
|
||||
port: $ldapPort
|
||||
secure: $ldapSecure
|
||||
$ldapBindUserLine
|
||||
$ldapBindPassLine
|
||||
$ldapFilterLine
|
||||
$ldapBaseDNLine
|
||||
$ldapUidTagLine
|
||||
queue:
|
||||
processes: 5
|
||||
EOT
|
||||
|
||||
cat > server/services/workers/reports/config/production.yaml <<EOT
|
||||
mysql:
|
||||
host: $mySqlHost
|
||||
log:
|
||||
level: warn
|
||||
# Manage LDAP if enabled
|
||||
if [ "$WITH_LDAP" = "true" ]; then
|
||||
echo 'Info: LDAP enabled'
|
||||
cat >> server/config/production.yaml <<EOT
|
||||
ldap:
|
||||
enabled: true
|
||||
host: $LDAP_HOST
|
||||
port: $LDAP_PORT
|
||||
secure: $LDAP_SECURE
|
||||
bindUser: $LDAP_BIND_USER
|
||||
bindPasswort: $LDAP_BIND_PASS
|
||||
filter: $LDAP_FILTER
|
||||
baseDN: $LDAP_BASEDN
|
||||
uidTag: $LDAP_UIDTAG
|
||||
EOT
|
||||
else
|
||||
echo 'Info: LDAP not enabled'
|
||||
cat >> server/config/production.yaml <<EOT
|
||||
ldap:
|
||||
enabled: false
|
||||
EOT
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ -f server/services/workers/reports/config/production.yaml ]; then
|
||||
echo 'Info: server/production.yaml already provisioned'
|
||||
else
|
||||
echo 'Info: Generating server/production.yaml'
|
||||
cat > server/services/workers/reports/config/production.yaml <<EOT
|
||||
mysql:
|
||||
host: $MYSQL_HOST
|
||||
log:
|
||||
level: warn
|
||||
EOT
|
||||
fi
|
||||
|
||||
# Wait for the other services to start
|
||||
while ! nc -z $mySqlHost 3306; do sleep 1; done
|
||||
while ! nc -z $redisHost 6379; do sleep 1; done
|
||||
while ! nc -z $mongoHost 27017; do sleep 1; done
|
||||
echo 'Info: Waiting for MySQL Server'
|
||||
while ! nc -z $MYSQL_HOST 3306; do sleep 1; done
|
||||
|
||||
echo 'Info: Waiting for Redis Server'
|
||||
while ! nc -z $REDIS_HOST 6379; do sleep 1; done
|
||||
|
||||
echo 'Info: Waiting for MongoDB Server'
|
||||
while ! nc -z $MONGO_HOST 27017; do sleep 1; done
|
||||
|
||||
cd server
|
||||
NODE_ENV=production node index.js
|
1032
locales/de-DE/common.json
Normal file
1032
locales/de-DE/common.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -267,7 +267,7 @@
|
|||
"viewStatistics": "View statistics",
|
||||
"campaignIsBeingSentOut": "Campaign is being sent out.",
|
||||
"stop": "Stop",
|
||||
"allMessagesSent!HitContinueIfYouYouWant": "All messages sent! Hit \"Continue\" if you you want to send this campaign to new subscribers.",
|
||||
"allMessagesSent!HitContinueIfYouYouWant": "All messages sent! Hit \"Continue\" if you want to send this campaign to new subscribers.",
|
||||
"continue": "Continue",
|
||||
"reset": "Reset",
|
||||
"yourCampaignIsCurrentlyDisabledClick": "Your campaign is currently disabled. Click Enable button to start enable it.",
|
||||
|
@ -398,7 +398,7 @@
|
|||
"defaultValueIsNotAProperlyFormattedDate": "Default value is not a properly formatted date",
|
||||
"defaultValueIsNotAProperlyFormatted": "Default value is not a properly formatted birthday date",
|
||||
"defaultValueIsNotOneOfTheAllowedOptions": "Default value is not one of the allowed options",
|
||||
"errrorOnLineLine": "Errror on line {{ line }}",
|
||||
"errorOnLineLine": "Error on line {{ line }}",
|
||||
"fieldUpdated": "Field updated",
|
||||
"fieldCreated": "Field created",
|
||||
"notVisible": "Not visible",
|
||||
|
@ -864,6 +864,7 @@
|
|||
"beginsWithBeginRsaPrivateKey": "Begins with \"-----BEGIN RSA PRIVATE KEY-----\"",
|
||||
"signingIsDisabledWithoutAValidPrivateKey": "Signing is disabled without a valid private key.",
|
||||
"accessKey": "Access key",
|
||||
"accessSecret": "Access Secret",
|
||||
"awsAccessKeyId": "AWS access key ID",
|
||||
"awsSecretAccessKey": "AWS secret access key",
|
||||
"region": "Region",
|
||||
|
|
|
@ -267,7 +267,7 @@
|
|||
"viewStatistics": "View statistics",
|
||||
"campaignIsBeingSentOut": "Campaign is being sent out.",
|
||||
"stop": "Stop",
|
||||
"allMessagesSent!HitContinueIfYouYouWant": "All messages sent! Hit \"Continue\" if you you want to send this campaign to new subscribers.",
|
||||
"allMessagesSent!HitContinueIfYouYouWant": "All messages sent! Hit \"Continue\" if you want to send this campaign to new subscribers.",
|
||||
"continue": "Continue",
|
||||
"reset": "Reset",
|
||||
"yourCampaignIsCurrentlyDisabledClick": "Your campaign is currently disabled. Click Enable button to start enable it.",
|
||||
|
@ -398,7 +398,7 @@
|
|||
"defaultValueIsNotAProperlyFormattedDate": "Default value is not a properly formatted date",
|
||||
"defaultValueIsNotAProperlyFormatted": "Default value is not a properly formatted birthday date",
|
||||
"defaultValueIsNotOneOfTheAllowedOptions": "Default value is not one of the allowed options",
|
||||
"errrorOnLineLine": "Errror on line {{ line }}",
|
||||
"errorOnLineLine": "Error on line {{ line }}",
|
||||
"fieldUpdated": "Field updated",
|
||||
"fieldCreated": "Field created",
|
||||
"notVisible": "Not visible",
|
||||
|
@ -864,6 +864,7 @@
|
|||
"beginsWithBeginRsaPrivateKey": "Begins with \"-----BEGIN RSA PRIVATE KEY-----\"",
|
||||
"signingIsDisabledWithoutAValidPrivateKey": "Signing is disabled without a valid private key.",
|
||||
"accessKey": "Access key",
|
||||
"accessSecret": "Access Secret",
|
||||
"awsAccessKeyId": "AWS access key ID",
|
||||
"awsSecretAccessKey": "AWS secret access key",
|
||||
"region": "Region",
|
||||
|
@ -1024,5 +1025,8 @@
|
|||
"thePasswordMustContainAtLeastOne": "The password must contain at least one lowercase letter",
|
||||
"thePasswordMustContainAtLeastOne-1": "The password must contain at least one uppercase letter",
|
||||
"thePasswordMustContainAtLeastOneNumber": "The password must contain at least one number",
|
||||
"thePasswordMustContainAtLeastOneSpecial": "The password must contain at least one special character"
|
||||
"thePasswordMustContainAtLeastOneSpecial": "The password must contain at least one special character",
|
||||
"tagLanguage": "Tag language",
|
||||
"tagLanguageMustBeSelected": "Tag language must be selected",
|
||||
"helpText": "Help text"
|
||||
}
|
|
@ -277,7 +277,7 @@
|
|||
"viewStatistics": "View statistics",
|
||||
"campaignIsBeingSentOut": "Campaign is being sent out.",
|
||||
"stop": "Stop",
|
||||
"allMessagesSent!HitContinueIfYouYouWant": "All messages sent! Hit \"Continue\" if you you want to send this campaign to new subscribers.",
|
||||
"allMessagesSent!HitContinueIfYouYouWant": "All messages sent! Hit \"Continue\" if you want to send this campaign to new subscribers.",
|
||||
"continue": "Continue",
|
||||
"reset": "Reset",
|
||||
"yourCampaignIsCurrentlyDisabledClick": "Your campaign is currently disabled. Click Enable button to start enable it.",
|
||||
|
@ -425,7 +425,7 @@
|
|||
"defaultValueIsNotAProperlyFormattedDate": "Default value is not a properly formatted date",
|
||||
"defaultValueIsNotAProperlyFormatted": "Default value is not a properly formatted birthday date",
|
||||
"defaultValueIsNotOneOfTheAllowedOptions": "Default value is not one of the allowed options",
|
||||
"errrorOnLineLine": "Errror on line {{ line }}",
|
||||
"errorOnLineLine": "Error on line {{ line }}",
|
||||
"fieldUpdated": "Field updated",
|
||||
"fieldUpdated - TODO: update line above and then delete this line to mark that the translation has been fixed": "Field updated",
|
||||
"fieldCreated": "Field created",
|
||||
|
@ -915,6 +915,7 @@
|
|||
"beginsWithBeginRsaPrivateKey": "Begins with \"-----BEGIN RSA PRIVATE KEY-----\"",
|
||||
"signingIsDisabledWithoutAValidPrivateKey": "Signing is disabled without a valid private key.",
|
||||
"accessKey": "Access key",
|
||||
"accessSecret": "Access Secret",
|
||||
"awsAccessKeyId": "AWS access key ID",
|
||||
"awsSecretAccessKey": "AWS secret access key",
|
||||
"region": "Region",
|
||||
|
|
|
@ -17,7 +17,7 @@ const deepKeys = require('deep-keys');
|
|||
|
||||
const localeMain = 'en-US/common.json';
|
||||
const localeMainPrevious = 'en-US-last-run/common.json';
|
||||
const localeTranslations = ['es-ES/common.json', 'pt-BR/common.json'];
|
||||
const localeTranslations = ['es-ES/common.json', 'pt-BR/common.json', 'de-DE/common.json'];
|
||||
const searchDirs = [
|
||||
'../client/src',
|
||||
'../server',
|
||||
|
|
|
@ -426,7 +426,7 @@
|
|||
"defaultValueIsNotAProperlyFormattedDate": "O valor padrão não é uma data formatada corretamente",
|
||||
"defaultValueIsNotAProperlyFormatted": "O valor padrão não é uma data de aniversário formatada corretamente",
|
||||
"defaultValueIsNotOneOfTheAllowedOptions": "O valor padrão não é uma das opções permitidas",
|
||||
"errrorOnLineLine": "Errror on line {{line}}",
|
||||
"errorOnLineLine": "Error on line {{line}}",
|
||||
"fieldUpdated": "Field updated",
|
||||
"fieldUpdated - TODO: update line above and then delete this line to mark that the translation has been fixed": "Field updated",
|
||||
"fieldCreated": "Field created",
|
||||
|
@ -916,6 +916,7 @@
|
|||
"beginsWithBeginRsaPrivateKey": "Começa com \"----- INICIO DA CHAVE PRIVADA RSA ----- \"",
|
||||
"signingIsDisabledWithoutAValidPrivateKey": "A assinatura está desativada sem uma chave privada válida.",
|
||||
"accessKey": "Chave de acesso",
|
||||
"accessSecret": "Acesso secreto",
|
||||
"awsAccessKeyId": "ID da chave de acesso da AWS",
|
||||
"awsSecretAccessKey": "Chave de acesso secreto da AWS",
|
||||
"region": "Região",
|
||||
|
|
|
@ -237,11 +237,11 @@ async function createApp(appType) {
|
|||
useWith404Fallback('/static', express.static(path.join(__dirname, '..', 'client', 'static')));
|
||||
useWith404Fallback('/client', express.static(path.join(__dirname, '..', 'client', 'dist')));
|
||||
|
||||
useWith404Fallback('/static-npm/fontawesome', express.static(path.join(__dirname, '..', 'client', 'node_modules', '@fortawesome', 'fontawesome-free', 'webfonts')));
|
||||
useWith404Fallback('/static-npm/jquery.min.js', express.static(path.join(__dirname, '..', 'client', 'node_modules', 'jquery', 'dist', 'jquery.min.js')));
|
||||
useWith404Fallback('/static-npm/popper.min.js', express.static(path.join(__dirname, '..', 'client', 'node_modules', 'popper.js', 'dist', 'umd', 'popper.min.js')));
|
||||
useWith404Fallback('/static-npm/bootstrap.min.js', express.static(path.join(__dirname, '..', 'client', 'node_modules', 'bootstrap', 'dist', 'js', 'bootstrap.min.js')));
|
||||
useWith404Fallback('/static-npm/coreui.min.js', express.static(path.join(__dirname, '..', 'client', 'node_modules', '@coreui', 'coreui', 'dist', 'js', 'coreui.min.js')));
|
||||
useWith404Fallback('/static-npm/fontawesome', express.static(path.join(__dirname, '..', 'client', 'dist', 'webfonts')));
|
||||
useWith404Fallback('/static-npm/jquery.min.js', express.static(path.join(__dirname, '..', 'client', 'dist', 'jquery.min.js')));
|
||||
useWith404Fallback('/static-npm/popper.min.js', express.static(path.join(__dirname, '..', 'client', 'dist', 'popper.min.js')));
|
||||
useWith404Fallback('/static-npm/bootstrap.min.js', express.static(path.join(__dirname, '..', 'client', 'dist', 'bootstrap.min.js')));
|
||||
useWith404Fallback('/static-npm/coreui.min.js', express.static(path.join(__dirname, '..', 'client', 'dist', 'coreui.min.js')));
|
||||
|
||||
|
||||
// Make sure flash messages are available
|
||||
|
|
|
@ -49,6 +49,7 @@ enabledLanguages:
|
|||
- en-US
|
||||
- es-ES
|
||||
- pt-BR
|
||||
- de-DE
|
||||
- fk-FK
|
||||
|
||||
# Inject custom scripts in subscription/layout.mjml.hbs
|
||||
|
|
|
@ -863,7 +863,7 @@ async function getListsWithEmail(context, email) {
|
|||
// FIXME - this methods is rather suboptimal if there are many lists. It quite needs permission caching in shares.js
|
||||
|
||||
return await knex.transaction(async tx => {
|
||||
const lsts = await tx('lists').select(['id', 'name']);
|
||||
const lsts = await tx('lists').select(['id', 'cid', 'name']);
|
||||
const result = [];
|
||||
|
||||
for (const list of lsts) {
|
||||
|
|
8
server/package-lock.json
generated
8
server/package-lock.json
generated
|
@ -360,7 +360,6 @@
|
|||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
|
@ -3735,7 +3734,6 @@
|
|||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
|
@ -3744,8 +3742,7 @@
|
|||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6658,8 +6655,7 @@
|
|||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||
"dev": true
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"sqlstring": {
|
||||
"version": "2.3.1",
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
"humanize": "0.0.9",
|
||||
"i18next": "^13.1.0",
|
||||
"isemail": "^3.2.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"jsdom": "^13.1.0",
|
||||
"juice": "^5.2.0",
|
||||
"klaw-sync": "^6.0.0",
|
||||
|
|
|
@ -361,7 +361,7 @@ async function processCampaign(campaignId) {
|
|||
}
|
||||
|
||||
const subs = await knex('campaign_messages')
|
||||
.where({status: CampaignMessageStatus.SCHEDULED})
|
||||
.where({status: CampaignMessageStatus.SCHEDULED, campaign: campaignId})
|
||||
.whereNotIn('hash_email', messagesInProcessing.map(x => x.hash_email))
|
||||
.limit(retrieveBatchSize);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ defaultLanguage: en-US
|
|||
enabledLanguages:
|
||||
- en-US
|
||||
- es-ES
|
||||
- de-DE
|
||||
- fk-FK
|
||||
|
||||
mysql:
|
||||
|
|
|
@ -56,6 +56,11 @@ const langCodes = {
|
|||
getLabel: t => 'Português',
|
||||
longCode: 'pt-BR'
|
||||
},
|
||||
'de-DE': {
|
||||
getShortLabel: t => 'DE',
|
||||
getLabel: t => 'Deutsch',
|
||||
longCode: 'de-DE'
|
||||
},
|
||||
'fk-FK': {
|
||||
getShortLabel: t => 'FK',
|
||||
getLabel: t => 'Fake',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue