diff --git a/app.js b/app.js index e1191b34..d500258f 100644 --- a/app.js +++ b/app.js @@ -36,7 +36,6 @@ const webhooks = require('./routes/webhooks'); const subscription = require('./routes/subscription'); const archive = require('./routes/archive'); const api = require('./routes/api'); -const blacklist = require('./routes/blacklist'); const editorapi = require('./routes/editorapi'); const grapejs = require('./routes/grapejs'); const mosaico = require('./routes/mosaico'); @@ -56,12 +55,14 @@ const fieldsRest = require('./routes/rest/fields'); const sharesRest = require('./routes/rest/shares'); const segmentsRest = require('./routes/rest/segments'); const subscriptionsRest = require('./routes/rest/subscriptions'); +const blacklistRest = require('./routes/rest/blacklist'); const namespacesLegacyIntegration = require('./routes/namespaces-legacy-integration'); const usersLegacyIntegration = require('./routes/users-legacy-integration'); const accountLegacyIntegration = require('./routes/account-legacy-integration'); const reportsLegacyIntegration = require('./routes/reports-legacy-integration'); const listsLegacyIntegration = require('./routes/lists-legacy-integration'); +const blacklistLegacyIntegration = require('./routes/blacklist-legacy-integration'); const interoperableErrors = require('./shared/interoperable-errors'); @@ -235,7 +236,6 @@ app.use('/lists', lists); app.use('/templates', templates); app.use('/campaigns', campaigns); app.use('/settings', settings); -app.use('/blacklist', blacklist); app.use('/links', links); app.use('/fields', fields); app.use('/forms', forms); @@ -259,6 +259,7 @@ app.use('/users', usersLegacyIntegration); app.use('/namespaces', namespacesLegacyIntegration); app.use('/account', accountLegacyIntegration); app.use('/lists', listsLegacyIntegration); +app.use('/blacklist', blacklistLegacyIntegration); if (config.reports && config.reports.enabled === true) { app.use('/reports', reports); @@ -281,6 +282,7 @@ app.use('/rest', fieldsRest); app.use('/rest', sharesRest); app.use('/rest', segmentsRest); app.use('/rest', subscriptionsRest); +app.use('/rest', blacklistRest); if (config.reports && config.reports.enabled === true) { app.use('/rest', reportTemplatesRest); diff --git a/client/package.json b/client/package.json index b174dba0..ba13c064 100644 --- a/client/package.json +++ b/client/package.json @@ -35,6 +35,8 @@ "react-router-dom": "^4.1.1", "react-sortable-tree": "^1.2.0", "slugify": "^1.1.0", + "react-dnd-html5-backend": "^2.4.1", + "react-dnd-touch-backend": "^0.3.13", "url-parse": "^1.1.9" }, "devDependencies": { @@ -48,8 +50,6 @@ "css-loader": "^0.28.4", "i18next-conv": "^3.0.3", "node-sass": "^4.5.3", - "react-dnd-html5-backend": "^2.4.1", - "react-dnd-touch-backend": "^0.3.13", "sass-loader": "^6.0.6", "style-loader": "^0.18.2", "url-loader": "^0.5.9", diff --git a/client/src/account/root.js b/client/src/account/root.js index 9e163bf6..f479f8a9 100644 --- a/client/src/account/root.js +++ b/client/src/account/root.js @@ -19,28 +19,28 @@ const getStructure = t => { login: { title: t('Sign in'), link: '/account/login', - component: Login, + panelComponent: Login, }, api: { title: t('API'), link: '/account/api', - component: API + panelComponent: API } }; if (mailtrainConfig.isAuthMethodLocal) { subPaths.forgot = { title: t('Password reset'), - extraParams: [':username?'], - link: '/account/forgot', - component: Reset + extraParams: [':username?'], + link: '/account/forgot', + panelComponent: Reset }; subPaths.reset = { title: t('Password reset'), - extraParams: [':username', ':resetToken'], - link: '/account/reset', - component: ResetLink + extraParams: [':username', ':resetToken'], + link: '/account/reset', + panelComponent: ResetLink }; } @@ -52,10 +52,9 @@ const getStructure = t => { account: { title: t('Account'), link: '/account', - component: Account, + panelComponent: Account, children: subPaths - } } } @@ -67,6 +66,6 @@ export default function() {
, document.getElementById('root') ); -}; +} diff --git a/client/src/blacklist/List.js b/client/src/blacklist/List.js new file mode 100644 index 00000000..cd9751fc --- /dev/null +++ b/client/src/blacklist/List.js @@ -0,0 +1,129 @@ +'use strict'; + +import React, {Component} from "react"; +import {translate} from "react-i18next"; +import {requiresAuthenticatedUser, Title, withPageHelpers} from "../lib/page"; +import {withAsyncErrorHandler, withErrorHandling} from "../lib/error-handling"; +import {Table} from "../lib/table"; +import {ButtonRow, Form, InputField, withForm, FormSendMethod} from "../lib/form"; +import {Button, Icon} from "../lib/bootstrap-components"; +import axios from "../lib/axios"; + +@translate() +@withForm +@withPageHelpers +@withErrorHandling +@requiresAuthenticatedUser +export default class List extends Component { + constructor(props) { + super(props); + + const t = props.t; + + this.state = {}; + + this.initForm({ + serverValidation: { + url: '/rest/blacklist-validate', + changed: ['email'] + } + }); + } + + static propTypes = { + } + + clearFields() { + this.populateFormValues({ + email: '' + }); + } + + localValidateFormValues(state) { + const t = this.props.t; + + const email = state.getIn(['email', 'value']); + const emailServerValidation = state.getIn(['email', 'serverValidation']); + + if (!email) { + state.setIn(['email', 'error'], t('Email must not be empty')); + } else if (emailServerValidation && emailServerValidation.invalid) { + state.setIn(['email', 'error'], t('Invalid email address.')); + } else if (emailServerValidation && emailServerValidation.exists) { + state.setIn(['email', 'error'], t('The email is already on blacklist.')); + } else if (!emailServerValidation) { + state.setIn(['email', 'error'], t('Validation is in progress...')); + } else { + state.setIn(['email', 'error'], null); + } + } + + async submitHandler() { + const t = this.props.t; + + this.disableForm(); + this.setFormStatusMessage('info', t('Saving ...')); + + const submitSuccessful = await this.validateAndSendFormValuesToURL(FormSendMethod.POST, '/rest/blacklist'); + + if (submitSuccessful) { + this.hideFormValidation(); + this.clearFields(); + this.enableForm(); + + this.clearFormStatusMessage(); + this.blacklistTable.refresh(); + + } else { + this.enableForm(); + this.setFormStatusMessage('warning', t('There are errors in the form. Please fix them and try again.')); + } + } + + componentDidMount() { + this.clearFields(); + } + + @withAsyncErrorHandler + async deleteBlacklisted(email) { + await axios.delete(`/rest/blacklist/${email}`); + this.blacklistTable.refresh(); + } + + render() { + const t = this.props.t; + + const columns = [ + { data: 0, title: t('Email') }, + { + actions: data => [ + { + label: , + action: () => this.deleteBlacklisted(data[0]) + } + ] + } + ]; + + return ( +
+ {t('Blacklist')} + +

{t('Add Email to Blacklist')}

+
+ + + +