jxp 2.16.0 → 4.0.0

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.
Files changed (218) hide show
  1. package/.env.sample +31 -6
  2. package/README.md +27 -13
  3. package/dist/bin/init_db.d.ts +3 -0
  4. package/dist/bin/init_db.d.ts.map +1 -0
  5. package/dist/bin/init_db.js +48 -0
  6. package/dist/bin/init_db.js.map +1 -0
  7. package/dist/bin/server.d.ts +4 -0
  8. package/dist/bin/server.d.ts.map +1 -0
  9. package/dist/bin/server.js +132 -0
  10. package/dist/bin/server.js.map +1 -0
  11. package/dist/bin/setup.d.ts +3 -0
  12. package/dist/bin/setup.d.ts.map +1 -0
  13. package/dist/bin/setup.js +185 -0
  14. package/dist/bin/setup.js.map +1 -0
  15. package/dist/globals.d.ts +14 -0
  16. package/dist/globals.d.ts.map +1 -0
  17. package/dist/globals.js +3 -0
  18. package/dist/globals.js.map +1 -0
  19. package/dist/libs/aggregate_guard.d.ts +5 -0
  20. package/dist/libs/aggregate_guard.d.ts.map +1 -0
  21. package/dist/libs/aggregate_guard.js +58 -0
  22. package/dist/libs/aggregate_guard.js.map +1 -0
  23. package/dist/libs/bulkwrite_guard.d.ts +5 -0
  24. package/dist/libs/bulkwrite_guard.d.ts.map +1 -0
  25. package/dist/libs/bulkwrite_guard.js +44 -0
  26. package/dist/libs/bulkwrite_guard.js.map +1 -0
  27. package/dist/libs/cache.d.ts +2 -0
  28. package/dist/libs/cache.d.ts.map +1 -0
  29. package/dist/libs/cache.js +94 -0
  30. package/dist/libs/cache.js.map +1 -0
  31. package/dist/libs/call_guard.d.ts +3 -0
  32. package/dist/libs/call_guard.d.ts.map +1 -0
  33. package/dist/libs/call_guard.js +17 -0
  34. package/dist/libs/call_guard.js.map +1 -0
  35. package/dist/libs/connection_string.d.ts +3 -0
  36. package/dist/libs/connection_string.d.ts.map +1 -0
  37. package/dist/libs/connection_string.js +4 -0
  38. package/dist/libs/connection_string.js.map +1 -0
  39. package/dist/libs/datamunging.d.ts +2 -0
  40. package/dist/libs/datamunging.d.ts.map +1 -0
  41. package/dist/libs/datamunging.js +320 -0
  42. package/dist/libs/datamunging.js.map +1 -0
  43. package/dist/libs/docs.d.ts +2 -0
  44. package/dist/libs/docs.d.ts.map +1 -0
  45. package/dist/libs/docs.js +307 -0
  46. package/dist/libs/docs.js.map +1 -0
  47. package/dist/libs/groups.d.ts +2 -0
  48. package/dist/libs/groups.d.ts.map +1 -0
  49. package/dist/libs/groups.js +136 -0
  50. package/dist/libs/groups.js.map +1 -0
  51. package/dist/libs/jxp.d.ts +4 -0
  52. package/dist/libs/jxp.d.ts.map +1 -0
  53. package/dist/libs/jxp.js +1157 -0
  54. package/dist/libs/jxp.js.map +1 -0
  55. package/dist/libs/link_index.d.ts +14 -0
  56. package/dist/libs/link_index.d.ts.map +1 -0
  57. package/dist/libs/link_index.js +37 -0
  58. package/dist/libs/link_index.js.map +1 -0
  59. package/dist/libs/load-config.d.ts +16 -0
  60. package/dist/libs/load-config.d.ts.map +1 -0
  61. package/dist/libs/load-config.js +155 -0
  62. package/dist/libs/load-config.js.map +1 -0
  63. package/dist/libs/login.d.ts +2 -0
  64. package/dist/libs/login.d.ts.map +1 -0
  65. package/dist/libs/login.js +244 -0
  66. package/dist/libs/login.js.map +1 -0
  67. package/dist/libs/modeldir.d.ts +5 -0
  68. package/dist/libs/modeldir.d.ts.map +1 -0
  69. package/dist/libs/modeldir.js +15 -0
  70. package/dist/libs/modeldir.js.map +1 -0
  71. package/dist/libs/query_limits.d.ts +2 -0
  72. package/dist/libs/query_limits.d.ts.map +1 -0
  73. package/dist/libs/query_limits.js +84 -0
  74. package/dist/libs/query_limits.js.map +1 -0
  75. package/dist/libs/query_manipulation.d.ts +3 -0
  76. package/dist/libs/query_manipulation.d.ts.map +1 -0
  77. package/{libs → dist/libs}/query_manipulation.js +22 -21
  78. package/dist/libs/query_manipulation.js.map +1 -0
  79. package/dist/libs/query_sanitize.d.ts +5 -0
  80. package/dist/libs/query_sanitize.d.ts.map +1 -0
  81. package/dist/libs/query_sanitize.js +109 -0
  82. package/dist/libs/query_sanitize.js.map +1 -0
  83. package/dist/libs/response_sanitize.d.ts +7 -0
  84. package/dist/libs/response_sanitize.d.ts.map +1 -0
  85. package/dist/libs/response_sanitize.js +57 -0
  86. package/dist/libs/response_sanitize.js.map +1 -0
  87. package/dist/libs/safe_error.d.ts +3 -0
  88. package/dist/libs/safe_error.d.ts.map +1 -0
  89. package/dist/libs/safe_error.js +14 -0
  90. package/dist/libs/safe_error.js.map +1 -0
  91. package/dist/libs/schema.d.ts +14 -0
  92. package/dist/libs/schema.d.ts.map +1 -0
  93. package/dist/libs/schema.js +98 -0
  94. package/dist/libs/schema.js.map +1 -0
  95. package/dist/libs/schema_description.d.ts +3 -0
  96. package/dist/libs/schema_description.d.ts.map +1 -0
  97. package/{libs → dist/libs}/schema_description.js +12 -21
  98. package/dist/libs/schema_description.js.map +1 -0
  99. package/dist/libs/security.d.ts +2 -0
  100. package/dist/libs/security.d.ts.map +1 -0
  101. package/dist/libs/security.js +428 -0
  102. package/dist/libs/security.js.map +1 -0
  103. package/dist/libs/setup.d.ts +2 -0
  104. package/dist/libs/setup.d.ts.map +1 -0
  105. package/dist/libs/setup.js +87 -0
  106. package/dist/libs/setup.js.map +1 -0
  107. package/dist/libs/startup-deprecations.d.ts +2 -0
  108. package/dist/libs/startup-deprecations.d.ts.map +1 -0
  109. package/dist/libs/startup-deprecations.js +21 -0
  110. package/dist/libs/startup-deprecations.js.map +1 -0
  111. package/dist/libs/startup.d.ts +16 -0
  112. package/dist/libs/startup.d.ts.map +1 -0
  113. package/dist/libs/startup.js +63 -0
  114. package/dist/libs/startup.js.map +1 -0
  115. package/dist/libs/ws.d.ts +2 -0
  116. package/dist/libs/ws.d.ts.map +1 -0
  117. package/{libs → dist/libs}/ws.js +114 -73
  118. package/dist/libs/ws.js.map +1 -0
  119. package/dist/models/apikey_model.d.ts +10 -0
  120. package/dist/models/apikey_model.d.ts.map +1 -0
  121. package/dist/models/apikey_model.js +14 -0
  122. package/dist/models/apikey_model.js.map +1 -0
  123. package/dist/models/link_model.d.ts +9 -0
  124. package/dist/models/link_model.d.ts.map +1 -0
  125. package/dist/models/link_model.js +20 -0
  126. package/dist/models/link_model.js.map +1 -0
  127. package/dist/models/refreshtoken_model.d.ts +11 -0
  128. package/dist/models/refreshtoken_model.d.ts.map +1 -0
  129. package/dist/models/refreshtoken_model.js +22 -0
  130. package/dist/models/refreshtoken_model.js.map +1 -0
  131. package/dist/models/test_model.d.ts +24 -0
  132. package/dist/models/test_model.d.ts.map +1 -0
  133. package/dist/models/test_model.js +44 -0
  134. package/dist/models/test_model.js.map +1 -0
  135. package/dist/models/token_model.d.ts +14 -0
  136. package/dist/models/token_model.d.ts.map +1 -0
  137. package/dist/models/token_model.js +25 -0
  138. package/dist/models/token_model.js.map +1 -0
  139. package/dist/models/user_model.d.ts +15 -0
  140. package/dist/models/user_model.d.ts.map +1 -0
  141. package/dist/models/user_model.js +38 -0
  142. package/dist/models/user_model.js.map +1 -0
  143. package/dist/models/usergroups_model.d.ts +9 -0
  144. package/dist/models/usergroups_model.d.ts.map +1 -0
  145. package/dist/models/usergroups_model.js +18 -0
  146. package/dist/models/usergroups_model.js.map +1 -0
  147. package/dist/types/jxp-config.d.ts +134 -0
  148. package/dist/types/jxp-config.d.ts.map +1 -0
  149. package/dist/types/jxp-config.js +3 -0
  150. package/dist/types/jxp-config.js.map +1 -0
  151. package/dist/types/schema-fields.d.ts +43 -0
  152. package/dist/types/schema-fields.d.ts.map +1 -0
  153. package/dist/types/schema-fields.js +3 -0
  154. package/dist/types/schema-fields.js.map +1 -0
  155. package/docs/aggregations.md +40 -21
  156. package/docs/api.md +55 -15
  157. package/docs/authentication.md +60 -37
  158. package/docs/bulk_writes.md +11 -8
  159. package/docs/caching.md +28 -11
  160. package/docs/changelog.md +237 -31
  161. package/docs/configuration.md +99 -118
  162. package/docs/hooks.md +12 -8
  163. package/docs/index.md +17 -17
  164. package/docs/installation.md +23 -18
  165. package/docs/permissions.md +33 -19
  166. package/docs/queries.md +9 -5
  167. package/docs/schemas.md +21 -10
  168. package/docs/special.md +4 -4
  169. package/docs/typescript.md +86 -0
  170. package/docs/websocket.md +99 -1
  171. package/mkdocs.yml +1 -0
  172. package/package.json +121 -69
  173. package/templates/api.pug +32 -0
  174. package/templates/app-server.js +43 -0
  175. package/templates/app.env.sample +8 -0
  176. package/templates/assets/api-console.js +133 -0
  177. package/templates/assets/docs.css +227 -0
  178. package/templates/index.pug +62 -2
  179. package/templates/layout.pug +17 -11
  180. package/templates/md.pug +1 -1
  181. package/templates/model.pug +117 -68
  182. package/templates/navbar.pug +14 -21
  183. package/templates/sidebar.pug +30 -0
  184. package/.env +0 -9
  185. package/.eslintrc.json +0 -20
  186. package/.jshintrc +0 -4
  187. package/.vscode/launch.json +0 -29
  188. package/.vscode/settings.json +0 -3
  189. package/Dockerfile +0 -7
  190. package/bin/init_db.js +0 -54
  191. package/bin/server.js +0 -84
  192. package/bin/setup.js +0 -190
  193. package/config_sample.json +0 -10
  194. package/docker-compose.yml +0 -32
  195. package/libs/cache.js +0 -92
  196. package/libs/connection_string.js +0 -24
  197. package/libs/datamunging.js +0 -335
  198. package/libs/docs.js +0 -162
  199. package/libs/groups.js +0 -133
  200. package/libs/jxp.js +0 -1208
  201. package/libs/login.js +0 -218
  202. package/libs/modeldir.js +0 -14
  203. package/libs/schema.js +0 -99
  204. package/libs/security.js +0 -410
  205. package/libs/setup.js +0 -90
  206. package/models/apikey_model.js +0 -10
  207. package/models/link_model.js +0 -17
  208. package/models/refreshtoken_model.js +0 -20
  209. package/models/test_model.js +0 -50
  210. package/models/token_model.js +0 -23
  211. package/models/user_model.js +0 -38
  212. package/models/usergroups_model.js +0 -15
  213. package/setup.sh +0 -3
  214. package/test/.eslintrc.json +0 -13
  215. package/test/init.js +0 -92
  216. package/test/setup.test.js +0 -62
  217. package/test/test.js +0 -1527
  218. package/test/wstest.js.old +0 -124
package/libs/jxp.js DELETED
@@ -1,1208 +0,0 @@
1
- const errors = require("restify-errors");
2
- const restify = require("restify");
3
- const path = require("path");
4
- const security = require("./security");
5
- const datamunging = require("./datamunging");
6
- const login = require("./login");
7
- const groups = require("./groups");
8
- const setup = require("./setup");
9
- const Docs = require("./docs");
10
- const querystring = require("querystring");
11
- const fs = require("fs");
12
- const morgan = require("morgan");
13
- const ws = require("./ws");
14
- const modeldir = require("./modeldir");
15
- const query_manipulation = require("./query_manipulation");
16
- const corsMiddleware = require('restify-cors-middleware2');
17
- const json2csv = require('json2csv').parse;
18
- const cache = require("./cache");
19
- global.JXPSchema = require("./schema");
20
-
21
- var models = {};
22
-
23
- var ops = 0;
24
-
25
- var debug = false;
26
-
27
- // Middleware
28
- const middlewareModel = (req, res, next) => {
29
- const modelname = req.params.modelname;
30
- req.modelname = modelname;
31
- // console.log("Model", modelname);
32
- try {
33
- req.Model = models[modelname];
34
- return next();
35
- } catch (err) {
36
- console.error(new Date, err);
37
- throw new errors.NotFoundError(`Model ${modelname} not found`);
38
- }
39
- };
40
-
41
- const middlewarePasswords = (req, res, next) => {
42
- if (req.body && req.body.password && !req.query.password_override) {
43
- req.body.password = security.encPassword(req.body.password);
44
- }
45
- next();
46
- };
47
-
48
- const middlewareCheckAdmin = (req, res, next) => {
49
- //We don't want users to pump up their own permissions
50
- if (req.modelname !== "user") return next();
51
- if (res.user.admin) return next();
52
- req.params.admin = false;
53
- next();
54
- };
55
-
56
- // Outputs whatever is in res.result as JSON
57
- const outputJSON = async (req, res) => {
58
- try {
59
- res.send(res.result);
60
- } catch (err) {
61
- console.error(new Date(), err);
62
- throw new errors.InternalServerError(err.toString());
63
- }
64
- }
65
-
66
- // Outputs whatever is in res.result as CSV
67
- const outputCSV = (req, res, next) => {
68
- const opts = { "flatten": true };
69
- if (!res.result.data) {
70
- throw new errors.InternalServerError("Error generating CSV");
71
- }
72
- try {
73
- const data = res.result.data.map(row => row._doc);
74
- if (!data.length) {
75
- throw ("")
76
- }
77
- res.writeHead(200, {
78
- 'Content-Type': 'text/csv',
79
- 'Content-Disposition': 'attachment; filename=export.csv'
80
- });
81
- const csv = json2csv(data, opts);
82
- res.end(csv);
83
- next();
84
- } catch (err) {
85
- console.error(err);
86
- throw new errors.InternalServerError(err.toString());
87
- }
88
- }
89
-
90
- // Actions (verbs)
91
- const actionGet = async (req, res) => {
92
- const opname = `get ${req.modelname} ${ops++}`;
93
- console.time(opname);
94
- const parseSearch = function (search) {
95
- let result = {};
96
- for (let i in search) {
97
- result[i] = new RegExp(search[i], "i");
98
- }
99
- return result;
100
- };
101
- let filters = {};
102
- try {
103
- filters = parseFilter(req.query.filter);
104
- } catch (err) {
105
- console.trace(new Date(), err);
106
- // Preserve BadRequestError, convert others to InternalServerError
107
- if (err instanceof errors.BadRequestError) {
108
- throw err;
109
- }
110
- throw new errors.InternalServerError(err.toString());
111
- }
112
- let search = parseSearch(req.query.search);
113
- for (let i in search) {
114
- filters[i] = search[i];
115
- }
116
- let countquery = filters;
117
- let qcount = req.Model.find(filters);
118
- let q = req.Model.find(filters);
119
- let checkDeleted = [{ _deleted: false }, { _deleted: null }];
120
- if (!req.query.showDeleted) {
121
- countquery = Object.assign({ $or: checkDeleted }, countquery);
122
- qcount.or(checkDeleted);
123
- q.or(checkDeleted);
124
- }
125
- if (req.query.search) {
126
- // console.log({ search: req.query.search });
127
- q = req.Model.find({ $text: { $search: req.query.search } }, { score: { $meta: "textScore" } }).sort({ score: { $meta: "textScore" } });
128
- countquery = Object.assign({ $text: { $search: req.query.search } }, countquery);
129
- qcount = req.Model.find({ $text: { $search: req.query.search } });
130
- }
131
- if (res.user) {
132
- q.options = ({ user: res.user });
133
- }
134
- try {
135
- let count = await req.Model.estimatedDocumentCount();
136
- if (count < 100000 && Object.keys(countquery).length !== 0) {
137
- count = await qcount.countDocuments();
138
- } else {
139
- count = -1;
140
- }
141
- const result = { count };
142
- const limit = parseInt(req.query.limit);
143
- if (limit) {
144
- q.limit(limit);
145
- result.limit = limit;
146
- let page_count = Math.ceil(count / limit);
147
- result.page_count = page_count;
148
- let page = parseInt(req.query.page);
149
- page = page ? page : 1;
150
- result.page = page;
151
- if (page < page_count) {
152
- result.next = changeUrlParams(req, "page", page + 1);
153
- }
154
- if (page > 1) {
155
- result.prev = changeUrlParams(req, "page", page - 1);
156
- q.skip(limit * (page - 1));
157
- }
158
- }
159
- if (req.query.sort) {
160
- q.sort(req.query.sort);
161
- result.sort = req.query.sort;
162
- }
163
- if (req.query.populate) {
164
- if ((typeof req.query.populate === "object") && !Array.isArray(req.query.populate)) {
165
- for (let i in req.query.populate) {
166
- q.populate(i, req.query.populate[i].replace(/,/g, " "));
167
- }
168
- } else {
169
- q.populate(req.query.populate);
170
- }
171
- result.populate = req.query.populate;
172
- }
173
- if (req.query.autopopulate) {
174
- for (let key in req.Model.schema.paths) {
175
- const dirpath = req.Model.schema.paths[key];
176
- if (dirpath.instance == "ObjectID" && dirpath.options.link) {
177
- q.populate(String(dirpath.options.map_to || dirpath.options.virtual || dirpath.options.link.toLowerCase()));
178
- }
179
- }
180
- result.autopopulate = true;
181
- }
182
- if (req.query.fields) {
183
- const fields = req.query.fields.split(",");
184
- const select = {};
185
- fields.forEach(field => {
186
- select[field] = 1;
187
- });
188
- q.select(select);
189
- }
190
- if (req.query.search) {
191
- result.search = req.query.search;
192
- }
193
- result.data = await q.exec();
194
- res.result = result;
195
- if (debug) console.timeEnd(opname);
196
- } catch (err) {
197
- console.error(new Date(), err);
198
- if (debug) console.timeEnd(opname);
199
- // Preserve BadRequestError, convert others to InternalServerError
200
- if (err instanceof errors.BadRequestError) {
201
- throw err;
202
- }
203
- if (err.code) throw err;
204
- throw new errors.InternalServerError(err.toString());
205
- }
206
- };
207
-
208
- const actionGetOne = async (req, res) => {
209
- const opname = `getOne ${req.modelname}/${req.params.item_id} ${ops++}`;
210
- console.time(opname);
211
- try {
212
- const data = await getOne(req.Model, req.params.item_id, req.query, { user: res.user });
213
- res.result = { data };
214
- if (debug) console.timeEnd(opname);
215
- } catch (err) {
216
- console.error(new Date(), err);
217
- if (debug) console.timeEnd(opname);
218
- if (err.code) throw err;
219
- throw new errors.InternalServerError(err.toString());
220
- }
221
- };
222
-
223
- const actionPost = async (req, res) => {
224
- const opname = `post ${req.modelname} ${ops++}`;
225
- console.time(opname);
226
- try {
227
- let item = new req.Model();
228
- _populateItem(item, datamunging.deserialize(req.body));
229
- if (res.user) {
230
- item._owner_id = res.user._id;
231
- item.__user = res.user;
232
- }
233
- const result = await item.save();
234
- let silence = req.params._silence;
235
- if (req.body && req.body._silence) silence = true;
236
- if (!silence) {
237
- req.config.callbacks.post.call(null, req.modelname, result, res.user);
238
- ws.postHook.call(null, req.modelname, result, res.user);
239
- }
240
- res.json({
241
- status: "ok",
242
- message: req.modelname + " created",
243
- data: item
244
- });
245
- if (debug) console.timeEnd(opname);
246
- } catch (err) {
247
- console.error(new Date(), err);
248
- if (debug) console.timeEnd(opname);
249
- if (err.code) throw err;
250
- throw new errors.InternalServerError(err.toString());
251
- }
252
- };
253
-
254
- const actionPut = async (req, res) => {
255
- const opname = `put ${req.modelname}/${req.params.item_id} ${ops++}`;
256
- console.time(opname);
257
- try {
258
- let item = await req.Model.findById(req.params.item_id);
259
- if (!item) {
260
- console.error(new Date(), "Document not found");
261
- throw new errors.NotFoundError(`Document ${req.params.item_id} not found on ${req.modelname}`);
262
- }
263
- _populateItem(item, datamunging.deserialize(req.body));
264
- _versionItem(item);
265
- if (res.user) {
266
- item.__user = res.user;
267
- item._updated_by_id = res.user._id;
268
- }
269
- const data = await item.save();
270
- let silence = req.params._silence;
271
- if (req.body && req.body._silence) silence = true;
272
- if (!silence) {
273
- req.config.callbacks.put.call(null, req.modelname, item, res.user);
274
- ws.putHook.call(null, req.modelname, item, res.user);
275
- }
276
- res.json({
277
- status: "ok",
278
- message: req.modelname + " updated",
279
- data: data
280
- });
281
- if (debug) console.timeEnd(opname);
282
- } catch (err) {
283
- console.error(new Date(), err);
284
- if (debug) console.timeEnd(opname);
285
- if (err.code) throw err;
286
- throw new errors.InternalServerError(err.toString());
287
- }
288
- };
289
-
290
- const actionUpdate = async (req, res) => {
291
- const opname = `update ${req.modelname}/${req.params.item_id} ${ops++}`;
292
- console.time(opname);
293
- try {
294
- let body_data = datamunging.deserialize(req.body);
295
- const data = await req.Model.update({ _id: req.params.item_id }, body_data);
296
- let silence = req.params._silence;
297
- if (req.body && req.body._silence) silence = true;
298
- if (!silence) {
299
- req.config.callbacks.put.call(null, req.modelname, data, res.user);
300
- ws.putHook.call(null, req.modelname, data, res.user);
301
- }
302
- res.json({
303
- status: "ok",
304
- message: req.modelname + " updated",
305
- data
306
- });
307
- if (debug) console.timeEnd(opname);
308
- } catch (err) {
309
- console.error(new Date(), err);
310
- if (debug) console.timeEnd(opname);
311
- if (err.code) throw err;
312
- throw new errors.InternalServerError(err.toString());
313
- }
314
- };
315
-
316
- const actionDelete = async (req, res) => {
317
- const permaDelete = req.query._permaDelete;
318
- const cascade = req.query._cascade;
319
- let silence = req.query._silence || (req.body && req.body._silence);
320
- const opname = `del ${req.modelname}/${req.params.item_id} ${ops++}`;
321
- console.time(opname);
322
- try {
323
- let item = await req.Model.findById(req.params.item_id);
324
- if (!item) {
325
- throw new errors.NotFoundError(`Couldn't find item ${req.params.item_id} for delete on ${req.modelname}`);
326
- }
327
- // Get linked models
328
- const linked_models = [];
329
- const link_modelnames = Object.getOwnPropertyNames(models);
330
- for (let link_modelname of link_modelnames) {
331
- const link_definitions = Object.getOwnPropertyNames(models[link_modelname].schema.definition);
332
- for (let link_definition of link_definitions) {
333
- if (req.Model.modelName === models[link_modelname].schema.definition[link_definition].link) {
334
- linked_models.push({
335
- modelname: link_modelname,
336
- field: link_definition
337
- });
338
- }
339
- }
340
- }
341
- // Test that none of our linked models have this ID we're trying to delete
342
- for (let linked_model of linked_models) {
343
- const q = {};
344
- q[linked_model.field] = item._id;
345
- const check = await models[linked_model.modelname].countDocuments(q);
346
- if (check) {
347
- if (cascade) {
348
- if (permaDelete) {
349
- await models[linked_model.modelname].deleteMany(q);
350
- } else {
351
- await models[linked_model.modelname].updateMany(q, { _deleted: true });
352
- }
353
- } else {
354
- throw new errors.ConflictError(`Parent link item exists in ${linked_model.modelname}/${linked_model.field}`);
355
- }
356
- }
357
- }
358
- if (res.user) {
359
- item.__user = res.user;
360
- }
361
- if (Object.prototype.hasOwnProperty.call(req.Model.schema.paths, "_deleted") && !(permaDelete)) {
362
- item._deleted = true;
363
- _versionItem(item);
364
- await item.save();
365
- } else {
366
- // console.log("Hard deleting");
367
- await req.Model.deleteOne({ _id: item._id });
368
- }
369
- if (!silence) {
370
- req.config.callbacks.delete.call(
371
- null,
372
- req.modelname,
373
- item,
374
- res.user,
375
- { soft: false }
376
- );
377
- ws.delHook.call(null, req.modelname, item, res.user);
378
- }
379
- res.json({
380
- status: "ok",
381
- message: `${req.modelname}/${req.params.item_id} deleted`
382
- });
383
- if (debug) console.timeEnd(opname);
384
- } catch (err) {
385
- console.error(new Date(), err);
386
- if (debug) console.timeEnd(opname);
387
- if (err.code) throw err;
388
- throw new errors.InternalServerError(err.toString());
389
- }
390
- };
391
-
392
- const actionCount = async (req, res) => {
393
- const opname = `count ${req.modelname} ${ops++}`;
394
- console.time(opname);
395
- const parseSearch = function (search) {
396
- let result = {};
397
- for (let i in search) {
398
- result[i] = new RegExp(search[i], "i");
399
- }
400
- return result;
401
- };
402
- let filters = {};
403
- try {
404
- filters = parseFilter(req.query.filter);
405
- } catch (err) {
406
- console.trace(new Date(), err);
407
- throw new errors.InternalServerError(err.toString());
408
- }
409
- let search = parseSearch(req.query.search);
410
- for (let i in search) {
411
- filters[i] = search[i];
412
- }
413
- if (!req.query.showDeleted) {
414
- filters = Object.assign({ $or: [{ _deleted: false }, { _deleted: null }] }, filters);
415
- }
416
- try {
417
- const count = await req.Model.countDocuments(filters).exec();
418
- res.result = { count };
419
- if (debug) console.timeEnd(opname);
420
- } catch (err) {
421
- console.error(new Date(), err);
422
- if (debug) console.timeEnd(opname);
423
- if (err.code) throw err;
424
- throw new errors.InternalServerError(err.toString());
425
- }
426
- };
427
-
428
- const actionCall = async (req, res) => {
429
- // console.log({ action_id: 7, action: "Method called", type: req.modelname, method: req.params.method_name, user: filterLogUser(res.user) });
430
- req.body = req.body || {};
431
- req.body.__user = res.user || null;
432
- try {
433
- const result = await req.Model[req.params.method_name](req.body);
434
- res.json(result);
435
- } catch (err) {
436
- console.error(new Date(), err);
437
- if (err.code) throw err;
438
- throw new errors.InternalServerError(err.toString());
439
- }
440
- };
441
-
442
- const actionCallItem = async (req, res) => {
443
- try {
444
- const item = req.Model.findById(req.params.item_id);
445
- if (!item) {
446
- throw new errors.NotFoundError(`Couldn't find item ${req.params.item_id} on ${req.modelname} for call`);
447
- }
448
- req.params.__user = res.user || null;
449
- const result = await req.Model[req.params.method_name](item);
450
- res.json(result);
451
- } catch (err) {
452
- console.trace(err);
453
- if (err.code) throw err;
454
- throw new errors.InternalServerError(err.toString());
455
- }
456
- };
457
-
458
- // Actions (verbs)
459
- const actionQuery = async (req, res) => {
460
- if (!req.body || !req.body.query || typeof req.body.query !== "object") {
461
- throw new errors.BadRequestError("Query missing or not of type object");
462
- }
463
- const opname = `query ${req.modelname} ${ops++}`;
464
- console.time(opname);
465
- let query = [req.body.query];
466
- let checkDeleted = { "$or": [{ _deleted: false }, { _deleted: null }] };
467
- if (!req.query.showDeleted) {
468
- query.push(checkDeleted);
469
- }
470
- let qcount = req.Model.find({ "$and": query });
471
- let q = req.Model.find({ "$and": query });
472
- try {
473
- const count = await qcount.countDocuments();
474
- const result = { count };
475
- const limit = parseInt(req.query.limit);
476
- if (limit) {
477
- q.limit(limit);
478
- result.limit = limit;
479
- let page_count = Math.ceil(count / limit);
480
- result.page_count = page_count;
481
- let page = parseInt(req.query.page);
482
- page = page ? page : 1;
483
- result.page = page;
484
- if (page < page_count) {
485
- result.next = changeUrlParams(req, "page", page + 1);
486
- }
487
- if (page > 1) {
488
- result.prev = changeUrlParams(req, "page", page - 1);
489
- q.skip(limit * (page - 1));
490
- }
491
- }
492
- if (req.query.sort) {
493
- q.sort(req.query.sort);
494
- result.sort = req.query.sort;
495
- }
496
- if (req.query.populate) {
497
- if ((typeof req.query.populate === "object") && !Array.isArray(req.query.populate)) {
498
- for (let i in req.query.populate) {
499
- q.populate(i, req.query.populate[i].replace(/,/g, " "));
500
- }
501
- } else {
502
- q.populate(req.query.populate);
503
- }
504
- result.populate = req.query.populate;
505
- }
506
- if (req.query.autopopulate) {
507
- for (let key in req.Model.schema.paths) {
508
- const dirpath = req.Model.schema.paths[key];
509
- if (dirpath.instance == "ObjectID" && dirpath.options.link) {
510
- q.populate(String(dirpath.options.map_to || dirpath.options.virtual || dirpath.options.link));
511
- }
512
- }
513
- result.autopopulate = true;
514
- }
515
- if (req.query.fields) {
516
- const fields = req.query.fields.split(",");
517
- const select = {};
518
- fields.forEach(field => {
519
- select[field] = 1;
520
- });
521
- q.select(select);
522
- }
523
- result.data = await q.exec();
524
- res.result = result;
525
- if (debug) console.timeEnd(opname);
526
- res.json(result);
527
- } catch (err) {
528
- console.error(new Date(), err);
529
- if (debug) console.timeEnd(opname);
530
- if (err.code) throw err;
531
- throw new errors.InternalServerError(err.toString());
532
- }
533
- };
534
-
535
- // Actions (verbs)
536
- const actionAggregate = async (req, res) => {
537
- let query = (req.body.query) ? req.body.query : req.body; // Don't require to embed in query anymore
538
- if (!query || !Array.isArray(query)) {
539
- console.error("query missing or not of type array")
540
- throw new errors.BadRequestError("Query missing or not of type array");
541
- }
542
- query = query_manipulation.fix_query(query);
543
- const opname = `aggregate ${req.modelname} ${ops++}`;
544
- console.time(opname);
545
- try {
546
- let result = {};
547
- if (req.query.allowDiskUse) {
548
- result.data = await req.Model.aggregate(query).allowDiskUse(true).exec();
549
- } else {
550
- result.data = await req.Model.aggregate(query);
551
- }
552
- res.result = result;
553
- if (debug) console.timeEnd(opname);
554
- res.json(result);
555
- } catch (err) {
556
- console.error(new Date(), err);
557
- if (debug) console.timeEnd(opname);
558
- throw new errors.InternalServerError(err.toString());
559
- }
560
- };
561
-
562
- // Actions (verbs)
563
- const actionBulkWrite = async (req, res) => {
564
- if (!req.body || !Array.isArray(req.body)) {
565
- console.error("query missing or not of type array")
566
- throw new errors.BadRequestError("Query missing or not of type array");
567
- }
568
- const opname = `bulkwrite ${req.modelname} ${ops++}`;
569
- console.time(opname);
570
- let query = req.body;
571
- // console.log(query);
572
- try {
573
- let result = {};
574
- result.data = await req.Model.bulkWrite(query);
575
- res.result = result;
576
- if (debug) console.timeEnd(opname);
577
- res.json(result);
578
- } catch (err) {
579
- console.error(new Date(), err);
580
- if (debug) console.timeEnd(opname);
581
- throw new errors.InternalServerError(err.toString());
582
- }
583
- };
584
-
585
- // var actionBatch = (req, res, next) => {
586
- // console.time("BATCH " + req.modelname);
587
- // var items = [];
588
- // data = JSON.parse(req.params.json);
589
- // data.forEach(function(data) {
590
- // var item = new req.Model();
591
- // if (res.user) {
592
- // item.__user = res.user;
593
- // }
594
- // _populateItem(item, data);
595
- // _versionItem(item);
596
- // if (res.user) {
597
- // item._owner_id = res.user._id;
598
- // }
599
- // items.push(item);
600
- // });
601
- // req.Model.create(items, function(err, docs) {
602
- // if (err) {
603
- // console.error(err);
604
- // res.status(500).send(err.toString());
605
- // } else {
606
- // // websocket.emit(modelname, { method: "post", _id: result._id });
607
- // console.log({ action_id: 8, action: "Batch insert", type: req.modelname, count: items.length, user: filterLogUser(res.user) });
608
- // res.send({ message: req.modelname + " created ", data: items.length });
609
- // if (debug) console.timeEnd("BATCH " + req.modelname);
610
- // return;
611
- // }
612
- // });
613
- // };
614
-
615
-
616
-
617
- // Utitlities
618
-
619
- const getOne = async (Model, item_id, params, options) => {
620
- const query = Model.findById(item_id, {}, options);
621
- if (params.populate) {
622
- if ((typeof params.populate === "object") && !Array.isArray(params.populate)) {
623
- for (let i in params.populate) {
624
- query.populate(i, params.populate[i].replace(/,/g, " "));
625
- }
626
- } else {
627
- query.populate(params.populate);
628
- }
629
- }
630
- if (params.autopopulate) {
631
- for (let key in Model.schema.paths) {
632
- var dirpath = Model.schema.paths[key];
633
- if (dirpath.instance == "ObjectID" && dirpath.options.link) {
634
- query.populate(String(dirpath.options.map_to || dirpath.options.virtual || dirpath.options.link.toLowerCase()));
635
- }
636
- }
637
- }
638
- try {
639
- var item = await query.exec();
640
- if (!item) {
641
- // console.error("Could not find document");
642
- throw new errors.NotFoundError(`Could not find document ${item_id} on ${Model.modelName}`);
643
- }
644
- if (item._deleted && !params.showDeleted) {
645
- // console.error("Document is deleted");
646
- throw new errors.NotFoundError(`Document ${item_id} is deleted on ${Model.modelName}`);
647
- }
648
- item = item.toObject();
649
- //Don't ever return passwords
650
- delete item.password;
651
- return item;
652
- } catch (err) {
653
- console.error(err);
654
- if (err.code) throw err;
655
- throw new errors.InternalServerError(err.toString());
656
- }
657
- };
658
-
659
- // Helper function to check if a string is an ISO date string
660
- function isISODateString(str) {
661
- if (typeof str !== 'string') return false;
662
- const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/;
663
- if (!isoDateRegex.test(str)) return false;
664
- const date = new Date(str);
665
- if (isNaN(date.getTime())) {
666
- throw new errors.BadRequestError("Invalid date format");
667
- }
668
- return true;
669
- }
670
-
671
- const parseFilter = (filter, depth = 0) => {
672
- const MAX_DEPTH = 10;
673
-
674
- if (!filter) return {};
675
- if (depth > MAX_DEPTH) {
676
- console.warn('Maximum filter depth exceeded');
677
- return filter;
678
- }
679
-
680
- if (typeof filter !== "object" || filter === null) return filter;
681
-
682
- // Handle arrays by merging their operators
683
- if (Array.isArray(filter)) {
684
- const result = {};
685
- filter.forEach(item => {
686
- if (typeof item === "string" && item.includes(":")) {
687
- const parts = item.split(":");
688
- const key = parts[0];
689
- const value = parts.slice(1).join(":");
690
- if (key.startsWith("$")) {
691
- try {
692
- if (isISODateString(value)) {
693
- result[key] = new Date(value);
694
- } else {
695
- result[key] = value;
696
- }
697
- } catch (err) {
698
- if (err instanceof errors.BadRequestError) {
699
- throw err;
700
- }
701
- throw new errors.BadRequestError("Invalid date format");
702
- }
703
- }
704
- }
705
- });
706
- return result;
707
- }
708
-
709
- // Create a new object to avoid modifying the input
710
- const parsedFilter = {};
711
-
712
- for (let i in filter) {
713
- if (filter[i] === "false") {
714
- parsedFilter[i] = false;
715
- continue;
716
- }
717
- if (filter[i] === "true") {
718
- parsedFilter[i] = true;
719
- continue;
720
- }
721
- if (typeof filter[i] === "string") {
722
- try {
723
- if (isISODateString(filter[i])) {
724
- parsedFilter[i] = new Date(filter[i]);
725
- continue;
726
- }
727
- } catch (err) {
728
- if (err instanceof errors.BadRequestError) {
729
- throw err;
730
- }
731
- throw new errors.BadRequestError("Invalid date format");
732
- }
733
- if (filter[i].includes(":")) {
734
- const parts = filter[i].split(":");
735
- const key = parts[0];
736
- const value = parts.slice(1).join(":");
737
- if (key.startsWith("$")) {
738
- try {
739
- if (isISODateString(value)) {
740
- if (!parsedFilter[i]) parsedFilter[i] = {};
741
- parsedFilter[i][key] = new Date(value);
742
- } else if (value.startsWith("[") && value.endsWith("]")) {
743
- if (!parsedFilter[i]) parsedFilter[i] = {};
744
- parsedFilter[i][key] = value.slice(1, -1).split(",");
745
- } else if (key === "$regex" && value.startsWith("/")) {
746
- if (!parsedFilter[i]) parsedFilter[i] = {};
747
- const match = value.match(/^\/(.+?)\/([gimy]*)$/);
748
- if (match) {
749
- parsedFilter[i][key] = new RegExp(match[1], match[2]);
750
- }
751
- } else {
752
- if (!parsedFilter[i]) parsedFilter[i] = {};
753
- parsedFilter[i][key] = value;
754
- }
755
- } catch (err) {
756
- if (err instanceof errors.BadRequestError) {
757
- throw err;
758
- }
759
- throw new errors.BadRequestError("Invalid date format");
760
- }
761
- } else {
762
- parsedFilter[i] = filter[i];
763
- }
764
- } else {
765
- parsedFilter[i] = filter[i];
766
- }
767
- } else if (Array.isArray(filter[i])) {
768
- parsedFilter[i] = parseFilter(filter[i], depth + 1);
769
- } else if (typeof filter[i] === "object") {
770
- parsedFilter[i] = parseFilter(filter[i], depth + 1);
771
- } else {
772
- parsedFilter[i] = filter[i];
773
- }
774
- }
775
-
776
- return parsedFilter;
777
- };
778
-
779
- const _deSerialize = (data) => {
780
- function assign(obj, keyPath, value) {
781
- const MAX_DEPTH = 20; // Prevent excessive nesting
782
- const lastKeyIndex = keyPath.length - 1;
783
-
784
- if (lastKeyIndex >= MAX_DEPTH) {
785
- console.warn('Maximum nesting depth exceeded in _deSerialize');
786
- return;
787
- }
788
-
789
- for (let i = 0; i < lastKeyIndex; ++i) {
790
- let key = keyPath[i];
791
- if (!(key in obj)) obj[key] = {};
792
- obj = obj[key];
793
- }
794
- obj[keyPath[lastKeyIndex]] = value;
795
- }
796
-
797
- if (!data || typeof data !== 'object') return;
798
-
799
- for (let datum in data) {
800
- const matches = datum.match(/\[(.+?)\]/g);
801
- if (matches) {
802
- const params = matches.map(function (match) {
803
- return match.replace(/[[\]]/g, "");
804
- });
805
- if (isNaN(params[0])) {
806
- params.unshift(datum.match(/(.+?)\[/)[1]);
807
- assign(data, params, data[datum]);
808
- }
809
- }
810
- }
811
- };
812
-
813
- const _populateItem = (item, data) => {
814
- _deSerialize(data);
815
- for (let prop in item) {
816
- if (typeof data[prop] != "undefined") {
817
- item[prop] = data[prop];
818
- // Unset any blank values - essentially 'deleting' values on editing
819
- if (data[prop] === "") {
820
- item[prop] = null;
821
- }
822
- }
823
- //Check for arrays that come in like param[1]=blah, param[2]=yack
824
- if (data[prop + "[0]"]) {
825
- var x = 0;
826
- var tmp = [];
827
- while (data[prop + "[" + x + "]"]) {
828
- tmp.push(data[prop + "[" + x + "]"]);
829
- x++;
830
- }
831
- item[prop] = tmp;
832
- }
833
- }
834
- };
835
-
836
- const _versionItem = (item) => {
837
- if (item._version || item._version === 0) {
838
- item._version++;
839
- } else {
840
- item._version = 0;
841
- }
842
- };
843
-
844
- const _fixArrays = (req, res, next) => {
845
- if (req.body) {
846
- for (var i in req.body) {
847
- if (i.search(/\[\d+\]/) > -1) {
848
- var parts = i.match(/(^[A-Za-z]+)(\[)/);
849
- var el = parts[1];
850
- if (!req.body[el]) {
851
- req.body[el] = [];
852
- }
853
- req.body[el].push(req.body[i]);
854
- }
855
- }
856
- }
857
- next();
858
- };
859
-
860
- const changeUrlParams = (req, key, val) => {
861
- var q = req.query;
862
- q[key] = val;
863
- return req.config.url + req.path() + "?" + querystring.stringify(q);
864
- };
865
-
866
- const JXP = function (options) {
867
- const server = restify.createServer();
868
- const model_dir = options.model_dir || modeldir.findModelDir(path.dirname(process.argv[1]));
869
- //Set up config with default
870
- var config = {
871
- model_dir: path.join(model_dir),
872
- mongo: options.mongo,
873
- callbacks: {
874
- put: function () { },
875
- post: function () { },
876
- delete: function () { },
877
- get: function () { },
878
- getOne: function () { },
879
- update: function () { },
880
- },
881
- log: "access.log",
882
- pre_hooks: {
883
- login: (req, res, next) => {
884
- next();
885
- },
886
- get: (req, res, next) => {
887
- next();
888
- },
889
- getOne: (req, res, next) => {
890
- next();
891
- },
892
- post: (req, res, next) => {
893
- next();
894
- },
895
- put: (req, res, next) => {
896
- next();
897
- },
898
- update: (req, res, next) => {
899
- next();
900
- },
901
- delete: (req, res, next) => {
902
- next();
903
- }
904
- },
905
- post_hooks: {
906
- login: async () => {
907
- },
908
- },
909
- cache_timeout: "5 minutes",
910
- };
911
- //Override config with passed in options
912
-
913
- for (let i in options) {
914
- if (typeof config[i] === "object" && !Array.isArray(config[i])) {
915
- if (typeof options[i] === "object" && !Array.isArray(options[i])) {
916
- for (let j in options[i]) {
917
- config[i][j] = options[i][j]; // Second level object copy
918
- }
919
- }
920
- } else {
921
- config[i] = options[i];
922
- }
923
- if (i === "model_dir" || i === "log") {
924
- // Decide whether it's absolute or relative
925
- if (config.model_dir.charAt(0) === "/") {
926
- config[i] = options[i];
927
- } else {
928
- config[i] = path.join(
929
- path.dirname(process.argv[1]),
930
- options[i]
931
- );
932
- }
933
- }
934
- }
935
-
936
- if (config.debug) debug = true;
937
-
938
- // Set apikey and server globally to inject into schemas
939
- global.apikey = config.apikey;
940
- global.server = config.server;
941
- global.model_dir = model_dir;
942
-
943
- // Pre-load models
944
- var files = fs.readdirSync(config.model_dir);
945
- let modelnames = files.filter(function (fname) {
946
- return fname.indexOf("_model.js") !== -1;
947
- });
948
- modelnames.forEach(function (fname) {
949
- var modelname = fname.replace("_model.js", "");
950
- models[modelname] = require(path.join(config.model_dir, fname));
951
- });
952
-
953
- setup.init(config);
954
- security.init(config);
955
- login.init(config);
956
- groups.init(config);
957
- ws.init({ models });
958
- cache.init(config);
959
- const docs = new Docs({ config, models });
960
-
961
- // Set up our API server
962
-
963
- // Rate limitting
964
- if (config.throttle) {
965
- server.use(restify.plugins.throttle(config.throttle));
966
- }
967
-
968
- // Logging
969
- console.log("Logging to", config.log);
970
-
971
- var accessLogStream = fs.createWriteStream(config.log, { flags: "a" });
972
- server.use(morgan("combined", { stream: accessLogStream }));
973
-
974
- // CORS
975
- const cors = corsMiddleware({
976
- preflightMaxAge: 5, //Optional
977
- origins: ['*'],
978
- allowHeaders: ['X-Requested-With', 'Authorization'],
979
- exposeHeaders: ['Authorization']
980
- });
981
-
982
- server.pre(cors.preflight);
983
- server.use(cors.actual);
984
-
985
- // Parse data
986
- server.use(restify.plugins.queryParser());
987
- server.use(restify.plugins.bodyParser());
988
-
989
- // Bind our config to req.config
990
- server.use((req, res, next) => {
991
- req.config = config;
992
- next();
993
- });
994
-
995
- // Set req.username = "anonymous" if not logged in
996
- server.use((req, res, next) => {
997
- if (!req.username) req.username = "anonymous";
998
- next();
999
- });
1000
-
1001
- // Define our endpoints
1002
-
1003
- /* Our API endpoints */
1004
- server.get(
1005
- "/api/:modelname",
1006
- middlewareModel,
1007
- security.login,
1008
- security.auth,
1009
- config.pre_hooks.get,
1010
- cache.get,
1011
- actionGet,
1012
- cache.set,
1013
- outputJSON
1014
- );
1015
- server.get(
1016
- "/api/:modelname/:item_id",
1017
- middlewareModel,
1018
- security.login,
1019
- security.auth,
1020
- config.pre_hooks.getOne,
1021
- cache.get,
1022
- actionGetOne,
1023
- cache.set,
1024
- outputJSON
1025
- );
1026
- server.post(
1027
- "/api/:modelname",
1028
- middlewareModel,
1029
- security.login,
1030
- security.auth,
1031
- middlewarePasswords,
1032
- config.pre_hooks.post,
1033
- actionPost,
1034
- cache.clearAll,
1035
- (req, res, next) => {
1036
- next();
1037
- },
1038
- );
1039
- server.put(
1040
- "/api/:modelname/:item_id",
1041
- middlewareModel,
1042
- security.login,
1043
- security.auth,
1044
- middlewarePasswords,
1045
- middlewareCheckAdmin,
1046
- config.pre_hooks.put,
1047
- actionPut,
1048
- cache.clearAll,
1049
- (req, res, next) => {
1050
- next();
1051
- },
1052
- );
1053
- server.del(
1054
- "/api/:modelname/:item_id",
1055
- middlewareModel,
1056
- security.login,
1057
- security.auth,
1058
- config.pre_hooks.delete,
1059
- actionDelete,
1060
- cache.clearAll,
1061
- );
1062
-
1063
- // Count
1064
- server.get(
1065
- "/count/:modelname",
1066
- middlewareModel,
1067
- security.login,
1068
- security.auth,
1069
- config.pre_hooks.get,
1070
- // cache.get,
1071
- actionCount,
1072
- // cache.set,
1073
- outputJSON
1074
- );
1075
-
1076
- // CSV endpoints
1077
- server.get(
1078
- "/csv/:modelname",
1079
- middlewareModel,
1080
- security.login,
1081
- security.auth,
1082
- config.pre_hooks.get,
1083
- actionGet,
1084
- outputCSV
1085
- );
1086
-
1087
- // Query endpoints
1088
- server.post(
1089
- "/query/:modelname",
1090
- middlewareModel,
1091
- security.login,
1092
- security.auth,
1093
- config.pre_hooks.get,
1094
- actionQuery,
1095
- );
1096
-
1097
- server.post(
1098
- "/aggregate/:modelname",
1099
- middlewareModel,
1100
- security.login,
1101
- security.auth,
1102
- config.pre_hooks.get,
1103
- actionAggregate
1104
- );
1105
-
1106
- server.post(
1107
- "/bulkwrite/:modelname",
1108
- middlewareModel,
1109
- security.login,
1110
- security.bulkAuth,
1111
- config.pre_hooks.get,
1112
- actionBulkWrite,
1113
- );
1114
-
1115
- server.post(
1116
- "/update/:modelname/:item_id",
1117
- middlewareModel,
1118
- security.login,
1119
- security.auth,
1120
- middlewarePasswords,
1121
- middlewareCheckAdmin,
1122
- config.pre_hooks.update,
1123
- actionUpdate,
1124
- cache.clearAll,
1125
- );
1126
-
1127
- /* Batch routes - ROLLED BACK FOR NOW */
1128
- // server.post('/batch/create/:modelname', middlewareModel, security.login, security.auth, actionBatch);
1129
-
1130
- /* Call Methods in our models */
1131
- server.get(
1132
- "/call/:modelname/:method_name",
1133
- middlewareModel,
1134
- security.login,
1135
- security.auth,
1136
- actionCall,
1137
- cache.clearAll,
1138
- );
1139
- server.post(
1140
- "/call/:modelname/:method_name",
1141
- middlewareModel,
1142
- security.login,
1143
- security.auth,
1144
- actionCall,
1145
- cache.clearAll,
1146
- );
1147
- server.get(
1148
- "/call/:modelname/:item_id/:method_name",
1149
- middlewareModel,
1150
- security.login,
1151
- security.auth,
1152
- actionCallItem,
1153
- cache.clearAll,
1154
- );
1155
-
1156
- /* Login and authentication */
1157
- server.post("/login/recover", login.recover);
1158
- server.post("/login/getjwt", security.login, login.getJWT);
1159
- server.get("/login/logout", security.login, login.logout);
1160
- server.get("/logout", security.login, login.logout);
1161
- server.get("/login/oauth/:provider", login.oauth);
1162
- server.get("/login/oauth/callback/:provider", login.oauth_callback);
1163
- server.post("/login", config.pre_hooks.login, login.login, config.post_hooks.login, outputJSON);
1164
- server.post("/refresh", security.refresh);
1165
- server.post("/login/refresh", security.refresh);
1166
-
1167
- /* Groups */
1168
- server.put(
1169
- "/groups/:user_id",
1170
- security.login,
1171
- security.admin_only,
1172
- _fixArrays,
1173
- groups.actionPut,
1174
- );
1175
- server.post(
1176
- "/groups/:user_id",
1177
- security.login,
1178
- security.admin_only,
1179
- _fixArrays,
1180
- groups.actionPost,
1181
- );
1182
- server.get("/groups/:user_id", security.login, groups.actionGet);
1183
- server.del("/groups/:user_id", security.login, security.admin_only, groups.actionDelete);
1184
-
1185
- /* Meta */
1186
- server.get("/model/:modelname", middlewareModel, docs.metaModel.bind(docs));
1187
- server.get("/model", docs.metaModels.bind(docs));
1188
- // server.get("/docs/_design", docs.dbDiagram.bind(docs));
1189
- server.get("/docs/md/:md_doc", docs.md.bind(docs));
1190
- server.get("/docs/model/:modelname", docs.model.bind(docs));
1191
- server.get("/", docs.frontPage.bind(docs));
1192
-
1193
- /* Setup */
1194
- server.get("/setup", setup.checkUserDoesNotExist, setup.setup);
1195
- server.post("/setup", setup.checkUserDoesNotExist, setup.setup);
1196
- server.post("/setup/data", setup.checkUserDoesNotExist, setup.data_setup);
1197
-
1198
- /* Websocket */
1199
- server.on("upgrade", ws.upgrade)
1200
-
1201
- /* Cache */
1202
- server.get("/cache/stats", cache.stats, outputJSON);
1203
- server.get("/cache/clear", cache.clearAll, outputJSON);
1204
-
1205
- return server;
1206
- };
1207
-
1208
- module.exports = JXP;