diff --git a/client/src/account/Account.js b/client/src/account/Account.js index 38ad8469..fc5a83e7 100644 --- a/client/src/account/Account.js +++ b/client/src/account/Account.js @@ -37,8 +37,6 @@ export default class Account extends Component { this.state = {}; this.initForm({ - loadMutator: ::this.getFormValuesMutator, - submitMutator: ::this.submitFormValuesMutator, serverValidation: { url: 'rest/account-validate', changed: ['email', 'currentPassword'] diff --git a/client/src/blacklist/List.js b/client/src/blacklist/List.js index 8f0c7cab..9429b446 100644 --- a/client/src/blacklist/List.js +++ b/client/src/blacklist/List.js @@ -28,6 +28,7 @@ export default class List extends Component { tableRestActionDialogInit(this); this.initForm({ + leaveConfirmation: false, serverValidation: { url: 'rest/blacklist-validate', changed: ['email'] diff --git a/client/src/campaigns/CUD.js b/client/src/campaigns/CUD.js index 8b180ca0..c1640137 100644 --- a/client/src/campaigns/CUD.js +++ b/client/src/campaigns/CUD.js @@ -92,8 +92,6 @@ export default class CUD extends Component { this.nextListEntryId = 0; this.initForm({ - loadMutator: ::this.getFormValuesMutator, - submitMutator: ::this.submitFormValuesMutator, onChange: { send_configuration: ::this.onSendConfigurationChanged }, diff --git a/client/src/campaigns/Content.js b/client/src/campaigns/Content.js index 5a28ae27..34b587a5 100644 --- a/client/src/campaigns/Content.js +++ b/client/src/campaigns/Content.js @@ -55,8 +55,6 @@ export default class CustomContent extends Component { }; this.initForm({ - loadMutator: ::this.getFormValuesMutator, - submitMutator: ::this.submitFormValuesMutator, getPreSubmitUpdater: ::this.getPreSubmitFormValuesUpdater, }); diff --git a/client/src/campaigns/Status.js b/client/src/campaigns/Status.js index 5ca90f70..0eaba972 100644 --- a/client/src/campaigns/Status.js +++ b/client/src/campaigns/Status.js @@ -28,7 +28,9 @@ import {withComponentMixins} from "../lib/decorator-helpers"; class TestUser extends Component { constructor(props) { super(props); - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } static propTypes = { @@ -94,7 +96,9 @@ class TestUser extends Component { class SendControls extends Component { constructor(props) { super(props); - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } static propTypes = { diff --git a/client/src/campaigns/TestSendModalDialog.js b/client/src/campaigns/TestSendModalDialog.js index 9117dfa2..c1f5d378 100644 --- a/client/src/campaigns/TestSendModalDialog.js +++ b/client/src/campaigns/TestSendModalDialog.js @@ -26,7 +26,9 @@ export class TestSendModalDialog extends Component { this.mailerTypes = getMailerTypes(props.t); - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } static propTypes = { diff --git a/client/src/campaigns/triggers/CUD.js b/client/src/campaigns/triggers/CUD.js index b38d951d..d90ae009 100644 --- a/client/src/campaigns/triggers/CUD.js +++ b/client/src/campaigns/triggers/CUD.js @@ -10,6 +10,7 @@ import { ButtonRow, CheckBox, Dropdown, + filterData, Form, FormSendMethod, InputField, @@ -42,7 +43,6 @@ export default class CUD extends Component { this.campaignTypeLabels = getCampaignLabels(props.t); const {entityLabels, eventLabels} = getTriggerTypes(props.t); - this.entityLabels = entityLabels; this.entityOptions = [ {key: Entity.SUBSCRIPTION, label: entityLabels[Entity.SUBSCRIPTION]}, @@ -92,6 +92,10 @@ export default class CUD extends Component { } } + submitFormValuesMutator(data) { + return filterData(data, ['name', 'description', 'entity', 'event', 'seconds', 'enabled', 'source_campaign']); + } + componentDidMount() { if (this.props.entity) { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator); diff --git a/client/src/lib/form.js b/client/src/lib/form.js index 60b2aec3..e5171511 100644 --- a/client/src/lib/form.js +++ b/client/src/lib/form.js @@ -1096,7 +1096,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => { data.originalHash = data.hash; delete data.hash; - const mutator = settings.loadMutator; + const mutator = this.getFormValuesMutator; if (mutator) { mutator(data); } @@ -1123,7 +1123,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => { data.originalHash = data.hash; delete data.hash; - const mutator = settings.loadMutator; + const mutator = this.getFormValuesMutator; if (mutator) { const newData = mutator(data); @@ -1154,7 +1154,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => { let data = this.getFormValues(); - const mutator = settings.submitMutator; + const mutator = this.submitFormValuesMutator; if (mutator) { const newData = mutator(data); if (newData !== undefined) { @@ -1321,8 +1321,8 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => { const settings = self.state.formSettings; const mutateData = data => { - if (settings.submitMutator) { - const newData = settings.submitMutator(data); + if (self.submitFormValuesMutator) { + const newData = self.submitFormValuesMutator(data); if (newData !== undefined) { data = newData; } diff --git a/client/src/lists/CUD.js b/client/src/lists/CUD.js index 4943f1a5..fedb64c9 100644 --- a/client/src/lists/CUD.js +++ b/client/src/lists/CUD.js @@ -42,10 +42,7 @@ export default class CUD extends Component { this.state = {}; - this.initForm({ - loadMutator: ::this.getFormValuesMutator, - submitMutator: ::this.submitFormValuesMutator - }); + this.initForm(); this.mailerTypes = getMailerTypes(props.t); } diff --git a/client/src/lists/fields/CUD.js b/client/src/lists/fields/CUD.js index b08913ef..2e30b51e 100644 --- a/client/src/lists/fields/CUD.js +++ b/client/src/lists/fields/CUD.js @@ -12,12 +12,14 @@ import { CheckBox, Dropdown, Fieldset, + filterData, Form, FormSendMethod, InputField, StaticField, TableSelect, - withForm + withForm, + withFormErrorHandlers } from '../../lib/form'; import {withErrorHandling} from '../../lib/error-handling'; import {DeleteModalDialog} from "../../lib/modals"; @@ -117,9 +119,58 @@ export default class CUD extends Component { data.orderManageBefore = data.orderManageBefore.toString(); } + submitFormValuesMutator(data) { + if (data.default_value.trim() === '') { + data.default_value = null; + } + + if (!data.isInGroup) { + data.group = null; + } + + data.settings = {}; + switch (data.type) { + case 'checkbox-grouped': + case 'radio-grouped': + case 'dropdown-grouped': + case 'json': + data.settings.renderTemplate = data.renderTemplate; + break; + + case 'radio-enum': + case 'dropdown-enum': + data.settings.options = this.parseEnumOptions(data.enumOptions).options; + data.settings.renderTemplate = data.renderTemplate; + break; + + case 'date': + case 'birthday': + data.settings.dateFormat = data.dateFormat; + break; + + case 'option': + if (!data.isInGroup) { + data.settings.checkedLabel = data.checkedLabel; + data.settings.uncheckedLabel = data.uncheckedLabel; + } + break; + } + + if (data.group !== null) { + data.orderListBefore = data.orderSubscribeBefore = data.orderManageBefore = 'none'; + } else { + data.orderListBefore = Number.parseInt(data.orderListBefore) || data.orderListBefore; + data.orderSubscribeBefore = Number.parseInt(data.orderSubscribeBefore) || data.orderSubscribeBefore; + data.orderManageBefore = Number.parseInt(data.orderManageBefore) || data.orderManageBefore; + } + + return filterData(data, ['name', 'key', 'default_value', 'type', 'group', 'settings', + 'orderListBefore', 'orderSubscribeBefore', 'orderManageBefore']); + } + componentDidMount() { if (this.props.entity) { - this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator); + this.getFormValuesFromEntity(this.props.entity); } else { this.populateFormValues({ @@ -237,6 +288,7 @@ export default class CUD extends Component { } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; @@ -253,65 +305,14 @@ export default class CUD extends Component { this.disableForm(); this.setFormStatusMessage('info', t('saving')); - const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { - if (data.default_value.trim() === '') { - data.default_value = null; - } - - if (!data.isInGroup) { - data.group = null; - } - - data.settings = {}; - switch (data.type) { - case 'checkbox-grouped': - case 'radio-grouped': - case 'dropdown-grouped': - case 'json': - data.settings.renderTemplate = data.renderTemplate; - break; - - case 'radio-enum': - case 'dropdown-enum': - data.settings.options = this.parseEnumOptions(data.enumOptions).options; - data.settings.renderTemplate = data.renderTemplate; - break; - - case 'date': - case 'birthday': - data.settings.dateFormat = data.dateFormat; - break; - - case 'option': - if (!data.isInGroup) { - data.settings.checkedLabel = data.checkedLabel; - data.settings.uncheckedLabel = data.uncheckedLabel; - } - break; - } - - delete data.renderTemplate; - delete data.enumOptions; - delete data.dateFormat; - delete data.checkedLabel; - delete data.uncheckedLabel; - delete data.isInGroup; - - if (data.group !== null) { - data.orderListBefore = data.orderSubscribeBefore = data.orderManageBefore = 'none'; - } else { - data.orderListBefore = Number.parseInt(data.orderListBefore) || data.orderListBefore; - data.orderSubscribeBefore = Number.parseInt(data.orderSubscribeBefore) || data.orderSubscribeBefore; - data.orderManageBefore = Number.parseInt(data.orderManageBefore) || data.orderManageBefore; - } - }); + const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url); if (submitResult) { if (this.props.entity) { if (submitAndLeave) { this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/fields`, 'success', t('Field updated')); } else { - await this.getFormValuesFromURL(`rest/fields/${this.props.list.id}/${this.props.entity.id}`, ::this.getFormValuesMutator); + await this.getFormValuesFromURL(`rest/fields/${this.props.list.id}/${this.props.entity.id}`); this.enableForm(); this.setFormStatusMessage('success', t('Field updated')); } diff --git a/client/src/lists/forms/CUD.js b/client/src/lists/forms/CUD.js index a12efbcd..cac47dfe 100644 --- a/client/src/lists/forms/CUD.js +++ b/client/src/lists/forms/CUD.js @@ -12,12 +12,14 @@ import { ButtonRow, Dropdown, Fieldset, + filterData, Form, FormSendMethod, InputField, TableSelect, TextArea, - withForm + withForm, + withFormErrorHandlers } from '../../lib/form'; import {withErrorHandling} from '../../lib/error-handling'; import {NamespaceSelect, validateNamespace} from '../../lib/namespace'; @@ -293,14 +295,38 @@ export default class CUD extends Component { getFormValuesMutator(data) { this.supplyDefaults(data); + data.selectedTemplate = data.selectedTemplate || 'layout'; + } + + submitFormValuesMutator(data) { + return filterData(data, ['name', 'description', 'layout', 'form_input_style', 'namespace', + 'web_subscribe', + 'web_confirm_subscription_notice', + 'mail_confirm_subscription_html', + 'mail_confirm_subscription_text', + 'mail_already_subscribed_html', + 'mail_already_subscribed_text', + 'web_subscribed_notice', + 'mail_subscription_confirmed_html', + 'mail_subscription_confirmed_text', + 'web_manage', + 'web_manage_address', + 'web_updated_notice', + 'web_unsubscribe', + 'web_confirm_unsubscription_notice', + 'mail_confirm_unsubscription_html', + 'mail_confirm_unsubscription_text', + 'mail_confirm_address_change_html', + 'mail_confirm_address_change_text', + 'web_unsubscribed_notice', + 'mail_unsubscription_confirmed_html', + 'mail_unsubscription_confirmed_text', 'web_manual_unsubscribe_notice', 'web_privacy_policy_notice' + ]); } componentDidMount() { if (this.props.entity) { - this.getFormValuesFromEntity(this.props.entity, data => { - this.getFormValuesMutator(data); - data.selectedTemplate = 'layout'; - }); + this.getFormValuesFromEntity(this.props.entity); } else { const data = { @@ -355,6 +381,7 @@ export default class CUD extends Component { } } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; @@ -370,17 +397,14 @@ export default class CUD extends Component { this.disableForm(); this.setFormStatusMessage('info', t('saving')); - const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { - delete data.selectedTemplate; - delete data.previewList; - }); + const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url); if (submitResult) { if (this.props.entity) { if (submitAndLeave) { this.navigateToWithFlashMessage('/lists/forms', 'success', t('Custom forms updated')); } else { - await this.getFormValuesFromURL(`rest/forms/${this.props.entity.id}`, ::this.getFormValuesMutator); + await this.getFormValuesFromURL(`rest/forms/${this.props.entity.id}`); this.enableForm(); this.setFormStatusMessage('success', t('Custom forms updated')); } diff --git a/client/src/lists/imports/CUD.js b/client/src/lists/imports/CUD.js index e2db5cf6..9c4aada3 100644 --- a/client/src/lists/imports/CUD.js +++ b/client/src/lists/imports/CUD.js @@ -11,12 +11,14 @@ import { CheckBox, Dropdown, Fieldset, + filterData, Form, FormSendMethod, InputField, StaticField, TextArea, - withForm + withForm, + withFormErrorHandlers } from '../../lib/form'; import {withAsyncErrorHandler, withErrorHandling} from '../../lib/error-handling'; import {DeleteModalDialog} from "../../lib/modals"; @@ -81,36 +83,101 @@ export default class CUD extends Component { entity: PropTypes.object } - initFromEntity(entity) { - this.getFormValuesFromEntity(entity, data => { - data.settings = data.settings || {}; - const mapping = data.mapping || {}; + getFormValuesMutator(data) { + data.settings = data.settings || {}; + const mapping = data.mapping || {}; + if (data.source === ImportSource.CSV_FILE) { + data.csvFileName = data.settings.csv.originalname; + data.csvDelimiter = data.settings.csv.delimiter; + } + + const mappingSettings = mapping.settings || {}; + data.mapping_settings_checkEmails = 'checkEmails' in mappingSettings ? !!mappingSettings.checkEmails : true; + + const mappingFlds = mapping.fields || {}; + for (const field of this.props.fieldsGrouped) { + if (field.column) { + const colMapping = mappingFlds[field.column] || {}; + data['mapping_fields_' + field.column + '_column'] = colMapping.column || ''; + } else { + for (const option of field.settings.options) { + const col = field.groupedOptions[option.key].column; + const colMapping = mappingFlds[col] || {}; + data['mapping_fields_' + col + '_column'] = colMapping.column || ''; + } + } + } + + const emailMapping = mappingFlds.email || {}; + data.mapping_fields_email_column = emailMapping.column || ''; + } + + submitFormValuesMutator(data) { + const isEdit = !!this.props.entity; + + data.source = Number.parseInt(data.source); + data.settings = {}; + + const formData = new FormData(); + if (!isEdit) { if (data.source === ImportSource.CSV_FILE) { - data.csvFileName = data.settings.csv.originalname; - data.csvDelimiter = data.settings.csv.delimiter; + data.settings.csv = {}; + formData.append('csvFile', this.csvFile.files[0]); + data.settings.csv.delimiter = data.csvDelimiter.trim(); } - const mappingSettings = mapping.settings || {}; - data.mapping_settings_checkEmails = 'checkEmails' in mappingSettings ? !!mappingSettings.checkEmails : true; + } else { + data.mapping_type = Number.parseInt(data.mapping_type); + const mapping = { + fields: {}, + settings: {} + }; - const mappingFlds = mapping.fields || {}; - for (const field of this.props.fieldsGrouped) { - if (field.column) { - const colMapping = mappingFlds[field.column] || {}; - data['mapping_fields_' + field.column + '_column'] = colMapping.column || ''; - } else { - for (const option of field.settings.options) { - const col = field.groupedOptions[option.key].column; - const colMapping = mappingFlds[col] || {}; - data['mapping_fields_' + col + '_column'] = colMapping.column || ''; + if (data.mapping_type === MappingType.BASIC_SUBSCRIBE) { + mapping.settings.checkEmails = data.mapping_settings_checkEmails; + + for (const field of this.props.fieldsGrouped) { + if (field.column) { + const colMapping = data['mapping_fields_' + field.column + '_column']; + if (colMapping) { + mapping.fields[field.column] = { + column: colMapping + }; + } + } else { + for (const option of field.settings.options) { + const col = field.groupedOptions[option.key].column; + const colMapping = data['mapping_fields_' + col + '_column']; + if (colMapping) { + mapping.fields[col] = { + column: colMapping + }; + } + } } } } - const emailMapping = mappingFlds.email || {}; - data.mapping_fields_email_column = emailMapping.column || ''; - }); + if (data.mapping_type === MappingType.BASIC_SUBSCRIBE || data.mapping_type === MappingType.BASIC_UNSUBSCRIBE) { + mapping.fields.email = { + column: data.mapping_fields_email_column + }; + } + + + data.mapping = mapping; + } + + formData.append('entity', JSON.stringify( + filterData(data, ['name', 'description', 'source', 'settings', 'mapping_type', 'mapping']) + )); + + return formData; + } + + initFromEntity(entity) { + this.getFormValuesFromEntity(entity); if (inProgress(entity.status)) { this.refreshTimeoutId = setTimeout(this.refreshTimeoutHandler, 1000); @@ -179,6 +246,7 @@ export default class CUD extends Component { await this.save(); } + @withFormErrorHandlers async save(runAfterSave) { const t = this.props.t; const isEdit = !!this.props.entity; @@ -197,74 +265,7 @@ export default class CUD extends Component { this.disableForm(); this.setFormStatusMessage('info', t('saving')); - const submitResponse = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { - data.source = Number.parseInt(data.source); - data.settings = {}; - - const formData = new FormData(); - if (!isEdit) { - if (data.source === ImportSource.CSV_FILE) { - data.settings.csv = {}; - formData.append('csvFile', this.csvFile.files[0]); - data.settings.csv.delimiter = data.csvDelimiter.trim(); - } - - } else { - data.mapping_type = Number.parseInt(data.mapping_type); - const mapping = { - fields: {}, - settings: {} - }; - - if (data.mapping_type === MappingType.BASIC_SUBSCRIBE) { - mapping.settings.checkEmails = data.mapping_settings_checkEmails; - - for (const field of this.props.fieldsGrouped) { - if (field.column) { - const colMapping = data['mapping_fields_' + field.column + '_column']; - if (colMapping) { - mapping.fields[field.column] = { - column: colMapping - }; - } - } else { - for (const option of field.settings.options) { - const col = field.groupedOptions[option.key].column; - const colMapping = data['mapping_fields_' + col + '_column']; - if (colMapping) { - mapping.fields[col] = { - column: colMapping - }; - } - } - } - } - } - - if (data.mapping_type === MappingType.BASIC_SUBSCRIBE || data.mapping_type === MappingType.BASIC_UNSUBSCRIBE) { - mapping.fields.email = { - column: data.mapping_fields_email_column - }; - } - - - data.mapping = mapping; - } - - for (const key in data) { - if (key.startsWith('mapping_fields') || key.startsWith('mapping_settings')) { - delete data[key]; - } - } - - delete data.csvFile; - delete data.csvDelimiter; - delete data.sampleRow; - - formData.append('entity', JSON.stringify(data)); - - return formData; - }); + const submitResponse = await this.validateAndSendFormValuesToURL(sendMethod, url); if (submitResponse) { if (!isEdit) { diff --git a/client/src/lists/segments/CUD.js b/client/src/lists/segments/CUD.js index ffe26768..537c3ad8 100644 --- a/client/src/lists/segments/CUD.js +++ b/client/src/lists/segments/CUD.js @@ -4,7 +4,16 @@ import React, {Component} from "react"; import PropTypes from "prop-types"; import {withTranslation} from '../../lib/i18n'; import {LinkButton, requiresAuthenticatedUser, Title, Toolbar, withPageHelpers} from "../../lib/page"; -import {ButtonRow, Dropdown, Form, FormSendMethod, InputField, withForm} from "../../lib/form"; +import { + ButtonRow, + Dropdown, + filterData, + Form, + FormSendMethod, + InputField, + withForm, + withFormErrorHandlers +} from "../../lib/form"; import {withErrorHandling} from "../../lib/error-handling"; import {DeleteModalDialog} from "../../lib/modals"; @@ -104,9 +113,14 @@ export default class CUD extends Component { }); } + submitFormValuesMutator(data) { + data.settings.rootRule.type = data.rootRuleType; + return filterData(data, ['name', 'settings']); + } + componentDidMount() { if (this.props.entity) { - this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator); + this.getFormValuesFromEntity(this.props.entity); } else { this.populateFormValues({ @@ -137,6 +151,7 @@ export default class CUD extends Component { } } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; @@ -153,21 +168,14 @@ export default class CUD extends Component { this.disableForm(); this.setFormStatusMessage('info', t('saving')); - const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { - const keep = ['name', 'settings', 'originalHash']; - - data.settings.rootRule.type = data.rootRuleType; - - delete data.rootRuleType; - delete data.selectedRule; - }); + const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url); if (submitResult) { if (this.props.entity) { if (submitAndLeave) { this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/segments`, 'success', t('Segment updated')); } else { - await this.getFormValuesFromURL(`rest/segments/${this.props.list.id}/${this.props.entity.id}`, ::this.getFormValuesMutator); + await this.getFormValuesFromURL(`rest/segments/${this.props.list.id}/${this.props.entity.id}`); this.enableForm(); this.setFormStatusMessage('success', t('Segment updated')); diff --git a/client/src/lists/segments/RuleSettingsPane.js b/client/src/lists/segments/RuleSettingsPane.js index 9c832e6e..d8b4728b 100644 --- a/client/src/lists/segments/RuleSettingsPane.js +++ b/client/src/lists/segments/RuleSettingsPane.js @@ -30,6 +30,7 @@ export default class RuleSettingsPane extends PureComponent { this.state = {}; this.initForm({ + leaveConfirmation: false, onChangeBeforeValidation: ::this.populateRuleDefaults, onChange: ::this.onFormChange }); diff --git a/client/src/lists/subscriptions/CUD.js b/client/src/lists/subscriptions/CUD.js index 2578ca00..18c02331 100644 --- a/client/src/lists/subscriptions/CUD.js +++ b/client/src/lists/subscriptions/CUD.js @@ -11,15 +11,17 @@ import { ButtonRow, CheckBox, Dropdown, + filterData, Form, FormSendMethod, InputField, - withForm + withForm, + withFormErrorHandlers } from '../../lib/form'; import {withErrorHandling} from '../../lib/error-handling'; import {RestActionModalDialog} from "../../lib/modals"; import interoperableErrors from '../../../../shared/interoperable-errors'; -import {SubscriptionStatus} from '../../../../shared/lists'; +import {getFieldColumn, SubscriptionStatus} from '../../../../shared/lists'; import {getFieldTypes, getSubscriptionStatusLabels} from './helpers'; import moment from 'moment-timezone'; import {withComponentMixins} from "../../lib/decorator-helpers"; @@ -67,9 +69,23 @@ export default class CUD extends Component { } } + submitFormValuesMutator(data) { + data.status = parseInt(data.status); + data.tz = data.tz || null; + + const allowedCols = ['email', 'tz', 'is_test', 'status']; + + for (const fld of this.props.fieldsGrouped) { + this.fieldTypes[fld.type].assignEntity(fld, data); + allowedCols.push(getFieldColumn(fld)); + } + + return filterData(data, allowedCols); + } + componentDidMount() { if (this.props.entity) { - this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator); + this.getFormValuesFromEntity(this.props.entity); } else { const data = { @@ -106,6 +122,7 @@ export default class CUD extends Component { } } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; @@ -122,21 +139,14 @@ export default class CUD extends Component { this.disableForm(); this.setFormStatusMessage('info', t('saving')); - const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { - data.status = parseInt(data.status); - data.tz = data.tz || null; - - for (const fld of this.props.fieldsGrouped) { - this.fieldTypes[fld.type].assignEntity(fld, data); - } - }); + const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url); if (submitResult) { if (this.props.entity) { if (submitAndLeave) { this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/subscriptions`, 'success', t('Subscription updated')); } else { - await this.getFormValuesFromURL(`rest/subscriptions/${this.props.list.id}/${this.props.entity.id}`, ::this.getFormValuesMutator); + await this.getFormValuesFromURL(`rest/subscriptions/${this.props.list.id}/${this.props.entity.id}`); this.enableForm(); this.setFormStatusMessage('success', t('Subscription updated')); } diff --git a/client/src/lists/subscriptions/List.js b/client/src/lists/subscriptions/List.js index 9343aef3..dad4c2c1 100644 --- a/client/src/lists/subscriptions/List.js +++ b/client/src/lists/subscriptions/List.js @@ -42,6 +42,7 @@ export default class List extends Component { this.fieldTypes = getFieldTypes(t); this.initForm({ + leaveConfirmation: false, onChange: { segment: (newState, key, oldValue, value) => { this.navigateTo(`/lists/${this.props.list.id}/subscriptions` + (value ? '?segment=' + value : '')); diff --git a/client/src/login/Forgot.js b/client/src/login/Forgot.js index 95ff2cf2..9957972e 100644 --- a/client/src/login/Forgot.js +++ b/client/src/login/Forgot.js @@ -19,7 +19,9 @@ export default class Forget extends Component { this.state = {}; - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } componentDidMount() { diff --git a/client/src/login/Login.js b/client/src/login/Login.js index a81af1f9..1942b639 100644 --- a/client/src/login/Login.js +++ b/client/src/login/Login.js @@ -33,7 +33,9 @@ export default class Login extends Component { this.state = {}; - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } componentDidMount() { diff --git a/client/src/login/Reset.js b/client/src/login/Reset.js index e17fd12d..4c6335a5 100644 --- a/client/src/login/Reset.js +++ b/client/src/login/Reset.js @@ -34,7 +34,9 @@ export default class Account extends Component { resetTokenValidationState: ResetTokenValidationState.PENDING }; - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } @withAsyncErrorHandler diff --git a/client/src/namespaces/CUD.js b/client/src/namespaces/CUD.js index 048d186d..8ab8e5ca 100644 --- a/client/src/namespaces/CUD.js +++ b/client/src/namespaces/CUD.js @@ -4,7 +4,18 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import {withTranslation} from '../lib/i18n'; import {LinkButton, requiresAuthenticatedUser, Title, withPageHelpers} from '../lib/page'; -import {Button, ButtonRow, Form, FormSendMethod, InputField, TextArea, TreeTableSelect, withForm} from '../lib/form'; +import { + Button, + ButtonRow, + filterData, + Form, + FormSendMethod, + InputField, + TextArea, + TreeTableSelect, + withForm, + withFormErrorHandlers +} from '../lib/form'; import axios from '../lib/axios'; import {withAsyncErrorHandler, withErrorHandling} from '../lib/error-handling'; import interoperableErrors from '../../../shared/interoperable-errors'; @@ -35,6 +46,10 @@ export default class CUD extends Component { entity: PropTypes.object } + submitFormValuesMutator(data) { + return filterData(data, ['name', 'description', 'namespace']); + } + isEditGlobal() { return this.props.entity && this.props.entity.id === getGlobalNamespaceId(); } @@ -106,6 +121,7 @@ export default class CUD extends Component { } } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; diff --git a/client/src/reports/CUD.js b/client/src/reports/CUD.js index 2741d49e..b7d8f9d5 100644 --- a/client/src/reports/CUD.js +++ b/client/src/reports/CUD.js @@ -8,13 +8,15 @@ import { Button, ButtonRow, Fieldset, + filterData, Form, FormSendMethod, InputField, TableSelect, TableSelectMode, TextArea, - withForm + withForm, + withFormErrorHandlers } from '../lib/form'; import axios from '../lib/axios'; import {withAsyncErrorHandler, withErrorHandling} from '../lib/error-handling'; @@ -73,9 +75,22 @@ export default class CUD extends Component { } } + submitFormValuesMutator(data) { + const params = {}; + + for (const spec of data.user_fields) { + const fldId = `param_${spec.id}`; + params[spec.id] = data[fldId]; + } + + data.params = params; + + return filterData(data, ['name', 'description', 'report_template', 'params', 'namespace']); + } + componentDidMount() { if (this.props.entity) { - this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator); + this.getFormValuesFromEntity(this.props.entity); } else { this.populateFormValues({ @@ -133,6 +148,7 @@ export default class CUD extends Component { validateNamespace(t, state); } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; @@ -153,25 +169,14 @@ export default class CUD extends Component { this.disableForm(); this.setFormStatusMessage('info', t('saving')); - const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { - const params = {}; - - for (const spec of data.user_fields) { - const fldId = `param_${spec.id}`; - params[spec.id] = data[fldId]; - delete data[fldId]; - } - - delete data.user_fields; - data.params = params; - }); + const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url); if (submitResult) { if (this.props.entity) { if (submitAndLeave) { this.navigateToWithFlashMessage('/reports', 'success', t('Report updated')); } else { - await this.getFormValuesFromURL(`rest/reports/${this.props.entity.id}`, ::this.getFormValuesMutator); + await this.getFormValuesFromURL(`rest/reports/${this.props.entity.id}`); this.enableForm(); this.setFormStatusMessage('success', t('Report updated')); } diff --git a/client/src/reports/templates/CUD.js b/client/src/reports/templates/CUD.js index 12155eb2..a7ec1330 100644 --- a/client/src/reports/templates/CUD.js +++ b/client/src/reports/templates/CUD.js @@ -10,11 +10,13 @@ import { Button, ButtonRow, Dropdown, + filterData, Form, FormSendMethod, InputField, TextArea, - withForm + withForm, + withFormErrorHandlers } from '../../lib/form'; import {withErrorHandling} from '../../lib/error-handling'; import {NamespaceSelect, validateNamespace} from '../../lib/namespace'; @@ -47,6 +49,10 @@ export default class CUD extends Component { entity: PropTypes.object } + submitFormValuesMutator(data) { + return filterData(data, ['name', 'description', 'mime_type', 'user_fields', 'js', 'hbs', 'namespace']); + } + componentDidMount() { if (this.props.entity) { this.getFormValuesFromEntity(this.props.entity); @@ -246,6 +252,7 @@ export default class CUD extends Component { validateNamespace(t, state); } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; diff --git a/client/src/send-configurations/CUD.js b/client/src/send-configurations/CUD.js index c0d8f605..eb5cc1f0 100644 --- a/client/src/send-configurations/CUD.js +++ b/client/src/send-configurations/CUD.js @@ -10,12 +10,14 @@ import { ButtonRow, CheckBox, Fieldset, + filterData, Form, FormSendMethod, InputField, StaticField, TextArea, - withForm + withForm, + withFormErrorHandlers } from '../lib/form'; import {withErrorHandling} from '../lib/error-handling'; import {NamespaceSelect, validateNamespace} from '../lib/namespace'; @@ -75,9 +77,15 @@ export default class CUD extends Component { data.verp_disable_sender_header = data.verpEnabled ? !!data.verp_disable_sender_header : false; } + submitFormValuesMutator(data) { + return filterData(data, ['name', 'description', 'from_email', 'from_email_overridable', 'from_name', + 'from_name_overridable', 'reply_to', 'reply_to_overridable', 'subject', 'subject_overridable', 'x_mailer', + 'verp_hostname', 'verp_disable_sender_header', 'mailer_type', 'mailer_settings', 'namespace']); + } + componentDidMount() { if (this.props.entity) { - this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator); + this.getFormValuesFromEntity(this.props.entity); } else { this.populateFormValues({ name: '', @@ -131,6 +139,7 @@ export default class CUD extends Component { } } + @withFormErrorHandlers async submitHandler(submitAndLeave) { const t = this.props.t; @@ -159,7 +168,7 @@ export default class CUD extends Component { if (submitAndLeave) { this.navigateToWithFlashMessage('/send-configurations', 'success', t('Send configuration updated')); } else { - await this.getFormValuesFromURL(`rest/send-configurations-private/${this.props.entity.id}`, ::this.getFormValuesMutator); + await this.getFormValuesFromURL(`rest/send-configurations-private/${this.props.entity.id}`); this.enableForm(); this.setFormStatusMessage('success', t('Send configuration updated')); } diff --git a/client/src/settings/Update.js b/client/src/settings/Update.js index 10bcb8cf..27a26bd0 100644 --- a/client/src/settings/Update.js +++ b/client/src/settings/Update.js @@ -9,6 +9,7 @@ import { Button, ButtonRow, Fieldset, + filterData, Form, FormSendMethod, InputField, @@ -39,6 +40,10 @@ export default class Update extends Component { entity: PropTypes.object } + submitFormValuesMutator(data) { + return filterData(data, ['adminEmail', 'uaCode', 'mapsApiKey', 'shoutout', 'pgpPassphrase', 'pgpPrivateKey', 'defaultHomepage']); + } + componentDidMount() { this.getFormValuesFromEntity(this.props.entity); } diff --git a/client/src/shares/Share.js b/client/src/shares/Share.js index ef711cb9..4a729bb2 100644 --- a/client/src/shares/Share.js +++ b/client/src/shares/Share.js @@ -23,7 +23,9 @@ export default class Share extends Component { constructor(props) { super(props); - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } static propTypes = { diff --git a/client/src/templates/CUD.js b/client/src/templates/CUD.js index be51c0e3..974e02bb 100644 --- a/client/src/templates/CUD.js +++ b/client/src/templates/CUD.js @@ -55,8 +55,6 @@ export default class CUD extends Component { }; this.initForm({ - loadMutator: ::this.getFormValuesMutator, - submitMutator: ::this.submitFormValuesMutator, getPreSubmitUpdater: ::this.getPreSubmitFormValuesUpdater, onChangeBeforeValidation: { type: ::this.onTypeChanged diff --git a/client/src/templates/TestSendModalDialog.js b/client/src/templates/TestSendModalDialog.js index 2548c65d..5d72d65a 100644 --- a/client/src/templates/TestSendModalDialog.js +++ b/client/src/templates/TestSendModalDialog.js @@ -27,7 +27,9 @@ export class TestSendModalDialog extends Component { this.mailerTypes = getMailerTypes(props.t); - this.initForm(); + this.initForm({ + leaveConfirmation: false + }); } static propTypes = { diff --git a/client/src/templates/mosaico/CUD.js b/client/src/templates/mosaico/CUD.js index e0425f46..6d5c56ac 100644 --- a/client/src/templates/mosaico/CUD.js +++ b/client/src/templates/mosaico/CUD.js @@ -49,10 +49,7 @@ export default class CUD extends Component { this.state = {}; - this.initForm({ - loadMutator: ::this.getFormValuesMutator, - submitMutator: ::this.submitFormValuesMutator - }); + this.initForm(); } static propTypes = { diff --git a/client/src/users/CUD.js b/client/src/users/CUD.js index a21c3741..9a9301f9 100644 --- a/client/src/users/CUD.js +++ b/client/src/users/CUD.js @@ -39,8 +39,6 @@ export default class CUD extends Component { this.state = {}; this.initForm({ - loadMutator: ::this.getFormValuesMutator, - submitMutator: ::this.submitFormValuesMutator, serverValidation: { url: 'rest/users-validate', changed: mailtrainConfig.isAuthMethodLocal ? ['username', 'email'] : ['username'], diff --git a/mvis/ivis-core b/mvis/ivis-core index 885ee383..ec89af43 160000 --- a/mvis/ivis-core +++ b/mvis/ivis-core @@ -1 +1 @@ -Subproject commit 885ee383bd508eb7a872afb5208259d694a7c255 +Subproject commit ec89af43120f95dcf7f14dc92a2b3811bf50d7e8