Addresses #785 "Allow segmentation by Subscription Status"

This commit is contained in:
Tomas Bures 2020-01-03 14:27:47 +01:00
parent d340a803e1
commit d7d626cbc0
6 changed files with 174 additions and 69 deletions

View file

@ -6,22 +6,22 @@ export function getFieldTypes(t) {
const fieldTypes = { const fieldTypes = {
text: { text: {
label: t('text'), label: t('text')
}, },
website: { website: {
label: t('website'), label: t('website')
}, },
longtext: { longtext: {
label: t('multilineText'), label: t('multilineText')
}, },
gpg: { gpg: {
label: t('gpgPublicKey'), label: t('gpgPublicKey')
}, },
number: { number: {
label: t('number'), label: t('number')
}, },
'checkbox-grouped': { 'checkbox-grouped': {
label: t('checkboxesFromOptionFields'), label: t('checkboxesFromOptionFields')
}, },
'radio-grouped': { 'radio-grouped': {
label: t('radioButtonsFromOptionFields') label: t('radioButtonsFromOptionFields')

View file

@ -90,8 +90,8 @@ export default class CUD extends Component {
const tree = []; const tree = [];
for (const rule of rules) { for (const rule of rules) {
const ruleTypeSettings = ruleHelpers.getRuleTypeSettings(rule); const ruleTreeLabel = ruleHelpers.getTreeLabel(rule);
const title = ruleTypeSettings ? ruleTypeSettings.treeLabel(rule) : this.props.t('newRule'); const title = ruleTreeLabel || this.props.t('newRule');
tree.push({ tree.push({
rule, rule,

View file

@ -25,7 +25,7 @@ export default class RuleSettingsPane extends PureComponent {
const t = props.t; const t = props.t;
this.ruleHelpers = getRuleHelpers(t, props.fields); this.ruleHelpers = getRuleHelpers(t, props.fields);
this.fieldTypes = getFieldTypes(t); this.fieldTypes = { ...getFieldTypes(t), ...this.ruleHelpers.extraFieldTypes };
this.state = {}; this.state = {};
@ -54,9 +54,11 @@ export default class RuleSettingsPane extends PureComponent {
if (!ruleHelpers.isCompositeRuleType(rule.type)) { // rule.type === null signifies primitive rule where the type has not been determined yet if (!ruleHelpers.isCompositeRuleType(rule.type)) { // rule.type === null signifies primitive rule where the type has not been determined yet
data = ruleHelpers.primitiveRuleTypesFormDataDefaults; data = ruleHelpers.primitiveRuleTypesFormDataDefaults;
const settings = ruleHelpers.getRuleTypeSettings(rule); const colDef = ruleHelpers.getColumnDef(rule.column);
if (settings) { if (colDef) {
Object.assign(data, settings.getFormData(rule)); const colType = colDef.type;
const settings = ruleHelpers.primitiveRuleTypes[colType][rule.type];
Object.assign(data, settings.getFormData(rule, colDef));
} }
data.type = rule.type || ''; // On '', we display label "--SELECT--" in the type dropdown. Null would not be accepted by React. data.type = rule.type || ''; // On '', we display label "--SELECT--" in the type dropdown. Null would not be accepted by React.
@ -92,8 +94,10 @@ export default class RuleSettingsPane extends PureComponent {
if (!ruleHelpers.isCompositeRuleType(rule.type)) { if (!ruleHelpers.isCompositeRuleType(rule.type)) {
rule.column = this.getFormValue('column'); rule.column = this.getFormValue('column');
const settings = this.ruleHelpers.getRuleTypeSettings(rule); const colDef = ruleHelpers.getColumnDef(rule.column);
settings.assignRuleSettings(rule, key => this.getFormValue(key)); const colType = colDef.type;
const settings = ruleHelpers.primitiveRuleTypes[colType][rule.type];
settings.assignRuleSettings(rule, key => this.getFormValue(key), colDef);
} }
this.props.onChange(false); this.props.onChange(false);
@ -118,11 +122,12 @@ export default class RuleSettingsPane extends PureComponent {
const column = state.getIn(['column', 'value']); const column = state.getIn(['column', 'value']);
if (column) { if (column) {
const colType = ruleHelpers.getColumnType(column); const colDef = ruleHelpers.getColumnDef(column);
if (ruleType) { if (ruleType) {
const colType = colDef.type;
const settings = ruleHelpers.primitiveRuleTypes[colType][ruleType]; const settings = ruleHelpers.primitiveRuleTypes[colType][ruleType];
settings.validate(state); settings.validate(state, colDef);
} }
} else { } else {
state.setIn(['column', 'error'], t('fieldMustBeSelected')); state.setIn(['column', 'error'], t('fieldMustBeSelected'));
@ -138,9 +143,10 @@ export default class RuleSettingsPane extends PureComponent {
const column = mutStateData.getIn(['column', 'value']); const column = mutStateData.getIn(['column', 'value']);
if (column) { if (column) {
const colType = ruleHelpers.getColumnType(column); const colDef = ruleHelpers.getColumnDef(column);
if (type) { if (type) {
const colType = colDef.type;
const settings = ruleHelpers.primitiveRuleTypes[colType][type]; const settings = ruleHelpers.primitiveRuleTypes[colType][type];
if (!settings) { if (!settings) {
// The existing rule type does not fit the newly changed column. This resets the rule type chooser to "--- Select ---" // The existing rule type does not fit the newly changed column. This resets the rule type chooser to "--- Select ---"
@ -187,8 +193,9 @@ export default class RuleSettingsPane extends PureComponent {
const ruleColumn = this.getFormValue('column'); const ruleColumn = this.getFormValue('column');
if (ruleColumn) { if (ruleColumn) {
const colType = ruleHelpers.getColumnType(ruleColumn); const colDef = ruleHelpers.getColumnDef(ruleColumn);
if (colType) { if (colDef) {
const colType = colDef.type;
const ruleTypeOptions = ruleHelpers.getPrimitiveRuleTypeOptions(colType); const ruleTypeOptions = ruleHelpers.getPrimitiveRuleTypeOptions(colType);
ruleTypeOptions.unshift({ key: '', label: t('select-1')}); ruleTypeOptions.unshift({ key: '', label: t('select-1')});
@ -197,7 +204,7 @@ export default class RuleSettingsPane extends PureComponent {
const ruleType = this.getFormValue('type'); const ruleType = this.getFormValue('type');
if (ruleType) { if (ruleType) {
ruleSettings = ruleHelpers.primitiveRuleTypes[colType][ruleType].getForm(); ruleSettings = ruleHelpers.primitiveRuleTypes[colType][ruleType].getForm(colDef);
} }
} }
} }

View file

@ -214,16 +214,23 @@ export function getRuleHelpers(t, fields) {
} }
}; };
ruleHelpers.primitiveRuleTypes['dropdown-static'] = {
eq: {
dropdownLabel: t('equalTo'),
treeLabel: rule => t('valueInColumnColNameIsEqualToValue', {colName: ruleHelpers.getColumnName(rule.column), value: rule.value}),
}
};
const stringValueSettings = allowEmpty => ({ const stringValueSettings = allowEmpty => ({
getForm: () => <InputField id="value" label={t('value')} />, getForm: fldDef => <InputField id="value" label={t('value')} />,
getFormData: rule => ({ getFormData: (rule, fldDef) => ({
value: rule.value value: rule.value
}), }),
assignRuleSettings: (rule, getter) => { assignRuleSettings: (rule, getter, fldDef) => {
rule.value = getter('value'); rule.value = getter('value');
}, },
validate: state => { validate: (state, fldDef) => {
if (!allowEmpty && !state.getIn(['value', 'value'])) { if (!allowEmpty && !state.getIn(['value', 'value'])) {
state.setIn(['value', 'error'], t('valueMustNotBeEmpty')); state.setIn(['value', 'error'], t('valueMustNotBeEmpty'));
} else { } else {
@ -233,14 +240,14 @@ export function getRuleHelpers(t, fields) {
}); });
const numberValueSettings = { const numberValueSettings = {
getForm: () => <InputField id="value" label={t('value')} />, getForm: fldDef => <InputField id="value" label={t('value')} />,
getFormData: rule => ({ getFormData: (rule, fldDef) => ({
value: rule.value.toString() value: rule.value.toString()
}), }),
assignRuleSettings: (rule, getter) => { assignRuleSettings: (rule, getter, fldDef) => {
rule.value = parseInt(getter('value')); rule.value = parseInt(getter('value'));
}, },
validate: state => { validate: (state, fldDef) => {
const value = state.getIn(['value', 'value']).trim(); const value = state.getIn(['value', 'value']).trim();
if (value === '') { if (value === '') {
state.setIn(['value', 'error'], t('valueMustNotBeEmpty')); state.setIn(['value', 'error'], t('valueMustNotBeEmpty'));
@ -253,14 +260,14 @@ export function getRuleHelpers(t, fields) {
}; };
const birthdayValueSettings = { const birthdayValueSettings = {
getForm: () => <DatePicker id="birthday" label={t('date')} birthday />, getForm: fldDef => <DatePicker id="birthday" label={t('date')} birthday />,
getFormData: rule => ({ getFormData: (rule, fldDef) => ({
birthday: formatBirthday(DateFormat.INTL, rule.value) birthday: formatBirthday(DateFormat.INTL, rule.value)
}), }),
assignRuleSettings: (rule, getter) => { assignRuleSettings: (rule, getter, fldDef) => {
rule.value = parseBirthday(DateFormat.INTL, getter('birthday')).toISOString(); rule.value = parseBirthday(DateFormat.INTL, getter('birthday')).toISOString();
}, },
validate: state => { validate: (state, fldDef) => {
const value = state.getIn(['birthday', 'value']); const value = state.getIn(['birthday', 'value']);
const date = parseBirthday(DateFormat.INTL, value); const date = parseBirthday(DateFormat.INTL, value);
if (!value) { if (!value) {
@ -274,14 +281,14 @@ export function getRuleHelpers(t, fields) {
}; };
const dateValueSettings = { const dateValueSettings = {
getForm: () => <DatePicker id="date" label={t('date')} />, getForm: fldDef => <DatePicker id="date" label={t('date')} />,
getFormData: rule => ({ getFormData: (rule, fldDef) => ({
date: formatDate(DateFormat.INTL, rule.value) date: formatDate(DateFormat.INTL, rule.value)
}), }),
assignRuleSettings: (rule, getter) => { assignRuleSettings: (rule, getter, fldDef) => {
rule.value = parseDate(DateFormat.INTL, getter('date')).toISOString(); rule.value = parseDate(DateFormat.INTL, getter('date')).toISOString();
}, },
validate: state => { validate: (state, fldDef) => {
const value = state.getIn(['date', 'value']); const value = state.getIn(['date', 'value']);
const date = parseDate(DateFormat.INTL, value); const date = parseDate(DateFormat.INTL, value);
if (!value) { if (!value) {
@ -295,7 +302,7 @@ export function getRuleHelpers(t, fields) {
}; };
const dateRelativeValueSettings = { const dateRelativeValueSettings = {
getForm: () => getForm: fldDef =>
<div> <div>
<InputField id="daysValue" label={t('numberOfDays')}/> <InputField id="daysValue" label={t('numberOfDays')}/>
<Dropdown id="direction" label={t('beforeAfter')} options={[ <Dropdown id="direction" label={t('beforeAfter')} options={[
@ -303,15 +310,15 @@ export function getRuleHelpers(t, fields) {
{ key: 'after', label: t('afterCurrentDate') } { key: 'after', label: t('afterCurrentDate') }
]}/> ]}/>
</div>, </div>,
getFormData: rule => ({ getFormData: (rule, fldDef) => ({
daysValue: Math.abs(rule.value).toString(), daysValue: Math.abs(rule.value).toString(),
direction: rule.value >= 0 ? 'after' : 'before' direction: rule.value >= 0 ? 'after' : 'before'
}), }),
assignRuleSettings: (rule, getter) => { assignRuleSettings: (rule, getter, fldDef) => {
const direction = getter('direction'); const direction = getter('direction');
rule.value = parseInt(getter('daysValue')) * (direction === 'before' ? -1 : 1); rule.value = parseInt(getter('daysValue')) * (direction === 'before' ? -1 : 1);
}, },
validate: state => { validate: (state, fldDef) => {
const value = state.getIn(['daysValue', 'value']); const value = state.getIn(['daysValue', 'value']);
if (!value) { if (!value) {
state.setIn(['daysValue', 'error'], t('numberOfDaysMustNotBeEmpty')); state.setIn(['daysValue', 'error'], t('numberOfDaysMustNotBeEmpty'));
@ -324,12 +331,45 @@ export function getRuleHelpers(t, fields) {
}; };
const optionValueSettings = { const optionValueSettings = {
getForm: () => null, getForm: fldDef => null,
getFormData: rule => ({}), getFormData: (rule, fldDef) => ({}),
assignRuleSettings: (rule, getter) => {}, assignRuleSettings: (rule, getter, fldDef) => {},
validate: state => {} validate: state => {}
}; };
const staticEnumValueSettings = {
getForm: fldDef => {
const opts = [];
for (const opt in fldDef.options) {
opts.push({key: opt, label: fldDef.options[opt]});
}
return <Dropdown id="value" label={t('value')} options={opts}/>;
},
getFormData: (rule, fldDef) => {
let value;
if (rule.value in fldDef.options) {
value = rule.value;
} else {
value = fldDef.default
}
return {
value
};
},
assignRuleSettings: (rule, getter, fldDef) => {
let value = getter('value');
if (!(value in fldDef.options)) {
value = fldDef.default
}
rule.value = value;
},
validate: (state, fldDef) => {
}
};
function assignSettingsToRuleTypes(ruleTypes, keys, settings) { function assignSettingsToRuleTypes(ruleTypes, keys, settings) {
for (const key of keys) { for (const key of keys) {
@ -349,6 +389,7 @@ export function getRuleHelpers(t, fields) {
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['dropdown-enum'], ['lt', 'le', 'gt', 'ge'], stringValueSettings(false)); assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['dropdown-enum'], ['lt', 'le', 'gt', 'ge'], stringValueSettings(false));
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['radio-enum'], ['eq', 'like', 're'], stringValueSettings(true)); assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['radio-enum'], ['eq', 'like', 're'], stringValueSettings(true));
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['radio-enum'], ['lt', 'le', 'gt', 'ge'], stringValueSettings(false)); assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['radio-enum'], ['lt', 'le', 'gt', 'ge'], stringValueSettings(false));
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['dropdown-static'], ['eq'], staticEnumValueSettings);
ruleHelpers.primitiveRuleTypesFormDataDefaults = { ruleHelpers.primitiveRuleTypesFormDataDefaults = {
value: '', value: '',
@ -374,7 +415,8 @@ export function getRuleHelpers(t, fields) {
date: ['eq', 'lt', 'le', 'gt', 'ge', 'eqTodayPlusDays', 'ltTodayPlusDays', 'leTodayPlusDays', 'gtTodayPlusDays', 'geTodayPlusDays'], date: ['eq', 'lt', 'le', 'gt', 'ge', 'eqTodayPlusDays', 'ltTodayPlusDays', 'leTodayPlusDays', 'gtTodayPlusDays', 'geTodayPlusDays'],
option: ['isTrue', 'isFalse'], option: ['isTrue', 'isFalse'],
'dropdown-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge'], 'dropdown-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge'],
'radio-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge'] 'radio-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge'],
'dropdown-static': ['eq'],
}; };
return order[columnType].map(key => ({ key, label: ruleHelpers.primitiveRuleTypes[columnType][key].dropdownLabel })); return order[columnType].map(key => ({ key, label: ruleHelpers.primitiveRuleTypes[columnType][key].dropdownLabel }));
@ -411,7 +453,20 @@ export function getRuleHelpers(t, fields) {
column: 'is_test', column: 'is_test',
name: t('testUser'), name: t('testUser'),
type: 'option' type: 'option'
},
{
column: 'status',
name: t('Status'),
type: 'dropdown-static',
options: {
subscribed: t('Subscribed'),
unsubscribed: t('Unsubscribed'),
bounced: t('Bounced'),
complained: t('Complained')
},
default: 'subscribed'
} }
]; ];
ruleHelpers.fields = [ ruleHelpers.fields = [
@ -424,10 +479,10 @@ export function getRuleHelpers(t, fields) {
ruleHelpers.fieldsByColumn[fld.column] = fld; ruleHelpers.fieldsByColumn[fld.column] = fld;
} }
ruleHelpers.getColumnType = column => { ruleHelpers.getColumnDef = column => {
const field = ruleHelpers.fieldsByColumn[column]; const field = ruleHelpers.fieldsByColumn[column];
if (field) { if (field) {
return field.type; return field;
} }
}; };
@ -438,21 +493,29 @@ export function getRuleHelpers(t, fields) {
} }
}; };
ruleHelpers.getRuleTypeSettings = rule => { ruleHelpers.isCompositeRuleType = ruleType => ruleType in ruleHelpers.compositeRuleTypes;
if (ruleHelpers.isCompositeRuleType(rule.type)) {
return ruleHelpers.compositeRuleTypes[rule.type];
} else {
const colType = ruleHelpers.getColumnType(rule.column);
if (colType) { ruleHelpers.getTreeLabel = rule => {
if (ruleHelpers.isCompositeRuleType(rule.type)) {
return ruleHelpers.compositeRuleTypes[rule.type].treeLabel(rule);
} else {
const colDef = ruleHelpers.getColumnDef(rule.column);
if (colDef) {
const colType = colDef.type;
if (rule.type in ruleHelpers.primitiveRuleTypes[colType]) { if (rule.type in ruleHelpers.primitiveRuleTypes[colType]) {
return ruleHelpers.primitiveRuleTypes[colType][rule.type]; return ruleHelpers.primitiveRuleTypes[colType][rule.type].treeLabel(rule);
} }
} }
} }
}; };
ruleHelpers.isCompositeRuleType = ruleType => ruleType in ruleHelpers.compositeRuleTypes;
ruleHelpers.extraFieldTypes = {
'dropdown-static': {
label: t('Dropdown')
}
};
return ruleHelpers; return ruleHelpers;
} }

View file

@ -12,6 +12,7 @@ const subscriptions = require('./subscriptions');
const dependencyHelpers = require('../lib/dependency-helpers'); const dependencyHelpers = require('../lib/dependency-helpers');
const {ListActivityType} = require('../../shared/activity-log'); const {ListActivityType} = require('../../shared/activity-log');
const activityLog = require('../lib/activity-log'); const activityLog = require('../lib/activity-log');
const {SubscriptionStatus} = require('../../shared/lists');
const allowedKeys = new Set(['name', 'settings']); const allowedKeys = new Set(['name', 'settings']);
@ -41,6 +42,16 @@ const predefColumns = [
{ {
column: 'is_test', column: 'is_test',
type: 'option' type: 'option'
},
{
column: 'status',
type: 'dropdown-static',
options: {
subscribed: 1,
unsubscribed: 2,
bounced: 3,
complained: 4
}
} }
]; ];
@ -85,36 +96,37 @@ const primitiveRuleTypes = {
birthday: {}, birthday: {},
option: {}, option: {},
'dropdown-enum': {}, 'dropdown-enum': {},
'radio-enum': {} 'radio-enum': {},
'dropdown-static': {}
}; };
function stringValueSettings(sqlOperator, allowEmpty) { function stringValueSettings(sqlOperator, allowEmpty) {
return { return {
validate: rule => { validate: (rule, fldDef) => {
enforce(typeof rule.value === 'string', 'Invalid value type in rule'); enforce(typeof rule.value === 'string', 'Invalid value type in rule');
enforce(allowEmpty || rule.value, 'Value in rule must not be empty'); enforce(allowEmpty || rule.value, 'Value in rule must not be empty');
}, },
addQuery: (subsTableName, query, rule) => query.where(subsTableName + '. ' + rule.column, sqlOperator, rule.value) addQuery: (subsTableName, query, rule, fldDef) => query.where(subsTableName + '. ' + rule.column, sqlOperator, rule.value)
}; };
} }
function numberValueSettings(sqlOperator) { function numberValueSettings(sqlOperator) {
return { return {
validate: rule => { validate: (rule, fldDef) => {
enforce(typeof rule.value === 'number', 'Invalid value type in rule'); enforce(typeof rule.value === 'number', 'Invalid value type in rule');
}, },
addQuery: (subsTableName, query, rule) => query.where(subsTableName + '. ' + rule.column, sqlOperator, rule.value) addQuery: (subsTableName, query, rule, fldDef) => query.where(subsTableName + '. ' + rule.column, sqlOperator, rule.value)
}; };
} }
function dateValueSettings(thisDaySqlOperator, nextDaySqlOperator) { function dateValueSettings(thisDaySqlOperator, nextDaySqlOperator) {
return { return {
validate: rule => { validate: (rule, fldDef) => {
const date = moment.utc(rule.value); const date = moment.utc(rule.value);
enforce(date.isValid(), 'Invalid date value'); enforce(date.isValid(), 'Invalid date value');
}, },
addQuery: (subsTableName, query, rule) => { addQuery: (subsTableName, query, rule, fldDef) => {
const thisDay = moment.utc(rule.value).startOf('day'); const thisDay = moment.utc(rule.value).startOf('day');
const nextDay = moment(thisDay).add(1, 'days'); const nextDay = moment(thisDay).add(1, 'days');
@ -131,10 +143,10 @@ function dateValueSettings(thisDaySqlOperator, nextDaySqlOperator) {
function dateRelativeValueSettings(todaySqlOperator, tomorrowSqlOperator) { function dateRelativeValueSettings(todaySqlOperator, tomorrowSqlOperator) {
return { return {
validate: rule => { validate: (rule, fldDef) => {
enforce(typeof rule.value === 'number', 'Invalid value type in rule'); enforce(typeof rule.value === 'number', 'Invalid value type in rule');
}, },
addQuery: (subsTableName, query, rule) => { addQuery: (subsTableName, query, rule, fldDef) => {
const todayWithOffset = moment.utc().startOf('day').add(rule.value, 'days'); const todayWithOffset = moment.utc().startOf('day').add(rule.value, 'days');
const tomorrowWithOffset = moment(todayWithOffset).add(1, 'days'); const tomorrowWithOffset = moment(todayWithOffset).add(1, 'days');
@ -151,8 +163,18 @@ function dateRelativeValueSettings(todaySqlOperator, tomorrowSqlOperator) {
function optionValueSettings(value) { function optionValueSettings(value) {
return { return {
validate: rule => {}, validate: (rule, fldDef) => {},
addQuery: (subsTableName, query, rule) => query.where(subsTableName + '. ' + rule.column, value) addQuery: (subsTableName, query, rule, fldDef) => query.where(subsTableName + '. ' + rule.column, value)
};
}
function staticEnumValueSettings(sqlOperator) {
return {
validate: (rule, fldDef) => {
enforce(rule.value, 'Value in rule must not be empty');
enforce(rule.value in fldDef.options, 'Value is not permitted')
},
addQuery: (subsTableName, query, rule, fldDef) => query.where(subsTableName + '. ' + rule.column, sqlOperator, fldDef.options[rule.value])
}; };
} }
@ -212,6 +234,15 @@ primitiveRuleTypes['radio-enum'].le = stringValueSettings('<=', false);
primitiveRuleTypes['radio-enum'].gt = stringValueSettings('>', false); primitiveRuleTypes['radio-enum'].gt = stringValueSettings('>', false);
primitiveRuleTypes['radio-enum'].ge = stringValueSettings('>=', false); primitiveRuleTypes['radio-enum'].ge = stringValueSettings('>=', false);
primitiveRuleTypes['radio-enum'].eq = stringValueSettings('=', true);
primitiveRuleTypes['radio-enum'].like = stringValueSettings('LIKE', true);
primitiveRuleTypes['radio-enum'].re = stringValueSettings('REGEXP', true);
primitiveRuleTypes['radio-enum'].lt = stringValueSettings('<', false);
primitiveRuleTypes['radio-enum'].le = stringValueSettings('<=', false);
primitiveRuleTypes['radio-enum'].gt = stringValueSettings('>', false);
primitiveRuleTypes['radio-enum'].ge = stringValueSettings('>=', false);
primitiveRuleTypes['dropdown-static'].eq = staticEnumValueSettings('=', true);
function hash(entity) { function hash(entity) {
@ -283,8 +314,9 @@ async function _validateAndPreprocess(tx, listId, entity, isCreate) {
validateRule(childRule); validateRule(childRule);
} }
} else { } else {
const colType = fieldsByColumn[rule.column].type; const fldDef = fieldsByColumn[rule.column];
primitiveRuleTypes[colType][rule.type].validate(rule); const colType = fldDef.type;
primitiveRuleTypes[colType][rule.type].validate(rule, fldDef);
} }
} }
@ -421,8 +453,9 @@ async function getQueryGeneratorTx(tx, listId, id) {
processRule(subQuery, childRule); processRule(subQuery, childRule);
}); });
} else { } else {
const colType = fieldsByColumn[rule.column].type; const fldDef = fieldsByColumn[rule.column];
primitiveRuleTypes[colType][rule.type].addQuery(subsTableName, query, rule); const colType = fldDef.type;
primitiveRuleTypes[colType][rule.type].addQuery(subsTableName, query, rule, fldDef);
} }
} }

View file

@ -6,6 +6,8 @@ const mailers = require('../lib/mailers');
const messageSender = require('../lib/message-sender'); const messageSender = require('../lib/message-sender');
const {CampaignTrackerActivityType} = require('../../shared/activity-log'); const {CampaignTrackerActivityType} = require('../../shared/activity-log');
const activityLog = require('../lib/activity-log'); const activityLog = require('../lib/activity-log');
// TODO - use extension manager to add check to cleanExit (in fork) that waits for sendRegularCampaignMessage or sendQueuedMessage to finish
require('../lib/fork'); require('../lib/fork');
const MessageType = messageSender.MessageType; const MessageType = messageSender.MessageType;