CUD operations on reports and report templates seem to work
Execution of reports is TBD
This commit is contained in:
parent
38cf3e49c0
commit
6d95fa515e
18 changed files with 273 additions and 46 deletions
24
app.js
24
app.js
|
@ -40,11 +40,13 @@ const editorapi = require('./routes/editorapi');
|
|||
const grapejs = require('./routes/grapejs');
|
||||
const mosaico = require('./routes/mosaico');
|
||||
|
||||
const namespaces = require('./routes/rest/namespaces');
|
||||
const users = require('./routes/rest/users');
|
||||
const account = require('./routes/rest/account');
|
||||
const reportTemplates = require('./routes/rest/report-templates');
|
||||
const reports = require('./routes/rest/reports');
|
||||
const namespacesRest = require('./routes/rest/namespaces');
|
||||
const usersRest = require('./routes/rest/users');
|
||||
const accountRest = require('./routes/rest/account');
|
||||
const reportTemplatesRest = require('./routes/rest/report-templates');
|
||||
const reportsRest = require('./routes/rest/reports');
|
||||
const campaignsRest = require('./routes/rest/campaigns');
|
||||
const listsRest = require('./routes/rest/lists');
|
||||
|
||||
const namespacesLegacyIntegration = require('./routes/namespaces-legacy-integration');
|
||||
const usersLegacyIntegration = require('./routes/users-legacy-integration');
|
||||
|
@ -257,13 +259,15 @@ app.all('/rest/*', (req, res, next) => {
|
|||
next();
|
||||
});
|
||||
|
||||
app.use('/rest', namespaces);
|
||||
app.use('/rest', users);
|
||||
app.use('/rest', account);
|
||||
app.use('/rest', namespacesRest);
|
||||
app.use('/rest', usersRest);
|
||||
app.use('/rest', accountRest);
|
||||
app.use('/rest', campaignsRest);
|
||||
app.use('/rest', listsRest);
|
||||
|
||||
if (config.reports && config.reports.enabled === true) {
|
||||
app.use('/rest', reportTemplates);
|
||||
app.use('/rest', reports);
|
||||
app.use('/rest', reportTemplatesRest);
|
||||
app.use('/rest', reportsRest);
|
||||
}
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
|
|
|
@ -402,6 +402,7 @@ class TableSelect extends Component {
|
|||
columns: PropTypes.array,
|
||||
selectionKeyIndex: PropTypes.number,
|
||||
selectionLabelIndex: PropTypes.number,
|
||||
selectionAsArray: PropTypes.bool,
|
||||
selectMode: PropTypes.number,
|
||||
withHeader: PropTypes.bool,
|
||||
dropdown: PropTypes.bool,
|
||||
|
@ -432,9 +433,19 @@ class TableSelect extends Component {
|
|||
}
|
||||
|
||||
async onSelectionDataAsync(sel, data) {
|
||||
if (this.props.selectMode === TableSelectMode.SINGLE && this.props.dropdown) {
|
||||
if (this.props.dropdown) {
|
||||
let label;
|
||||
|
||||
if (!data) {
|
||||
label = '';
|
||||
} else if (this.props.selectMode === TableSelectMode.SINGLE && !this.props.selectionAsArray) {
|
||||
label = data[this.props.selectionLabelIndex];
|
||||
} else {
|
||||
label = data.map(entry => entry[this.props.selectionLabelIndex]).join('; ');
|
||||
}
|
||||
|
||||
this.setState({
|
||||
selectedLabel: data ? data[this.props.selectionLabelIndex] : ''
|
||||
selectedLabel: label
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -462,7 +473,7 @@ class TableSelect extends Component {
|
|||
</span>
|
||||
</div>
|
||||
<div className={'mt-tableselect-table' + (this.state.open ? '' : ' mt-tableselect-table-hidden')}>
|
||||
<Table dataUrl={props.dataUrl} columns={props.columns} selectMode={props.selectMode} withHeader={props.withHeader} selection={owner.getFormValue(id)} onSelectionDataAsync={::this.onSelectionDataAsync} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||
<Table dataUrl={props.dataUrl} columns={props.columns} selectMode={props.selectMode} selectionAsArray={this.props.selectionAsArray} withHeader={props.withHeader} selection={owner.getFormValue(id)} onSelectionDataAsync={::this.onSelectionDataAsync} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -470,7 +481,7 @@ class TableSelect extends Component {
|
|||
return wrapInput(id, htmlId, owner, props.label, props.help,
|
||||
<div>
|
||||
<div>
|
||||
<Table dataUrl={props.dataUrl} columns={props.columns} selectMode={props.selectMode} withHeader={props.withHeader} selection={owner.getFormValue(id)} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||
<Table dataUrl={props.dataUrl} columns={props.columns} selectMode={props.selectMode} selectionAsArray={this.props.selectionAsArray} withHeader={props.withHeader} selection={owner.getFormValue(id)} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -706,12 +717,24 @@ function withForm(target) {
|
|||
};
|
||||
|
||||
inst.updateFormValue = function(key, value) {
|
||||
this.setState(previousState => ({
|
||||
formState: previousState.formState.withMutations(mutState => {
|
||||
mutState.setIn(['data', key, 'value'], value);
|
||||
validateFormState(this, mutState);
|
||||
})
|
||||
}));
|
||||
this.setState(previousState => {
|
||||
const oldValue = previousState.formState.getIn(['data', key, 'value']);
|
||||
|
||||
let newState = {
|
||||
formState: previousState.formState.withMutations(mutState => {
|
||||
mutState.setIn(['data', key, 'value'], value);
|
||||
validateFormState(this, mutState);
|
||||
})
|
||||
};
|
||||
|
||||
const onChangeCallbacks = this.state.formSettings.onChange || {};
|
||||
|
||||
if (onChangeCallbacks[key]) {
|
||||
onChangeCallbacks[key](newState, key, oldValue, value);
|
||||
}
|
||||
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
inst.getFormValue = function(name) {
|
||||
|
|
|
@ -205,8 +205,10 @@ class SectionContent extends Component {
|
|||
/* FIXME, once we turn Mailtrain to single-page application, this should become navigateTo */
|
||||
window.location = '/account/login?next=' + encodeURIComponent(this.props.root);
|
||||
} else if (error.response && error.response.data && error.response.data.message) {
|
||||
console.error(error);
|
||||
this.navigateToWithFlashMessage(this.props.root, 'danger', error.response.data.message);
|
||||
} else {
|
||||
console.error(error);
|
||||
this.navigateToWithFlashMessage(this.props.root, 'danger', error.message);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -45,6 +45,7 @@ class Table extends Component {
|
|||
selectMode: PropTypes.number,
|
||||
selection: PropTypes.oneOfType([PropTypes.array, PropTypes.string, PropTypes.number]),
|
||||
selectionKeyIndex: PropTypes.number,
|
||||
selectionAsArray: PropTypes.bool,
|
||||
onSelectionChangedAsync: PropTypes.func,
|
||||
onSelectionDataAsync: PropTypes.func,
|
||||
actionLinks: PropTypes.array,
|
||||
|
@ -58,14 +59,14 @@ class Table extends Component {
|
|||
|
||||
getSelectionMap(props) {
|
||||
let selArray = [];
|
||||
if (props.selectMode === TableSelectMode.SINGLE) {
|
||||
if (props.selectMode === TableSelectMode.SINGLE && !this.props.selectionAsArray) {
|
||||
if (props.selection !== null && props.selection !== undefined) {
|
||||
selArray = [props.selection];
|
||||
} else {
|
||||
selArray = [];
|
||||
}
|
||||
} else if (props.selectMode === TableSelectMode.MULTI) {
|
||||
selArray = props.selection;
|
||||
} else if ((props.selectMode === TableSelectMode.SINGLE && this.props.selectionAsArray) || props.selectMode === TableSelectMode.MULTI) {
|
||||
selArray = props.selection || [];
|
||||
}
|
||||
|
||||
const selMap = new Map();
|
||||
|
@ -126,8 +127,6 @@ class Table extends Component {
|
|||
values: keysToFetch
|
||||
});
|
||||
|
||||
console.log(response.data);
|
||||
|
||||
for (const row of response.data) {
|
||||
const key = row[this.props.selectionKeyIndex];
|
||||
if (this.selectionMap.has(key)) {
|
||||
|
@ -270,7 +269,7 @@ class Table extends Component {
|
|||
let data = selPairs.map(entry => entry[1]);
|
||||
let sel = selPairs.map(entry => entry[0]);
|
||||
|
||||
if (this.props.selectMode === TableSelectMode.SINGLE) {
|
||||
if (this.props.selectMode === TableSelectMode.SINGLE && !this.props.selectionAsArray) {
|
||||
if (sel.length) {
|
||||
sel = sel[0];
|
||||
data = data[0];
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
import React, { Component } from 'react';
|
||||
import { translate, Trans } from 'react-i18next';
|
||||
import { withPageHelpers, Title } from '../lib/page'
|
||||
import { withForm, Form, FormSendMethod, InputField, TextArea, TableSelect, TableSelectMode, ButtonRow, Button } from '../lib/form';
|
||||
import {
|
||||
withForm, Form, FormSendMethod, InputField, TextArea, TableSelect, TableSelectMode, ButtonRow, Button,
|
||||
Fieldset
|
||||
} from '../lib/form';
|
||||
import axios from '../lib/axios';
|
||||
import { withErrorHandling, withAsyncErrorHandler } from '../lib/error-handling';
|
||||
import { ModalDialog } from '../lib/bootstrap-components';
|
||||
|
@ -23,16 +26,40 @@ export default class CUD extends Component {
|
|||
this.state.entityId = parseInt(props.match.params.id);
|
||||
}
|
||||
|
||||
this.initForm();
|
||||
this.initForm({
|
||||
onChange: {
|
||||
report_template: ::this.onReportTemplateChange
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isDelete() {
|
||||
return this.props.match.params.action === 'delete';
|
||||
}
|
||||
|
||||
@withAsyncErrorHandler
|
||||
async fetchUserFields(reportTemplateId) {
|
||||
const result = await axios.get(`/rest/report-template-user-fields/${reportTemplateId}`);
|
||||
this.updateFormValue('user_fields', result.data);
|
||||
}
|
||||
|
||||
onReportTemplateChange(state, key, oldVal, newVal) {
|
||||
if (oldVal !== newVal) {
|
||||
state.formState = state.formState.setIn(['data', 'user_fields', 'value'], '');
|
||||
|
||||
if (newVal) {
|
||||
this.fetchUserFields(newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@withAsyncErrorHandler
|
||||
async loadFormValues() {
|
||||
await this.getFormValuesFromURL(`/rest/reports/${this.state.entityId}`);
|
||||
await this.getFormValuesFromURL(`/rest/reports/${this.state.entityId}`, data => {
|
||||
for (const key in data.params) {
|
||||
data[`param_${key}`] = data.params[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -40,9 +67,10 @@ export default class CUD extends Component {
|
|||
this.loadFormValues();
|
||||
} else {
|
||||
this.populateFormValues({
|
||||
report_template: null,
|
||||
name: '',
|
||||
description: ''
|
||||
description: '',
|
||||
report_template: null,
|
||||
user_fields: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -62,12 +90,43 @@ export default class CUD extends Component {
|
|||
} else {
|
||||
state.setIn(['report_template', 'error'], null);
|
||||
}
|
||||
|
||||
for (const paramId of state.keys()) {
|
||||
if (paramId.startsWith('param_')) {
|
||||
state.deleteIn([paramId, 'error']);
|
||||
}
|
||||
}
|
||||
|
||||
const userFieldsSpec = state.getIn(['user_fields', 'value']);
|
||||
if (userFieldsSpec) {
|
||||
for (const spec of userFieldsSpec) {
|
||||
const fldId = `param_${spec.id}`;
|
||||
const selection = state.getIn([fldId, 'value']) || [];
|
||||
|
||||
if (spec.maxOccurences === 1) {
|
||||
if (spec.minOccurences === 1 && (selection === null || selection === undefined)) {
|
||||
state.setIn([fldId, 'error'], t('Exactly one item has to be selected'));
|
||||
}
|
||||
} else {
|
||||
if (selection.length < spec.minOccurences) {
|
||||
state.setIn([fldId, 'error'], t('At least {{ count }} item(s) have to be selected', { count: spec.minOccurences }));
|
||||
} else if (selection.length > spec.maxOccurences) {
|
||||
state.setIn([fldId, 'error'], t('At most {{ count }} item(s) can to be selected', { count: spec.maxOccurences }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async submitHandler() {
|
||||
const t = this.props.t;
|
||||
const edit = this.props.edit;
|
||||
|
||||
if (!this.getFormValue('user_fields')) {
|
||||
this.setFormStatusMessage('warning', t('Report parameters are not selected. Wait for them to get displayed and then fill them in.'));
|
||||
return;
|
||||
}
|
||||
|
||||
let sendMethod, url;
|
||||
if (edit) {
|
||||
sendMethod = FormSendMethod.PUT;
|
||||
|
@ -81,7 +140,16 @@ export default class CUD extends Component {
|
|||
this.setFormStatusMessage('info', t('Saving report template ...'));
|
||||
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
|
||||
delete data.password2;
|
||||
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;
|
||||
});
|
||||
|
||||
if (submitSuccessful) {
|
||||
|
@ -124,6 +192,49 @@ export default class CUD extends Component {
|
|||
{ data: 3, title: t('Created'), render: data => moment(data).fromNow() }
|
||||
];
|
||||
|
||||
const userFieldsSpec = this.getFormValue('user_fields');
|
||||
const userFields = [];
|
||||
|
||||
function addUserFieldTableSelect(spec, dataUrl, selIndex, columns) {
|
||||
let dropdown, selectMode;
|
||||
|
||||
if (spec.maxOccurences === 1) {
|
||||
dropdown = true;
|
||||
selectMode = TableSelectMode.SINGLE;
|
||||
} else {
|
||||
dropdown = true;
|
||||
selectMode = TableSelectMode.MULTI;
|
||||
}
|
||||
|
||||
const fld = <TableSelect key={spec.id} id={`param_${spec.id}`} label={spec.name} selectionAsArray withHeader dropdown={dropdown} selectMode={selectMode} dataUrl={dataUrl} columns={columns} selectionLabelIndex={selIndex}/>;
|
||||
|
||||
userFields.push(fld);
|
||||
}
|
||||
|
||||
if (userFieldsSpec) {
|
||||
for (const spec of userFieldsSpec) {
|
||||
if (spec.type === 'campaign') {
|
||||
addUserFieldTableSelect(spec, '/rest/campaigns-table', 1,[
|
||||
{data: 0, title: "#"},
|
||||
{data: 1, title: t('Name')},
|
||||
{data: 2, title: t('Description')},
|
||||
{data: 3, title: t('Status')},
|
||||
{data: 4, title: t('Created'), render: data => moment(data).fromNow()}
|
||||
]);
|
||||
} else if (spec.type === 'list') {
|
||||
addUserFieldTableSelect(spec, '/rest/lists-table', 1,[
|
||||
{data: 0, title: "#"},
|
||||
{data: 1, title: t('Name')},
|
||||
{data: 2, title: t('ID')},
|
||||
{data: 3, title: t('Subscribers')},
|
||||
{data: 4, title: t('Description')}
|
||||
]);
|
||||
} else {
|
||||
userFields.push(<div className="alert alert-danger" role="alert">{t('Unknown field type "{{type}}"', { type: spec.type })}</div>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{edit &&
|
||||
|
@ -141,7 +252,17 @@ export default class CUD extends Component {
|
|||
<InputField id="name" label={t('Name')}/>
|
||||
<TextArea id="description" label={t('Description')} help={t('HTML is allowed')}/>
|
||||
|
||||
<TableSelect id="report_template" label={t('Report Template')} withHeader dropdown dataUrl="/rest/report-templates-table" columns={columns} selectionLabelIndex={1} />
|
||||
<TableSelect id="report_template" label={t('Report Template')} withHeader dropdown dataUrl="/rest/report-templates-table" columns={columns} selectionLabelIndex={1}/>
|
||||
|
||||
{userFieldsSpec ?
|
||||
userFields.length > 0 &&
|
||||
<Fieldset label={t('Report parameters')}>
|
||||
{userFields}
|
||||
</Fieldset>
|
||||
:
|
||||
this.getFormValue('report_template') &&
|
||||
<div className="alert alert-info" role="alert">{t('Loading report template...')}</div>
|
||||
}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('Save')}/>
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class List extends Component {
|
|||
{ data: 1, title: t('Name') },
|
||||
{ data: 2, title: t('Template') },
|
||||
{ data: 3, title: t('Description') },
|
||||
{ data: 4, title: t('Created'), render: data => moment(data).fromNow() }
|
||||
{ data: 4, title: t('Last Run'), render: data => data ? moment(data).fromNow() : t('Not run yet') }
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
|
@ -269,9 +269,7 @@ export default class CUD extends Component {
|
|||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('Saving report template ...'));
|
||||
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
|
||||
delete data.password2;
|
||||
});
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url);
|
||||
|
||||
if (submitSuccessful) {
|
||||
if (stay) {
|
||||
|
|
|
@ -44,6 +44,8 @@ async function ajaxList(params, queryFun, columns) {
|
|||
query.orderBy(columns[params.columns[order.column].data], order.dir);
|
||||
}
|
||||
|
||||
query.options({rowsAsArray:true});
|
||||
|
||||
const rows = await query;
|
||||
const rowsOfArray = rows.map(row => Object.keys(row).map(field => row[field]));
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
const config = require('config');
|
||||
|
||||
const knex = require('knex')({
|
||||
client: 'mysql',
|
||||
client: 'mysql2',
|
||||
connection: config.mysql,
|
||||
migrations: {
|
||||
directory: __dirname + '/../setup/knex/migrations'
|
||||
|
|
13
models/campaigns.js
Normal file
13
models/campaigns.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
'use strict';
|
||||
|
||||
const knex = require('../lib/knex');
|
||||
const dtHelpers = require('../lib/dt-helpers');
|
||||
|
||||
async function listDTAjax(params) {
|
||||
return await dtHelpers.ajaxList(params, tx => tx('campaigns'), ['campaigns.id', 'campaigns.name', 'campaigns.description', 'campaigns.status', 'campaigns.created']);
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
listDTAjax
|
||||
};
|
13
models/lists.js
Normal file
13
models/lists.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
'use strict';
|
||||
|
||||
const knex = require('../lib/knex');
|
||||
const dtHelpers = require('../lib/dt-helpers');
|
||||
|
||||
async function listDTAjax(params) {
|
||||
return await dtHelpers.ajaxList(params, tx => tx('lists'), ['lists.id', 'lists.name', 'lists.cid', 'lists.subscribers', 'lists.description']);
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
listDTAjax
|
||||
};
|
|
@ -50,11 +50,21 @@ async function remove(id) {
|
|||
await knex('report_templates').where('id', id).del();
|
||||
}
|
||||
|
||||
async function getUserFieldsById(id) {
|
||||
const entity = await knex('report_templates').select(['user_fields']).where('id', id).first();
|
||||
if (!entity) {
|
||||
throw new interoperableErrors.NotFoundError();
|
||||
}
|
||||
|
||||
return JSON.parse(entity.user_fields);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hash,
|
||||
getById,
|
||||
listDTAjax,
|
||||
create,
|
||||
updateWithConsistencyCheck,
|
||||
remove
|
||||
remove,
|
||||
getUserFieldsById
|
||||
};
|
|
@ -21,12 +21,15 @@ function hash(entity) {
|
|||
return hasher.hash(filterObject(entity, allowedKeys));
|
||||
}
|
||||
|
||||
async function getById(id) {
|
||||
const entity = await knex('reports').where('id', id).first();
|
||||
async function getByIdWithUserFields(id) {
|
||||
const entity = await knex('reports').where('reports.id', id).innerJoin('report_templates', 'reports.report_template', 'report_templates.id').select(['reports.id', 'reports.name', 'reports.description', 'reports.report_template', 'reports.params', 'report_templates.user_fields']).first();
|
||||
if (!entity) {
|
||||
throw new interoperableErrors.NotFoundError();
|
||||
}
|
||||
|
||||
entity.user_fields = JSON.parse(entity.user_fields);
|
||||
entity.params = JSON.parse(entity.params);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
@ -36,12 +39,14 @@ async function listDTAjax(params) {
|
|||
|
||||
async function create(entity) {
|
||||
await knex.transaction(async tx => {
|
||||
const id = await tx('reports').insert(filterObject(entity, allowedKeys));
|
||||
|
||||
if (!await tx('report_templates').select(['id']).where('id', entity.report_template).first()) {
|
||||
throw new interoperableErrors.DependencyNotFoundError();
|
||||
}
|
||||
|
||||
entity.params = JSON.stringify(entity.params);
|
||||
|
||||
const id = await tx('reports').insert(filterObject(entity, allowedKeys));
|
||||
|
||||
return id;
|
||||
});
|
||||
}
|
||||
|
@ -53,6 +58,8 @@ async function updateWithConsistencyCheck(entity) {
|
|||
throw new interoperableErrors.NotFoundError();
|
||||
}
|
||||
|
||||
existing.params = JSON.parse(existing.params);
|
||||
|
||||
const existingHash = hash(existing);
|
||||
if (existingHash != entity.originalHash) {
|
||||
throw new interoperableErrors.ChangedError();
|
||||
|
@ -62,6 +69,8 @@ async function updateWithConsistencyCheck(entity) {
|
|||
throw new interoperableErrors.DependencyNotFoundError();
|
||||
}
|
||||
|
||||
entity.params = JSON.stringify(entity.params);
|
||||
|
||||
await tx('reports').where('id', entity.id).update(filterObject(entity, allowedKeys));
|
||||
});
|
||||
}
|
||||
|
@ -87,7 +96,7 @@ async function bulkChangeState(oldState, newState) {
|
|||
module.exports = {
|
||||
ReportState,
|
||||
hash,
|
||||
getById,
|
||||
getByIdWithUserFields,
|
||||
listDTAjax,
|
||||
create,
|
||||
updateWithConsistencyCheck,
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
"morgan": "^1.8.1",
|
||||
"multer": "^1.3.0",
|
||||
"multiparty": "^4.1.3",
|
||||
"mysql": "^2.13.0",
|
||||
"mysql2": "^1.3.5",
|
||||
"node-gettext": "^2.0.0-rc.1",
|
||||
"node-mocks-http": "^1.6.1",
|
||||
"node-object-hash": "^1.2.0",
|
||||
|
|
14
routes/rest/campaigns.js
Normal file
14
routes/rest/campaigns.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
const passport = require('../../lib/passport');
|
||||
const campaigns = require('../../models/campaigns');
|
||||
|
||||
const router = require('../../lib/router-async').create();
|
||||
|
||||
|
||||
router.postAsync('/campaigns-table', passport.loggedIn, async (req, res) => {
|
||||
return res.json(await campaigns.listDTAjax(req.body));
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
14
routes/rest/lists.js
Normal file
14
routes/rest/lists.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
const passport = require('../../lib/passport');
|
||||
const lists = require('../../models/lists');
|
||||
|
||||
const router = require('../../lib/router-async').create();
|
||||
|
||||
|
||||
router.postAsync('/lists-table', passport.loggedIn, async (req, res) => {
|
||||
return res.json(await lists.listDTAjax(req.body));
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
|
@ -35,5 +35,10 @@ router.postAsync('/report-templates-table', passport.loggedIn, async (req, res)
|
|||
return res.json(await reportTemplates.listDTAjax(req.body));
|
||||
});
|
||||
|
||||
router.getAsync('/report-template-user-fields/:reportTemplateId', passport.loggedIn, async (req, res) => {
|
||||
const userFields = await reportTemplates.getUserFieldsById(req.params.reportTemplateId);
|
||||
return res.json(userFields);
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
|
@ -9,7 +9,7 @@ const router = require('../../lib/router-async').create();
|
|||
|
||||
|
||||
router.getAsync('/reports/:reportId', passport.loggedIn, async (req, res) => {
|
||||
const report = await reports.getById(req.params.reportId);
|
||||
const report = await reports.getByIdWithUserFields(req.params.reportId);
|
||||
report.hash = reports.hash(report);
|
||||
return res.json(report);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue