ti2 1.0.28 → 1.0.31
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/api.yml +101 -0
- package/auth/authHandler.js +65 -25
- package/controllers/__tests__/allotments.js +106 -0
- package/controllers/allotment.js +40 -0
- package/index.js +15 -10
- package/package.json +1 -1
- package/test/plugin.js +20 -0
package/api.yml
CHANGED
|
@@ -1342,3 +1342,104 @@ paths:
|
|
|
1342
1342
|
application/json:
|
|
1343
1343
|
schema:
|
|
1344
1344
|
$ref: '#/components/schemas/AnyValue'
|
|
1345
|
+
/allotment/{appKey}/{userId}:
|
|
1346
|
+
get:
|
|
1347
|
+
security:
|
|
1348
|
+
- bearerAuth: ['admin', 'user']
|
|
1349
|
+
tags:
|
|
1350
|
+
- allotment
|
|
1351
|
+
summary: Query the allotment
|
|
1352
|
+
operationId: queryAllotment
|
|
1353
|
+
parameters:
|
|
1354
|
+
- name: appKey
|
|
1355
|
+
in: path
|
|
1356
|
+
description: app to create the booking for, defaults to first token
|
|
1357
|
+
required: true
|
|
1358
|
+
example: 'tourplan'
|
|
1359
|
+
schema:
|
|
1360
|
+
type: string
|
|
1361
|
+
- name: userId
|
|
1362
|
+
in: path
|
|
1363
|
+
description: the user/company that the appKey belongs to
|
|
1364
|
+
required: true
|
|
1365
|
+
schema:
|
|
1366
|
+
type: string
|
|
1367
|
+
- in: query
|
|
1368
|
+
name: startDate
|
|
1369
|
+
schema:
|
|
1370
|
+
type: string
|
|
1371
|
+
description: the start date of the requested allotment (dd/mm/yyyy)
|
|
1372
|
+
default: "01/04/2023"
|
|
1373
|
+
- in: query
|
|
1374
|
+
name: endDate
|
|
1375
|
+
schema:
|
|
1376
|
+
type: string
|
|
1377
|
+
description: the end date of the requested allotment (dd/mm/yyyy)
|
|
1378
|
+
default: "03/04/2023"
|
|
1379
|
+
- in: query
|
|
1380
|
+
name: keyPath
|
|
1381
|
+
schema:
|
|
1382
|
+
type: string
|
|
1383
|
+
description: a string with the product path separater by pipes ie. supplierId|locationId|productID
|
|
1384
|
+
default: "MAGLUX|7CQLDACMAGLUXDELSUI"
|
|
1385
|
+
responses:
|
|
1386
|
+
'200':
|
|
1387
|
+
description: Allotment Details
|
|
1388
|
+
content:
|
|
1389
|
+
application/json:
|
|
1390
|
+
schema:
|
|
1391
|
+
$ref: '#/components/schemas/AnyValue'
|
|
1392
|
+
/allotment/{appKey}/{hint}/{userId}:
|
|
1393
|
+
get:
|
|
1394
|
+
security:
|
|
1395
|
+
- bearerAuth: ['admin', 'user']
|
|
1396
|
+
tags:
|
|
1397
|
+
- allotment
|
|
1398
|
+
summary: Query the allotment with an specific hit
|
|
1399
|
+
operationId: queryAllotment
|
|
1400
|
+
parameters:
|
|
1401
|
+
- name: appKey
|
|
1402
|
+
in: path
|
|
1403
|
+
description: app to create the booking for, defaults to first token
|
|
1404
|
+
required: true
|
|
1405
|
+
example: 'tourplan'
|
|
1406
|
+
schema:
|
|
1407
|
+
type: string
|
|
1408
|
+
- name: hint
|
|
1409
|
+
in: path
|
|
1410
|
+
description: a specific token hint to be used
|
|
1411
|
+
required: true
|
|
1412
|
+
example: 'tourplan-australia'
|
|
1413
|
+
schema:
|
|
1414
|
+
type: string
|
|
1415
|
+
- name: userId
|
|
1416
|
+
in: path
|
|
1417
|
+
description: the user/company that the appKey belongs to
|
|
1418
|
+
required: true
|
|
1419
|
+
schema:
|
|
1420
|
+
type: string
|
|
1421
|
+
- in: query
|
|
1422
|
+
name: startDate
|
|
1423
|
+
schema:
|
|
1424
|
+
type: string
|
|
1425
|
+
description: the start date of the requested allotment (dd/mm/yyyy)
|
|
1426
|
+
default: "01/04/2023"
|
|
1427
|
+
- in: query
|
|
1428
|
+
name: endDate
|
|
1429
|
+
schema:
|
|
1430
|
+
type: string
|
|
1431
|
+
description: the end date of the requested allotment (dd/mm/yyyy)
|
|
1432
|
+
default: "03/04/2023"
|
|
1433
|
+
- in: query
|
|
1434
|
+
name: keyPath
|
|
1435
|
+
schema:
|
|
1436
|
+
type: string
|
|
1437
|
+
description: a string with the product path separater by pipes ie. supplierId|locationId|productID
|
|
1438
|
+
default: "MAGLUX|7CQLDACMAGLUXDELSUI"
|
|
1439
|
+
responses:
|
|
1440
|
+
'200':
|
|
1441
|
+
description: Allotment Details
|
|
1442
|
+
content:
|
|
1443
|
+
application/json:
|
|
1444
|
+
schema:
|
|
1445
|
+
$ref: '#/components/schemas/AnyValue'
|
package/auth/authHandler.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const jsonwebtoken = require('jsonwebtoken');
|
|
2
2
|
const Promise = require('bluebird');
|
|
3
|
-
const assert = require('assert');
|
|
4
3
|
|
|
5
4
|
const sqldb = require('../models');
|
|
6
5
|
|
|
@@ -12,7 +11,8 @@ const {
|
|
|
12
11
|
},
|
|
13
12
|
} = process;
|
|
14
13
|
|
|
15
|
-
const invalid =
|
|
14
|
+
const invalid = (res, msg) => res.status(401).json({ error: msg || 'Unauthorized' });
|
|
15
|
+
|
|
16
16
|
const getToken = ({ req }) => {
|
|
17
17
|
if (
|
|
18
18
|
!req.header('Authorization')
|
|
@@ -20,61 +20,101 @@ const getToken = ({ req }) => {
|
|
|
20
20
|
) return null;
|
|
21
21
|
return req.header('Authorization').split(' ')[1];
|
|
22
22
|
};
|
|
23
|
+
|
|
23
24
|
// the authentication middleware
|
|
24
|
-
const
|
|
25
|
-
if (!req.pathParams || !req.pathParams.app)
|
|
25
|
+
const appCheck = async req => {
|
|
26
|
+
if (!req.pathParams || !req.pathParams.app) {
|
|
27
|
+
return 'App parameters not found';
|
|
28
|
+
}
|
|
26
29
|
const token = getToken({ req });
|
|
27
|
-
if (!token) return
|
|
28
|
-
// try {
|
|
30
|
+
if (!token) return 'Api key not found';
|
|
29
31
|
const appRecord = await sqldb.Integration.findOne({
|
|
30
32
|
where: {
|
|
31
33
|
name: req.pathParams.app,
|
|
32
34
|
},
|
|
33
35
|
});
|
|
34
|
-
if (!appRecord) return
|
|
36
|
+
if (!appRecord) return 'App not found';
|
|
35
37
|
if (appRecord.apiKey !== token) {
|
|
36
|
-
return
|
|
38
|
+
return 'Invalid api key';
|
|
37
39
|
}
|
|
38
40
|
req.appRecord = appRecord.dataValues;
|
|
41
|
+
return undefined;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const app = async (req, res, next) => {
|
|
45
|
+
const error = await appCheck(req);
|
|
46
|
+
if (error) {
|
|
47
|
+
return invalid(res, error);
|
|
48
|
+
}
|
|
39
49
|
return next();
|
|
40
50
|
};
|
|
41
51
|
|
|
42
52
|
// The requester is an admin; createApps and other admin tasks
|
|
43
|
-
const
|
|
53
|
+
const adminCheck = async req => {
|
|
44
54
|
const token = getToken({ req });
|
|
45
|
-
if (token !== adminKey) return
|
|
55
|
+
if (token !== adminKey) return 'Invalid admin key';
|
|
56
|
+
return undefined;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const admin = async (req, res, next) => {
|
|
60
|
+
const error = await adminCheck(req);
|
|
61
|
+
if (error) {
|
|
62
|
+
return invalid(res, error);
|
|
63
|
+
}
|
|
46
64
|
return next();
|
|
47
65
|
};
|
|
48
66
|
|
|
49
67
|
// the request is from a user, checke the userId agains the url param
|
|
50
|
-
const
|
|
68
|
+
const userCheck = async req => {
|
|
51
69
|
const token = getToken({ req });
|
|
52
|
-
if (!token) return
|
|
70
|
+
if (!token) return 'Token not found';
|
|
71
|
+
let userId;
|
|
53
72
|
try {
|
|
54
|
-
|
|
55
|
-
assert(userId);
|
|
56
|
-
if (req.params.userId && userId !== req.params.userId) return invalid(next);
|
|
73
|
+
({ userId } = jsonwebtoken.verify(token, jwtSecret));
|
|
57
74
|
} catch (err) {
|
|
58
|
-
return
|
|
75
|
+
return 'Invalid token';
|
|
76
|
+
}
|
|
77
|
+
if (!userId) return 'UserId not found';
|
|
78
|
+
if (req.params.userId && userId !== req.params.userId) {
|
|
79
|
+
return 'Non matching user id';
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const user = async (req, res, next) => {
|
|
85
|
+
const error = await userCheck(req);
|
|
86
|
+
if (error) {
|
|
87
|
+
return invalid(res, error);
|
|
59
88
|
}
|
|
60
89
|
return next();
|
|
61
90
|
};
|
|
62
91
|
|
|
63
92
|
// The requester comes from frontend; frontend driven tasks
|
|
64
|
-
const
|
|
93
|
+
const frontendCheck = async req => {
|
|
65
94
|
const token = getToken({ req });
|
|
66
|
-
if (token !== frontendKey)
|
|
95
|
+
if (token !== frontendKey) {
|
|
96
|
+
return 'Invalid frontend token';
|
|
97
|
+
}
|
|
98
|
+
return undefined;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const frontend = async (req, res, next) => {
|
|
102
|
+
const error = await frontendCheck(req);
|
|
103
|
+
if (error) {
|
|
104
|
+
return invalid(res, error);
|
|
105
|
+
}
|
|
67
106
|
return next();
|
|
68
107
|
};
|
|
69
108
|
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
109
|
+
const multipleAuthEval = levels => async (req, res, next) => {
|
|
110
|
+
// res.send = true;
|
|
111
|
+
const results = await Promise.all(levels.map(
|
|
112
|
+
levelCheck => levelCheck(req),
|
|
73
113
|
));
|
|
74
|
-
if (
|
|
114
|
+
if (results.some(val => !val)) {
|
|
75
115
|
return next();
|
|
76
116
|
}
|
|
77
|
-
return
|
|
117
|
+
return invalid(res, results.join(' or '));
|
|
78
118
|
};
|
|
79
119
|
|
|
80
120
|
module.exports = {
|
|
@@ -82,6 +122,6 @@ module.exports = {
|
|
|
82
122
|
frontend,
|
|
83
123
|
admin,
|
|
84
124
|
user,
|
|
85
|
-
'admin,user':
|
|
86
|
-
'admin,app,user':
|
|
125
|
+
'admin,user': multipleAuthEval([adminCheck, userCheck]),
|
|
126
|
+
'admin,app,user': multipleAuthEval([adminCheck, appCheck, userCheck]),
|
|
87
127
|
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/* globals beforeAll describe it expect */
|
|
2
|
+
|
|
3
|
+
const chance = require('chance').Chance();
|
|
4
|
+
const testUtils = require('../../test/utils');
|
|
5
|
+
|
|
6
|
+
const { env: { adminKey } } = process;
|
|
7
|
+
|
|
8
|
+
describe('allotment', () => {
|
|
9
|
+
const newApp = {
|
|
10
|
+
name: 'tourplantest',
|
|
11
|
+
packageName: 'ti2-tourplanTest',
|
|
12
|
+
adminEmail: 'engineering+tourplantest@tourconnect.com',
|
|
13
|
+
};
|
|
14
|
+
const appKey = newApp.name;
|
|
15
|
+
const userId = '551394be5ac58e5c76000019';
|
|
16
|
+
const token = {
|
|
17
|
+
endpoint: 'https://someendpoint.com',
|
|
18
|
+
username: chance.guid(),
|
|
19
|
+
password: chance.string(),
|
|
20
|
+
};
|
|
21
|
+
const newIntegration = {
|
|
22
|
+
tokenHint: 'testingToken',
|
|
23
|
+
token,
|
|
24
|
+
};
|
|
25
|
+
let doApiDelete;
|
|
26
|
+
let doApiGet;
|
|
27
|
+
let doApiPost;
|
|
28
|
+
let plugins;
|
|
29
|
+
beforeAll(async () => {
|
|
30
|
+
({
|
|
31
|
+
doApiDelete,
|
|
32
|
+
doApiGet,
|
|
33
|
+
doApiPost,
|
|
34
|
+
plugins,
|
|
35
|
+
} = await testUtils({
|
|
36
|
+
plugins: [appKey],
|
|
37
|
+
}));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
let userToken;
|
|
41
|
+
it('drop any existing user integration', async () => {
|
|
42
|
+
try {
|
|
43
|
+
await doApiDelete({
|
|
44
|
+
url: `/${appKey}/${userId}`,
|
|
45
|
+
token: adminKey,
|
|
46
|
+
payload: { tokenHint: newIntegration.tokenHint },
|
|
47
|
+
});
|
|
48
|
+
} catch (err) {
|
|
49
|
+
// console.debug(err);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
it('create the user', async () => {
|
|
53
|
+
({ value: userToken } = await doApiPost({
|
|
54
|
+
url: '/user',
|
|
55
|
+
token: adminKey,
|
|
56
|
+
payload: { userId },
|
|
57
|
+
}));
|
|
58
|
+
expect(userToken).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
it('create the App+User setup', async () => {
|
|
61
|
+
const { userAppKeys } = await doApiGet({
|
|
62
|
+
url: `/user/${userId}/apps`,
|
|
63
|
+
token: userToken,
|
|
64
|
+
});
|
|
65
|
+
if (!userAppKeys.map(e => e.integrationId).includes(appKey)) {
|
|
66
|
+
// relation does not exits
|
|
67
|
+
const { value } = await doApiPost({
|
|
68
|
+
url: `/${appKey}/${userId}`,
|
|
69
|
+
token: userToken,
|
|
70
|
+
payload: newIntegration,
|
|
71
|
+
});
|
|
72
|
+
expect(value).toBeTruthy();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
const payload = {
|
|
76
|
+
dateFormat: 'DD-MM-YYYY',
|
|
77
|
+
startDate: '01-12-2022',
|
|
78
|
+
endDate: '15-12-2022',
|
|
79
|
+
keyPath: `${chance.guid()}|${chance.guid()}`,
|
|
80
|
+
};
|
|
81
|
+
const urlParams = new URLSearchParams(payload).toString();
|
|
82
|
+
it('should be able to get some allotments', async () => {
|
|
83
|
+
const { allotments } = await doApiGet({
|
|
84
|
+
url: `/allotment/${appKey}/${userId}?${urlParams}`,
|
|
85
|
+
token: userToken,
|
|
86
|
+
payload,
|
|
87
|
+
});
|
|
88
|
+
expect(plugins[0].queryAllotment).toHaveBeenCalled();
|
|
89
|
+
expect(Array.isArray(allotments)).toBeTruthy();
|
|
90
|
+
const call = plugins[0].queryAllotment.mock.calls[0][0];
|
|
91
|
+
expect(call.payload).toEqual(payload);
|
|
92
|
+
expect(call.token).toEqual(token);
|
|
93
|
+
});
|
|
94
|
+
it('should be able to get some allotments with a hint', async () => {
|
|
95
|
+
const { allotments } = await doApiGet({
|
|
96
|
+
url: `/allotment/${appKey}/${newIntegration.tokenHint}/${userId}?${urlParams}`,
|
|
97
|
+
token: userToken,
|
|
98
|
+
payload,
|
|
99
|
+
});
|
|
100
|
+
expect(plugins[0].queryAllotment).toHaveBeenCalled();
|
|
101
|
+
expect(Array.isArray(allotments)).toBeTruthy();
|
|
102
|
+
const call = plugins[0].queryAllotment.mock.calls[0][0];
|
|
103
|
+
expect(call.payload).toEqual(payload);
|
|
104
|
+
expect(call.token).toEqual(token);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
|
|
3
|
+
const { UserAppKey } = require('../models/index');
|
|
4
|
+
|
|
5
|
+
const queryAllotment = plugins => async (req, res, next) => {
|
|
6
|
+
const {
|
|
7
|
+
params: {
|
|
8
|
+
appKey,
|
|
9
|
+
hint,
|
|
10
|
+
userId,
|
|
11
|
+
},
|
|
12
|
+
query,
|
|
13
|
+
} = req;
|
|
14
|
+
try {
|
|
15
|
+
const app = plugins.find(({ name }) => name === appKey);
|
|
16
|
+
assert(app, `could not find the app ${appKey}`);
|
|
17
|
+
const userAppKeys = await UserAppKey.findOne({
|
|
18
|
+
where: {
|
|
19
|
+
userId,
|
|
20
|
+
integrationId: appKey,
|
|
21
|
+
...(hint ? { hint } : {}),
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
assert(userAppKeys, 'could not find the app key');
|
|
25
|
+
const token = userAppKeys.appKey;
|
|
26
|
+
assert(app.queryAllotment, 'could not find the allotment method');
|
|
27
|
+
const search = app.queryAllotment;
|
|
28
|
+
const results = await search({
|
|
29
|
+
token,
|
|
30
|
+
payload: query,
|
|
31
|
+
});
|
|
32
|
+
return res.json(results);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
return next(err);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
module.exports = plugins => ({
|
|
39
|
+
queryAllotment: queryAllotment(plugins),
|
|
40
|
+
});
|
package/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const adminController = require('./controllers/admin');
|
|
|
17
17
|
const appController = require('./controllers/app');
|
|
18
18
|
const userController = require('./controllers/user');
|
|
19
19
|
const bookingsController = require('./controllers/bookings');
|
|
20
|
+
const allotmentController = require('./controllers/allotment');
|
|
20
21
|
const { Integration } = require('./models');
|
|
21
22
|
const cache = require('./cache');
|
|
22
23
|
|
|
@@ -24,6 +25,8 @@ const cache = require('./cache');
|
|
|
24
25
|
const rebuild = fn => obj =>
|
|
25
26
|
Object.fromEntries(Object.entries(obj).flatMap(([k, v]) => fn(k, v)));
|
|
26
27
|
|
|
28
|
+
const isNumber = value => !Number.isNaN(Number(value));
|
|
29
|
+
|
|
27
30
|
module.exports = async ({
|
|
28
31
|
apiDocs = true,
|
|
29
32
|
elasticLogIndex = 'apilog_ti2',
|
|
@@ -64,7 +67,8 @@ module.exports = async ({
|
|
|
64
67
|
},
|
|
65
68
|
raw: true,
|
|
66
69
|
});
|
|
67
|
-
const
|
|
70
|
+
const matchedIntegrationsNames = matchedIntegrations.map(R.prop('name'));
|
|
71
|
+
const missingIntegrations = R.difference(pluginNames, matchedIntegrationsNames);
|
|
68
72
|
if (missingIntegrations.length > 0) {
|
|
69
73
|
// need to crete the missing integrations
|
|
70
74
|
await Integration.bulkCreate(missingIntegrations.map(name => ({
|
|
@@ -81,6 +85,7 @@ module.exports = async ({
|
|
|
81
85
|
...appController,
|
|
82
86
|
...userController(plugins),
|
|
83
87
|
...bookingsController(plugins),
|
|
88
|
+
...allotmentController(plugins),
|
|
84
89
|
cache: R.omit(['cache'], cache),
|
|
85
90
|
}; // mehthods that should map to the yaml api spec
|
|
86
91
|
app.plugins = plugins;
|
|
@@ -121,6 +126,8 @@ module.exports = async ({
|
|
|
121
126
|
);
|
|
122
127
|
const connect = connector(api, allSchema, {
|
|
123
128
|
security: auth,
|
|
129
|
+
notFound: (req, res) => res.sendStatus(404),
|
|
130
|
+
notImplemented: (req, res) => res.sendStatus(501),
|
|
124
131
|
});
|
|
125
132
|
if (elasticLogsClient) { // API request logs are saved on elastic
|
|
126
133
|
// setup the index
|
|
@@ -200,20 +207,18 @@ module.exports = async ({
|
|
|
200
207
|
});
|
|
201
208
|
}
|
|
202
209
|
connect(app);
|
|
203
|
-
|
|
204
|
-
app.use(middleware.mock());
|
|
205
|
-
}
|
|
206
|
-
app.use((req, res, next) => {
|
|
207
|
-
return res.sendStatus(404);
|
|
208
|
-
})
|
|
210
|
+
app.use(middleware.mock());
|
|
209
211
|
// global error Handling
|
|
210
|
-
app.use((err, req, res) => {
|
|
212
|
+
app.use((err, req, res, next) => {
|
|
213
|
+
if (res.headersSent) {
|
|
214
|
+
return next(err);
|
|
215
|
+
}
|
|
211
216
|
if (process.env.CONSOLE_ERRORS || process.env.JEST_WORKER_ID) {
|
|
212
217
|
console.error(err);
|
|
213
218
|
}
|
|
214
219
|
return res.status((() => {
|
|
215
|
-
if (
|
|
216
|
-
return
|
|
220
|
+
if (!isNumber(err.status)) return 500;
|
|
221
|
+
return Number(err.status);
|
|
217
222
|
})()).json({
|
|
218
223
|
message: err.message || 'Internal Error',
|
|
219
224
|
});
|
package/package.json
CHANGED
package/test/plugin.js
CHANGED
|
@@ -53,6 +53,7 @@ class Plugin {
|
|
|
53
53
|
});
|
|
54
54
|
this.searchQuote = jestPlugin.fn(() => ({ quote: [{ id: chance.guid() }] }));
|
|
55
55
|
this.createBooking = jestPlugin.fn(() => {});
|
|
56
|
+
this.queryAllotment = jestPlugin.fn(() => ({ allotments: [] }));
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* Background and schedule Jos
|
|
@@ -437,6 +438,25 @@ class Plugin {
|
|
|
437
438
|
* @returns {Booking} retVal.booking - A Booking object.
|
|
438
439
|
*/
|
|
439
440
|
createBooking() {}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Query Allotment
|
|
444
|
+
* @async
|
|
445
|
+
* @param {Object} args - Allotment query arguments.
|
|
446
|
+
* @param {Object} args.token - A token definition, it's content varies between integrations.
|
|
447
|
+
* @param {Object} args.payload - Search spect object.
|
|
448
|
+
* dateFormat = 'DD/MM/YYYY',
|
|
449
|
+
startDate,
|
|
450
|
+
endDate,
|
|
451
|
+
keyPath,
|
|
452
|
+
* @param {string} args.payload.dateFormat - Date format to use for params and return value (i.e. DD/MM/YYYY
|
|
453
|
+
* @param {string} args.payload.startDate - Start date for the query of allotment objects
|
|
454
|
+
* @param {string} args.payload.endDate - End date for the query of allotment objects
|
|
455
|
+
* @param {string} args.payload.keyPath - End date for the query of allotment objects
|
|
456
|
+
* @returns {object} retVal - the return object.
|
|
457
|
+
* @returns {Booking} retVal.booking - A Booking object.
|
|
458
|
+
*/
|
|
459
|
+
queryAllotment() {}
|
|
440
460
|
}
|
|
441
461
|
|
|
442
462
|
module.exports = Plugin;
|