@tiledesk/tiledesk-server 2.19.11 → 2.19.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/app.js +3 -0
- package/models/dataTable.js +64 -0
- package/package.json +3 -3
- package/routes/dataTable.js +280 -0
- package/services/dataTableService.js +545 -0
- package/services/requestService.js +21 -16
- package/test/dataTablesRoute.test.js +844 -0
- package/utils/dataTableBsonUtils.js +12 -0
- package/utils/dataTableUtils.js +353 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
|
7
7
|
|
|
8
|
+
# 2.19.13
|
|
9
|
+
- Added new routes and services for Data Tables management
|
|
10
|
+
- Updated tybot-connector to 2.1.5
|
|
11
|
+
|
|
12
|
+
# 2.19.12
|
|
13
|
+
- Updated messenger-connector to 0.1.30
|
|
14
|
+
|
|
8
15
|
# 2.19.11
|
|
9
16
|
- Updated payments module
|
|
10
17
|
|
package/app.js
CHANGED
|
@@ -149,6 +149,7 @@ var urls = require('./routes/urls');
|
|
|
149
149
|
var email = require('./routes/email');
|
|
150
150
|
var property = require('./routes/property');
|
|
151
151
|
var segment = require('./routes/segment');
|
|
152
|
+
var dataTable = require('./routes/dataTable');
|
|
152
153
|
var webhook = require('./routes/webhook');
|
|
153
154
|
var webhooks = require('./routes/webhooks');
|
|
154
155
|
var roles = require('./routes/roles');
|
|
@@ -635,6 +636,8 @@ app.use('/:projectid/emails',[passport.authenticate(['basic', 'jwt'], { session:
|
|
|
635
636
|
app.use('/:projectid/properties',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], property);
|
|
636
637
|
app.use('/:projectid/segments',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], segment);
|
|
637
638
|
|
|
639
|
+
app.use('/:projectid/tables', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], dataTable);
|
|
640
|
+
|
|
638
641
|
app.use('/:projectid/llm', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], llm);
|
|
639
642
|
app.use('/:projectid/openai', openai);
|
|
640
643
|
app.use('/:projectid/url-preview', urlPreview);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
const Schema = mongoose.Schema;
|
|
3
|
+
const winston = require('../config/winston');
|
|
4
|
+
|
|
5
|
+
const TableSchema = new Schema({
|
|
6
|
+
id_project: {
|
|
7
|
+
type: String,
|
|
8
|
+
required: true,
|
|
9
|
+
index: true
|
|
10
|
+
},
|
|
11
|
+
name: {
|
|
12
|
+
type: String,
|
|
13
|
+
required: true
|
|
14
|
+
},
|
|
15
|
+
schema: {
|
|
16
|
+
type: Schema.Types.Mixed,
|
|
17
|
+
default: []
|
|
18
|
+
},
|
|
19
|
+
createdBy: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: true
|
|
22
|
+
},
|
|
23
|
+
stats: {
|
|
24
|
+
rows: {
|
|
25
|
+
type: Number,
|
|
26
|
+
default: 0
|
|
27
|
+
},
|
|
28
|
+
sizeBytes: {
|
|
29
|
+
type: Number,
|
|
30
|
+
default: 0
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, {
|
|
34
|
+
timestamps: true
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const TableRowSchema = new Schema({
|
|
38
|
+
id_project: {
|
|
39
|
+
type: String,
|
|
40
|
+
required: true
|
|
41
|
+
},
|
|
42
|
+
id_table: {
|
|
43
|
+
type: String,
|
|
44
|
+
required: true
|
|
45
|
+
},
|
|
46
|
+
data: {
|
|
47
|
+
type: Schema.Types.Mixed,
|
|
48
|
+
default: {}
|
|
49
|
+
},
|
|
50
|
+
}, {
|
|
51
|
+
timestamps: true
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
TableRowSchema.index({ id_project: 1, id_table: 1 });
|
|
55
|
+
|
|
56
|
+
const Table = mongoose.model('Table', TableSchema);
|
|
57
|
+
const TableRow = mongoose.model('TableRow', TableRowSchema);
|
|
58
|
+
|
|
59
|
+
if (process.env.MONGOOSE_SYNCINDEX) {
|
|
60
|
+
TableRow.syncIndexes();
|
|
61
|
+
winston.verbose('TableRow syncIndexes');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { Table, TableRow };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiledesk/tiledesk-server",
|
|
3
3
|
"description": "The Tiledesk server module",
|
|
4
|
-
"version": "2.19.
|
|
4
|
+
"version": "2.19.13",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"start": "node ./bin/www",
|
|
7
7
|
"pretest": "mongodb-runner start",
|
|
@@ -44,12 +44,12 @@
|
|
|
44
44
|
"@tiledesk/tiledesk-dialogflow-connector": "^1.8.4",
|
|
45
45
|
"@tiledesk/tiledesk-json-rules-engine": "^4.0.3",
|
|
46
46
|
"@tiledesk/tiledesk-kaleyra-proxy": "^0.1.7",
|
|
47
|
-
"@tiledesk/tiledesk-messenger-connector": "^0.1.
|
|
47
|
+
"@tiledesk/tiledesk-messenger-connector": "^0.1.30",
|
|
48
48
|
"@tiledesk/tiledesk-multi-worker": "^0.3.3",
|
|
49
49
|
"@tiledesk/tiledesk-rasa-connector": "^1.0.10",
|
|
50
50
|
"@tiledesk/tiledesk-sms-connector": "^0.1.13",
|
|
51
51
|
"@tiledesk/tiledesk-telegram-connector": "^0.1.14",
|
|
52
|
-
"@tiledesk/tiledesk-tybot-connector": "^2.1.
|
|
52
|
+
"@tiledesk/tiledesk-tybot-connector": "^2.1.5",
|
|
53
53
|
"@tiledesk/tiledesk-voice-twilio-connector": "^0.3.2",
|
|
54
54
|
"@tiledesk/tiledesk-vxml-connector": "^0.1.91",
|
|
55
55
|
"@tiledesk/tiledesk-whatsapp-connector": "1.0.26",
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const winston = require('../config/winston');
|
|
4
|
+
const dataTableService = require('../services/dataTableService');
|
|
5
|
+
|
|
6
|
+
function getRowPayload(body) {
|
|
7
|
+
if (body && body.data && typeof body.data === 'object' && !Array.isArray(body.data)) {
|
|
8
|
+
return body.data;
|
|
9
|
+
}
|
|
10
|
+
return body;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isValidationError(err) {
|
|
14
|
+
if (!err || !err.message) return false;
|
|
15
|
+
const msg = err.message;
|
|
16
|
+
return msg.indexOf('does not exist') !== -1 ||
|
|
17
|
+
msg.indexOf('required') !== -1 ||
|
|
18
|
+
msg.indexOf('Invalid') !== -1 ||
|
|
19
|
+
msg.indexOf('must be') !== -1 ||
|
|
20
|
+
msg.indexOf('already exists') !== -1 ||
|
|
21
|
+
msg.indexOf('Column id') !== -1 ||
|
|
22
|
+
msg.indexOf('not provided') !== -1 ||
|
|
23
|
+
msg.indexOf('Operator') !== -1 ||
|
|
24
|
+
msg.indexOf('id_row or conditions') !== -1 ||
|
|
25
|
+
msg.indexOf('data is required') !== -1 ||
|
|
26
|
+
msg.indexOf('valid JSON') !== -1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function handleError(res, err, action) {
|
|
30
|
+
if (err && err.message === 'TABLE_SIZE_LIMIT_EXCEEDED') {
|
|
31
|
+
return res.status(413).send({ success: false, message: 'TABLE_SIZE_LIMIT_EXCEEDED' });
|
|
32
|
+
}
|
|
33
|
+
if (isValidationError(err)) {
|
|
34
|
+
const status = err.message.indexOf('already exists') !== -1 ? 409 : 400;
|
|
35
|
+
return res.status(status).send({ success: false, message: err.message });
|
|
36
|
+
}
|
|
37
|
+
if (err.message === 'Column not found' || err.message.indexOf('Column not found:') === 0) {
|
|
38
|
+
return res.status(404).send({ success: false, message: err.message });
|
|
39
|
+
}
|
|
40
|
+
winston.error('DataTable ' + action + ': ', err);
|
|
41
|
+
return res.status(500).send({ success: false, error: 'Error ' + action });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// --- Tables ---
|
|
45
|
+
|
|
46
|
+
router.get('/', async function (req, res) {
|
|
47
|
+
try {
|
|
48
|
+
res.status(200).send(await dataTableService.listTables(req.projectid));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
handleError(res, err, 'finding tables');
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
router.get('/:id', async function (req, res) {
|
|
55
|
+
try {
|
|
56
|
+
const table = await dataTableService.getTable(req.projectid, req.params.id);
|
|
57
|
+
if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
58
|
+
res.status(200).send(table);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
handleError(res, err, 'finding table');
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
router.post('/', async function (req, res) {
|
|
65
|
+
try {
|
|
66
|
+
const table = await dataTableService.createTable(
|
|
67
|
+
req.projectid,
|
|
68
|
+
req.body,
|
|
69
|
+
req.user.id || req.user._id
|
|
70
|
+
);
|
|
71
|
+
res.status(200).send(table);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
handleError(res, err, 'creating table');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
router.put('/:id', async function (req, res) {
|
|
78
|
+
try {
|
|
79
|
+
const table = await dataTableService.updateTable(req.projectid, req.params.id, req.body);
|
|
80
|
+
if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
81
|
+
res.status(200).send(table);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
handleError(res, err, 'updating table');
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
router.delete('/:id', async function (req, res) {
|
|
88
|
+
try {
|
|
89
|
+
const deleted = await dataTableService.deleteTable(req.projectid, req.params.id);
|
|
90
|
+
if (!deleted) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
91
|
+
res.status(200).send({ success: true, message: 'Table deleted successfully' });
|
|
92
|
+
} catch (err) {
|
|
93
|
+
handleError(res, err, 'deleting table');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// --- Columns ---
|
|
98
|
+
|
|
99
|
+
router.post('/:id/columns', async function (req, res) {
|
|
100
|
+
try {
|
|
101
|
+
const table = await dataTableService.addColumn(req.projectid, req.params.id, req.body);
|
|
102
|
+
if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
103
|
+
res.status(200).send(table);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
handleError(res, err, 'adding column');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
router.patch('/:id/columns/:columnId', async function (req, res) {
|
|
110
|
+
try {
|
|
111
|
+
const table = await dataTableService.renameColumn(
|
|
112
|
+
req.projectid,
|
|
113
|
+
req.params.id,
|
|
114
|
+
req.params.columnId,
|
|
115
|
+
req.body.name
|
|
116
|
+
);
|
|
117
|
+
if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
118
|
+
res.status(200).send(table);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
handleError(res, err, 'renaming column');
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
router.delete('/:id/columns/:columnId', async function (req, res) {
|
|
125
|
+
try {
|
|
126
|
+
const table = await dataTableService.deleteColumn(
|
|
127
|
+
req.projectid,
|
|
128
|
+
req.params.id,
|
|
129
|
+
req.params.columnId
|
|
130
|
+
);
|
|
131
|
+
if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
132
|
+
res.status(200).send(table);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
handleError(res, err, 'deleting column');
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// --- Rows (insert / update / upsert / delete by id_row or conditions) ---
|
|
139
|
+
|
|
140
|
+
function getRowsListParams(req) {
|
|
141
|
+
var params = Object.assign({}, req.query);
|
|
142
|
+
if (req.body && typeof req.body === 'object' && !Array.isArray(req.body)) {
|
|
143
|
+
if (req.body.must_match !== undefined) params.must_match = req.body.must_match;
|
|
144
|
+
if (req.body.match !== undefined) params.match = req.body.match;
|
|
145
|
+
if (req.body.conditions !== undefined) params.conditions = req.body.conditions;
|
|
146
|
+
}
|
|
147
|
+
return params;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
router.get('/:id/rows/list', async function (req, res) {
|
|
151
|
+
|
|
152
|
+
console.log("List rows")
|
|
153
|
+
try {
|
|
154
|
+
const rows = await dataTableService.listRowsWithFilter(
|
|
155
|
+
req.projectid,
|
|
156
|
+
req.params.id,
|
|
157
|
+
Object.assign({}, getRowsListParams(req), { sort: -1, limit: 200 })
|
|
158
|
+
);
|
|
159
|
+
if (rows === null) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
160
|
+
res.status(200).send(rows);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
handleError(res, err, 'listing rows');
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
router.post('/:id/row/insert', async function (req, res) {
|
|
167
|
+
console.log("Insert row")
|
|
168
|
+
try {
|
|
169
|
+
const row = await dataTableService.insertRowByBody(req.projectid, req.params.id, req.body);
|
|
170
|
+
if (!row) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
171
|
+
res.status(200).send(row);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
handleError(res, err, 'inserting row');
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
router.put('/:id/row/update', async function (req, res) {
|
|
178
|
+
try {
|
|
179
|
+
const row = await dataTableService.updateRowByBody(req.projectid, req.params.id, req.body);
|
|
180
|
+
if (row === null) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
181
|
+
if (row === undefined) return res.status(404).send({ success: false, error: 'Row not found' });
|
|
182
|
+
res.status(200).send(row);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
handleError(res, err, 'updating row');
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
router.put('/:id/row/upsert', async function (req, res) {
|
|
189
|
+
try {
|
|
190
|
+
const result = await dataTableService.upsertRowByBody(req.projectid, req.params.id, req.body);
|
|
191
|
+
if (result === null) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
192
|
+
res.status(200).send(result);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
if (err.message === 'Multiple rows match the conditions') {
|
|
195
|
+
return res.status(409).send({ success: false, message: err.message });
|
|
196
|
+
}
|
|
197
|
+
handleError(res, err, 'upserting row');
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
router.put('/:id/row/delete', async function (req, res) {
|
|
202
|
+
try {
|
|
203
|
+
const row = await dataTableService.deleteRowByBody(req.projectid, req.params.id, req.body);
|
|
204
|
+
if (row === null) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
205
|
+
if (row === undefined) return res.status(404).send({ success: false, error: 'Row not found' });
|
|
206
|
+
res.status(200).send(row);
|
|
207
|
+
} catch (err) {
|
|
208
|
+
handleError(res, err, 'deleting row');
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// --- Rows (REST) ---
|
|
213
|
+
|
|
214
|
+
// router.get('/:id/rows', async function (req, res) {
|
|
215
|
+
// try {
|
|
216
|
+
// const rows = await dataTableService.listRows(req.projectid, req.params.id);
|
|
217
|
+
// if (rows === null) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
218
|
+
// res.status(200).send(rows);
|
|
219
|
+
// } catch (err) {
|
|
220
|
+
// handleError(res, err, 'finding rows');
|
|
221
|
+
// }
|
|
222
|
+
// });
|
|
223
|
+
|
|
224
|
+
// router.get('/:id/rows/:rowId', async function (req, res) {
|
|
225
|
+
// try {
|
|
226
|
+
// const row = await dataTableService.getRow(req.projectid, req.params.id, req.params.rowId);
|
|
227
|
+
// if (!row) return res.status(404).send({ success: false, error: 'Row not found' });
|
|
228
|
+
// res.status(200).send(row);
|
|
229
|
+
// } catch (err) {
|
|
230
|
+
// handleError(res, err, 'finding row');
|
|
231
|
+
// }
|
|
232
|
+
// });
|
|
233
|
+
|
|
234
|
+
// router.post('/:id/rows', async function (req, res) {
|
|
235
|
+
// try {
|
|
236
|
+
// const row = await dataTableService.insertRow(req.projectid, req.params.id, getRowPayload(req.body));
|
|
237
|
+
// if (!row) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
238
|
+
// res.status(200).send(row);
|
|
239
|
+
// } catch (err) {
|
|
240
|
+
// handleError(res, err, 'inserting row');
|
|
241
|
+
// }
|
|
242
|
+
// });
|
|
243
|
+
|
|
244
|
+
// router.put('/:id/rows/:rowId', async function (req, res) {
|
|
245
|
+
// try {
|
|
246
|
+
// const row = await dataTableService.updateRow(
|
|
247
|
+
// req.projectid,
|
|
248
|
+
// req.params.id,
|
|
249
|
+
// req.params.rowId,
|
|
250
|
+
// getRowPayload(req.body)
|
|
251
|
+
// );
|
|
252
|
+
// if (row === null) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
253
|
+
// if (row === undefined) return res.status(404).send({ success: false, error: 'Row not found' });
|
|
254
|
+
// res.status(200).send(row);
|
|
255
|
+
// } catch (err) {
|
|
256
|
+
// handleError(res, err, 'updating row');
|
|
257
|
+
// }
|
|
258
|
+
// });
|
|
259
|
+
|
|
260
|
+
// router.delete('/:id/rows/:rowId', async function (req, res) {
|
|
261
|
+
// try {
|
|
262
|
+
// const row = await dataTableService.deleteRow(req.projectid, req.params.id, req.params.rowId);
|
|
263
|
+
// if (!row) return res.status(404).send({ success: false, error: 'Row not found' });
|
|
264
|
+
// res.status(200).send(row);
|
|
265
|
+
// } catch (err) {
|
|
266
|
+
// handleError(res, err, 'deleting row');
|
|
267
|
+
// }
|
|
268
|
+
// });
|
|
269
|
+
|
|
270
|
+
// router.post('/:id/rows/search', async function (req, res) {
|
|
271
|
+
// try {
|
|
272
|
+
// const rows = await dataTableService.searchRows(req.projectid, req.params.id, req.body);
|
|
273
|
+
// if (rows === null) return res.status(404).send({ success: false, error: 'Table not found' });
|
|
274
|
+
// res.status(200).send(rows);
|
|
275
|
+
// } catch (err) {
|
|
276
|
+
// handleError(res, err, 'searching rows');
|
|
277
|
+
// }
|
|
278
|
+
// });
|
|
279
|
+
|
|
280
|
+
module.exports = router;
|