@galadrim/galadmin 0.2.12 → 0.3.0-alpha.2.1

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 (225) hide show
  1. package/.agents/report/blockers.json +1 -0
  2. package/.agents/report/failures/2026-09-23-api-user-filter-contract.md +31 -0
  3. package/.agents/report/failures/2026-09-23-api-values-contract.md +25 -0
  4. package/.agents/report/failures/2026-10-01-cycle-02-create-callback-contract.md +17 -0
  5. package/.agents/report/failures/2026-10-01-cycle-06-delete-callback-id-contract.md +17 -0
  6. package/.agents/report/failures/2026-10-01-cycle-07-panel-delete-callback-id-contract.md +24 -0
  7. package/.agents/report/failures/2026-10-01-cycle-13-update-callback-id-contract.md +17 -0
  8. package/.agents/report/failures/2026-10-01-cycle-15-rich-text-upload-boundary-contract.md +24 -0
  9. package/.agents/report/failures/2026-10-03-cycle-06-record-import-parser-contract.md +11 -0
  10. package/.agents/report/failures/2026-10-03-cycle-07-panel-import-parser-contract.md +24 -0
  11. package/.agents/report/failures/2026-10-07-resume-cycle-02-api-assembly-contract.md +46 -0
  12. package/.agents/report/port/2026-09-23-api-config-enrichment.md +13 -0
  13. package/.agents/report/port/2026-09-23-api-file-upload.md +11 -0
  14. package/.agents/report/port/2026-09-23-api-query-authorization.md +14 -0
  15. package/.agents/report/port/2026-09-23-api-request-configuration.md +11 -0
  16. package/.agents/report/port/2026-09-23-database-manager.md +13 -0
  17. package/.agents/report/port/2026-10-01-api-adjacent-record-id.md +9 -0
  18. package/.agents/report/port/2026-10-01-cycle-01-api-config-route.md +9 -0
  19. package/.agents/report/port/2026-10-01-cycle-03-custom-action.md +9 -0
  20. package/.agents/report/port/2026-10-01-cycle-04-custom-component.md +7 -0
  21. package/.agents/report/port/2026-10-01-cycle-05-custom-query.md +7 -0
  22. package/.agents/report/port/2026-10-01-cycle-08-bulk-delete.md +9 -0
  23. package/.agents/report/port/2026-10-01-cycle-09-duplicate-record.md +9 -0
  24. package/.agents/report/port/2026-10-01-cycle-10-notification-badges.md +9 -0
  25. package/.agents/report/port/2026-10-01-cycle-11-record.md +7 -0
  26. package/.agents/report/port/2026-10-01-cycle-12-search-companies.md +11 -0
  27. package/.agents/report/port/2026-10-01-cycle-14-upload-file.md +7 -0
  28. package/.agents/report/port/2026-10-03-cycle-01-create-record.md +11 -0
  29. package/.agents/report/port/2026-10-03-cycle-02-delete-record.md +11 -0
  30. package/.agents/report/port/2026-10-03-cycle-03-panel-delete-record.md +11 -0
  31. package/.agents/report/port/2026-10-03-cycle-04-update-record.md +11 -0
  32. package/.agents/report/port/2026-10-03-cycle-05-api-values.md +11 -0
  33. package/.agents/report/port/2026-10-06-cycle-01-record-import.md +9 -0
  34. package/.agents/report/port/2026-10-06-cycle-03-rich-text-upload.md +7 -0
  35. package/.agents/report/port/2026-10-06-cycle-04-user-filters.md +11 -0
  36. package/.agents/report/port/2026-10-06-resume-cycle-01-panel-import.md +9 -0
  37. package/.agents/report/port/2026-10-07-cycle-01-api-assembly.md +16 -0
  38. package/.agents/report/port/2026-10-07-cycle-02-index-entry-point.md +13 -0
  39. package/.agents/report/remediation/2026-10-02-api-user-filter-remediation.md +71 -0
  40. package/.agents/report/remediation/2026-10-02-api-values-remediation.md +17 -0
  41. package/.agents/report/remediation/2026-10-03-callback-id-contract-remediation.md +36 -0
  42. package/.agents/report/remediation/2026-10-06-import-parser-remediation.md +41 -0
  43. package/.agents/report/remediation/2026-10-06-rich-text-upload-remediation.md +33 -0
  44. package/.agents/report/remediation/2026-10-07-api-assembly-remediation.md +32 -0
  45. package/.agents/skills/port-javascript-to-typescript/SKILL.md +42 -0
  46. package/.agents/skills/port-javascript-to-typescript/agents/openai.yaml +3 -0
  47. package/.agents/skills/port-javascript-to-typescript/references/blockers.md +31 -0
  48. package/.agents/skills/port-javascript-to-typescript/references/planning.md +43 -0
  49. package/.agents/skills/port-javascript-to-typescript/references/porting.md +9 -0
  50. package/.agents/skills/port-javascript-to-typescript/references/reporting.md +24 -0
  51. package/.agents/skills/port-javascript-to-typescript/references/rules.md +8 -0
  52. package/.agents/skills/port-javascript-to-typescript/references/selection.md +16 -0
  53. package/.agents/skills/port-javascript-to-typescript/references/tools.md +20 -0
  54. package/.agents/skills/port-javascript-to-typescript/scripts/check.sh +17 -0
  55. package/.agents/skills/port-javascript-to-typescript/scripts/graph.sh +30 -0
  56. package/.agents/skills/port-javascript-to-typescript/scripts/madge.json +12 -0
  57. package/.agents/skills/port-javascript-to-typescript/scripts/oxlint.json +14 -0
  58. package/.agents/skills/port-javascript-to-typescript/scripts/test-tools.cjs +76 -0
  59. package/AGENTS.md +5 -0
  60. package/dist/api/authorization.d.ts +38 -0
  61. package/dist/api/authorization.js +74 -0
  62. package/dist/api/authorization.js.map +1 -0
  63. package/dist/api/config.d.ts +42 -0
  64. package/dist/api/config.js +105 -0
  65. package/dist/api/config.js.map +1 -0
  66. package/dist/api/filterUser.d.ts +2 -0
  67. package/dist/api/filterUser.js +24 -0
  68. package/dist/api/filterUser.js.map +1 -0
  69. package/dist/api/importRecords.d.ts +1 -0
  70. package/dist/api/importRecords.js +16 -0
  71. package/dist/api/importRecords.js.map +1 -0
  72. package/dist/api/queries.d.ts +48 -0
  73. package/dist/api/queries.js +139 -0
  74. package/dist/api/queries.js.map +1 -0
  75. package/dist/api/request.d.ts +29 -0
  76. package/dist/api/request.js +3 -0
  77. package/dist/api/request.js.map +1 -0
  78. package/dist/api/routes/adjacentRecordId.d.ts +10 -0
  79. package/dist/api/routes/adjacentRecordId.js +13 -0
  80. package/dist/api/routes/adjacentRecordId.js.map +1 -0
  81. package/dist/api/routes/config.d.ts +3 -0
  82. package/dist/api/routes/config.js +27 -0
  83. package/dist/api/routes/config.js.map +1 -0
  84. package/dist/api/routes/createRecord.d.ts +19 -0
  85. package/dist/api/routes/createRecord.js +93 -0
  86. package/dist/api/routes/createRecord.js.map +1 -0
  87. package/dist/api/routes/customAction.d.ts +17 -0
  88. package/dist/api/routes/customAction.js +35 -0
  89. package/dist/api/routes/customAction.js.map +1 -0
  90. package/dist/api/routes/customComponent.d.ts +3 -0
  91. package/dist/api/routes/customComponent.js +34 -0
  92. package/dist/api/routes/customComponent.js.map +1 -0
  93. package/dist/api/routes/customQuery.d.ts +7 -0
  94. package/dist/api/routes/customQuery.js +33 -0
  95. package/dist/api/routes/customQuery.js.map +1 -0
  96. package/dist/api/routes/deleteRecord.d.ts +9 -0
  97. package/dist/api/routes/deleteRecord.js +46 -0
  98. package/dist/api/routes/deleteRecord.js.map +1 -0
  99. package/dist/api/routes/deleteRecordFromPanel.d.ts +10 -0
  100. package/dist/api/routes/deleteRecordFromPanel.js +36 -0
  101. package/dist/api/routes/deleteRecordFromPanel.js.map +1 -0
  102. package/dist/api/routes/deleteRecords.d.ts +9 -0
  103. package/dist/api/routes/deleteRecords.js +12 -0
  104. package/dist/api/routes/deleteRecords.js.map +1 -0
  105. package/dist/api/routes/duplicateRecord.d.ts +17 -0
  106. package/dist/api/routes/duplicateRecord.js +55 -0
  107. package/dist/api/routes/duplicateRecord.js.map +1 -0
  108. package/dist/api/routes/foreignSelectRecords.d.ts +10 -0
  109. package/dist/api/routes/foreignSelectRecords.js +61 -0
  110. package/dist/api/routes/foreignSelectRecords.js.map +1 -0
  111. package/dist/api/routes/notificationBadges.d.ts +6 -0
  112. package/dist/api/routes/notificationBadges.js +31 -0
  113. package/dist/api/routes/notificationBadges.js.map +1 -0
  114. package/dist/api/routes/record.d.ts +7 -0
  115. package/dist/api/routes/record.js +32 -0
  116. package/dist/api/routes/record.js.map +1 -0
  117. package/dist/api/routes/records.d.ts +14 -0
  118. package/dist/api/routes/records.js +57 -0
  119. package/dist/api/routes/records.js.map +1 -0
  120. package/dist/api/routes/recordsExport.d.ts +13 -0
  121. package/dist/api/routes/recordsExport.js +67 -0
  122. package/dist/api/routes/recordsExport.js.map +1 -0
  123. package/dist/api/routes/recordsImport.d.ts +4 -0
  124. package/dist/api/routes/recordsImport.js +100 -0
  125. package/dist/api/routes/recordsImport.js.map +1 -0
  126. package/dist/api/routes/searchCompanies.d.ts +17 -0
  127. package/dist/api/routes/searchCompanies.js +72 -0
  128. package/dist/api/routes/searchCompanies.js.map +1 -0
  129. package/dist/api/routes/subrecordsImport.d.ts +4 -0
  130. package/dist/api/routes/subrecordsImport.js +94 -0
  131. package/dist/api/routes/subrecordsImport.js.map +1 -0
  132. package/dist/api/routes/updateRecord.d.ts +13 -0
  133. package/dist/api/routes/updateRecord.js +55 -0
  134. package/dist/api/routes/updateRecord.js.map +1 -0
  135. package/dist/api/routes/uploadFile.d.ts +3 -0
  136. package/dist/api/routes/uploadFile.js +13 -0
  137. package/dist/api/routes/uploadFile.js.map +1 -0
  138. package/dist/api/routes/uploadFileFromBetterRichTextInput.d.ts +3 -0
  139. package/dist/api/routes/uploadFileFromBetterRichTextInput.js +33 -0
  140. package/dist/api/routes/uploadFileFromBetterRichTextInput.js.map +1 -0
  141. package/dist/api/uploadFile.d.ts +4 -0
  142. package/dist/api/uploadFile.js +209 -0
  143. package/dist/api/uploadFile.js.map +1 -0
  144. package/dist/api/values.d.ts +6 -0
  145. package/dist/api/values.js +88 -0
  146. package/dist/api/values.js.map +1 -0
  147. package/dist/api.d.ts +8 -27
  148. package/dist/api.js +80 -1387
  149. package/dist/api.js.map +1 -1
  150. package/dist/index.d.ts +2 -2
  151. package/dist/index.js +8 -2
  152. package/dist/index.js.map +1 -1
  153. package/dist/tsconfig.strict.tsbuildinfo +1 -0
  154. package/dist/types/config.d.ts +15 -5
  155. package/dist/types/config.js +4 -0
  156. package/dist/types/config.js.map +1 -1
  157. package/dist/types/database.d.ts +1 -0
  158. package/dist/types/database.js +3 -0
  159. package/dist/types/database.js.map +1 -0
  160. package/dist/utils/dbManager.d.ts +32 -7
  161. package/dist/utils/dbManager.js +59 -7
  162. package/dist/utils/dbManager.js.map +1 -1
  163. package/package.json +12 -3
  164. package/src/api/authorization.ts +129 -0
  165. package/src/api/config.ts +152 -0
  166. package/src/api/filterUser.ts +28 -0
  167. package/src/api/importRecords.ts +16 -0
  168. package/src/api/queries.ts +194 -0
  169. package/src/api/request.ts +31 -0
  170. package/src/api/routes/adjacentRecordId.ts +20 -0
  171. package/src/api/routes/config.ts +15 -0
  172. package/src/api/routes/createRecord.ts +131 -0
  173. package/src/api/routes/customAction.ts +60 -0
  174. package/src/api/routes/customComponent.ts +44 -0
  175. package/src/api/routes/customQuery.ts +53 -0
  176. package/src/api/routes/deleteRecord.ts +59 -0
  177. package/src/api/routes/deleteRecordFromPanel.ts +58 -0
  178. package/src/api/routes/deleteRecords.ts +28 -0
  179. package/src/api/routes/duplicateRecord.ts +73 -0
  180. package/src/api/routes/foreignSelectRecords.ts +80 -0
  181. package/src/api/routes/notificationBadges.ts +47 -0
  182. package/src/api/routes/record.ts +48 -0
  183. package/src/api/routes/records.ts +91 -0
  184. package/src/api/routes/recordsExport.ts +92 -0
  185. package/src/api/routes/recordsImport.ts +115 -0
  186. package/src/api/routes/searchCompanies.ts +96 -0
  187. package/src/api/routes/subrecordsImport.ts +114 -0
  188. package/src/api/routes/updateRecord.ts +74 -0
  189. package/src/api/routes/uploadFile.ts +16 -0
  190. package/src/api/routes/uploadFileFromBetterRichTextInput.ts +41 -0
  191. package/src/api/uploadFile.ts +249 -0
  192. package/src/api/values.ts +96 -0
  193. package/src/api.ts +94 -1580
  194. package/src/index.ts +42 -25
  195. package/src/types/config.ts +15 -5
  196. package/src/types/database.ts +2 -0
  197. package/src/utils/dbManager.ts +99 -14
  198. package/tests/api-helpers.test.ts +59 -0
  199. package/tests/dbManager.test.ts +16 -1
  200. package/tests/helpers/fakeDb.ts +9 -7
  201. package/tests/integration/authorizationBoundary.integration.test.ts +57 -0
  202. package/tests/integration/configEnrichment.integration.test.ts +79 -0
  203. package/tests/integration/customComponentBoundary.integration.test.ts +58 -0
  204. package/tests/integration/dbManager.integration.test.ts +105 -3
  205. package/tests/integration/importParserChild.cjs +55 -0
  206. package/tests/integration/indexRuntime.integration.test.ts +22 -0
  207. package/tests/integration/indexRuntimeChild.cjs +110 -0
  208. package/tests/integration/queries.integration.test.ts +88 -0
  209. package/tests/integration/requestConfig.integration.test.ts +118 -0
  210. package/tests/integration/routes.authorization.integration.test.ts +1 -0
  211. package/tests/integration/routes.config.integration.test.ts +39 -1
  212. package/tests/integration/routes.crud.integration.test.ts +233 -1
  213. package/tests/integration/routes.custom.integration.test.ts +119 -0
  214. package/tests/integration/routes.foreign.integration.test.ts +3 -2
  215. package/tests/integration/routes.importExport.integration.test.ts +308 -6
  216. package/tests/integration/routes.integration.test.ts +4 -0
  217. package/tests/integration/routes.records.integration.test.ts +82 -6
  218. package/tests/integration/routes.upload.integration.test.ts +123 -0
  219. package/tests/integration/userFilters.integration.test.ts +225 -0
  220. package/tsconfig.json +1 -1
  221. package/tsconfig.strict.json +45 -0
  222. package/dist/front/ckeditor5-build/src/ckeditor.d.ts +0 -43
  223. package/dist/front/ckeditor5-build/src/ckeditor.js +0 -130
  224. package/dist/front/ckeditor5-build/src/ckeditor.js.map +0 -1
  225. package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/api.js CHANGED
@@ -1,210 +1,55 @@
1
1
  "use strict";
2
- var __rest = (this && this.__rest) || function (s, e) {
3
- var t = {};
4
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
- t[p] = s[p];
6
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
- t[p[i]] = s[p[i]];
10
- }
11
- return t;
12
- };
13
2
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.touchesHiddenColumn = exports.stripHiddenColumns = exports.hiddenColumnsOf = exports.looksLikeSqlBreakout = exports.writableTables = exports.areSafeColumnNames = exports.MUTATING_VIEW_ROUTES = exports.viewFromRequest = exports.canWriteView = exports.roleOf = exports.ROOT_ROLE = void 0;
15
- exports.generateUniqueIdForObject = generateUniqueIdForObject;
16
- exports.sqlAnd = sqlAnd;
17
- exports.getFormattedValue = getFormattedValue;
18
- exports.evalExpression = evalExpression;
19
- exports.formatValueForInsertion = formatValueForInsertion;
20
- exports.collectAllowedQueries = collectAllowedQueries;
21
- exports.enrichConfig = enrichConfig;
22
- exports.enrichColumn = enrichColumn;
3
+ exports.formatValueForInsertion = exports.evalExpression = exports.getFormattedValue = exports.collectAllowedQueries = exports.sqlAnd = exports.enrichColumn = exports.enrichConfig = exports.generateUniqueIdForObject = exports.looksLikeSqlBreakout = exports.touchesHiddenColumn = exports.stripHiddenColumns = exports.hiddenColumnsOf = exports.writableTables = exports.areSafeColumnNames = exports.MUTATING_VIEW_ROUTES = exports.viewFromRequest = exports.canWriteView = exports.roleOf = exports.ROOT_ROLE = void 0;
23
4
  const express = require("express");
24
- const multiparty = require("multiparty");
25
- const fs = require("fs");
26
- const path = require("path");
27
- const crypto = require("crypto");
28
- const mime = require("mime");
29
- const client_s3_1 = require("@aws-sdk/client-s3");
30
- const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
31
- const storage_1 = require("@google-cloud/storage");
32
- const imageDimensions_1 = require("./utils/imageDimensions");
33
- const serializeJs = require("serialize-javascript");
34
- const SftpClient = require("ssh2-sftp-client");
35
- const rollup = require("rollup");
36
- const plugin_babel_1 = require("@rollup/plugin-babel");
37
- const plugin_node_resolve_1 = require("@rollup/plugin-node-resolve");
38
- const axios_1 = require("axios");
39
- const uuid_1 = require("uuid");
40
- const dbManager_1 = require("./utils/dbManager");
41
- function generateUniqueIdForObject(obj) {
42
- const str = JSON.stringify(obj);
43
- const hash = crypto.createHash("sha256").update(str).digest("hex");
44
- return hash;
45
- }
46
- exports.ROOT_ROLE = "root";
47
- const roleOf = (req) => req.session && req.session.user && req.session.user.role;
48
- exports.roleOf = roleOf;
49
- const canWriteView = (view, role) => role === exports.ROOT_ROLE || !view || !view.roles || view.roles.includes(role);
50
- exports.canWriteView = canWriteView;
51
- const viewFromRequest = (req) => {
52
- const idx = req.body && req.body.viewIndex !== undefined
53
- ? req.body.viewIndex
54
- : req.query && req.query.viewIndex !== undefined
55
- ? req.query.viewIndex
56
- : undefined;
57
- if (idx === undefined || !req.config || !req.config.views)
58
- return undefined;
59
- return req.config.views[idx];
60
- };
61
- exports.viewFromRequest = viewFromRequest;
62
- exports.MUTATING_VIEW_ROUTES = new Set([
63
- "/updateRecord",
64
- "/createRecord",
65
- "/deleteRecord",
66
- "/deleteRecords",
67
- "/deleteRecordFromPanel",
68
- "/customAction",
69
- "/uploadFile",
70
- ]);
71
- const areSafeColumnNames = (data) => !data || Object.keys(data).every((k) => /^[A-Za-z0-9_]+$/.test(k));
72
- exports.areSafeColumnNames = areSafeColumnNames;
73
- const writableTables = (req) => {
74
- var _a, _b;
75
- const role = (0, exports.roleOf)(req);
76
- const tables = new Set();
77
- for (const view of ((_a = req.config) === null || _a === void 0 ? void 0 : _a.views) || []) {
78
- if (!(0, exports.canWriteView)(view, role))
79
- continue;
80
- if (view.tableName)
81
- tables.add(view.tableName);
82
- for (const panel of view.recordViewPanels || []) {
83
- if (panel.tableName)
84
- tables.add(panel.tableName);
85
- if ((_b = panel.createConfig) === null || _b === void 0 ? void 0 : _b.tableName)
86
- tables.add(panel.createConfig.tableName);
87
- }
88
- }
89
- return tables;
90
- };
91
- exports.writableTables = writableTables;
92
- const looksLikeSqlBreakout = (frag) => typeof frag === "string" &&
93
- /(;|--|\/\*|\bunion\b|\binto\s+(out|dump)file\b|\bsleep\s*\(|\bbenchmark\s*\(|\bload_file\s*\()/i.test(frag);
94
- exports.looksLikeSqlBreakout = looksLikeSqlBreakout;
95
- function sqlAnd(conditions) {
96
- const existingConditions = [];
97
- for (const condition of conditions) {
98
- if (condition && condition.length > 0) {
99
- existingConditions.push(condition);
100
- }
101
- }
102
- if (existingConditions.length <= 1) {
103
- return existingConditions[0] || null;
104
- }
105
- else {
106
- let result = "";
107
- for (let i = 0; i < existingConditions.length; i++) {
108
- if (i > 0) {
109
- result += " AND ";
110
- }
111
- result += "(" + existingConditions[i] + ")";
112
- }
113
- return result;
114
- }
115
- }
116
- async function getFormattedValue(column, record) {
117
- let value;
118
- try {
119
- record.options = column.options;
120
- if (column.formatValueForExport) {
121
- value = await column.formatValueForExport(record);
122
- }
123
- else if (column.formattedValue) {
124
- value = evalExpression(column.formattedValue, record);
125
- }
126
- else if (column.formatValue) {
127
- value = await column.formatValue(record);
128
- }
129
- else if (column.dataType == "tinyint") {
130
- value = record[column.name] == 1 ? "Oui" : "Non";
131
- }
132
- else {
133
- value = record[column.name];
134
- }
135
- return value === null || typeof value == "undefined" ? "" : value;
136
- }
137
- catch (err) {
138
- return value || "";
139
- }
140
- }
141
- function evalExpression(expression, data) {
142
- let varString = "";
143
- let statement = "";
144
- try {
145
- for (let key in data) {
146
- statement =
147
- "var " +
148
- key +
149
- " = " +
150
- (typeof data[key] === "string"
151
- ? "'" +
152
- data[key]
153
- .replace(/'/g, "\\'")
154
- .replace(/\n/g, "")
155
- .replace(/\r/g, "") +
156
- "'"
157
- : typeof data[key] === "object"
158
- ? JSON.stringify(data[key])
159
- : data[key]) +
160
- ";";
161
- varString += statement;
162
- }
163
- const result = eval(varString + expression);
164
- return result;
165
- }
166
- catch (e) {
167
- console.log("Problème d'évaluation de l'expression", statement);
168
- console.error(e);
169
- return "Error";
170
- }
171
- }
172
- function formatValueForInsertion(value, dbType) {
173
- if (value !== 0 && !value) {
174
- return "NULL";
175
- }
176
- if (value instanceof Date) {
177
- return value.toISOString();
178
- }
179
- if (typeof value === "string") {
180
- if (dbType === "POSTGRESQL") {
181
- return "'" + value.replace(/'/g, "''") + "'";
182
- }
183
- else {
184
- return "'" + value.replace(/'/g, "\\'") + "'";
185
- }
186
- }
187
- if (typeof value === "object") {
188
- return "'" + JSON.stringify(value).replace(/'/g, "\\'") + "'";
189
- }
190
- if (typeof value === "boolean") {
191
- return value ? "TRUE" : "FALSE";
192
- }
193
- if (typeof value === "number") {
194
- return value;
195
- }
196
- return value;
197
- }
198
- const hiddenColumnsOf = (view) => (view && view.__hiddenColumns) || [];
199
- exports.hiddenColumnsOf = hiddenColumnsOf;
200
- const stripHiddenColumns = (view, record) => {
201
- for (const name of (0, exports.hiddenColumnsOf)(view))
202
- delete record[name];
203
- return record;
204
- };
205
- exports.stripHiddenColumns = stripHiddenColumns;
206
- const touchesHiddenColumn = (view, data) => (0, exports.hiddenColumnsOf)(view).some((name) => data && Object.prototype.hasOwnProperty.call(data, name));
207
- exports.touchesHiddenColumn = touchesHiddenColumn;
5
+ require("./api/request");
6
+ const authorization_1 = require("./api/authorization");
7
+ const config_1 = require("./api/config");
8
+ const queries_1 = require("./api/queries");
9
+ const config_2 = require("./api/routes/config");
10
+ const customComponent_1 = require("./api/routes/customComponent");
11
+ const adjacentRecordId_1 = require("./api/routes/adjacentRecordId");
12
+ const foreignSelectRecords_1 = require("./api/routes/foreignSelectRecords");
13
+ const records_1 = require("./api/routes/records");
14
+ const recordsExport_1 = require("./api/routes/recordsExport");
15
+ const recordsImport_1 = require("./api/routes/recordsImport");
16
+ const subrecordsImport_1 = require("./api/routes/subrecordsImport");
17
+ const record_1 = require("./api/routes/record");
18
+ const updateRecord_1 = require("./api/routes/updateRecord");
19
+ const customAction_1 = require("./api/routes/customAction");
20
+ const deleteRecord_1 = require("./api/routes/deleteRecord");
21
+ const deleteRecordFromPanel_1 = require("./api/routes/deleteRecordFromPanel");
22
+ const deleteRecords_1 = require("./api/routes/deleteRecords");
23
+ const notificationBadges_1 = require("./api/routes/notificationBadges");
24
+ const duplicateRecord_1 = require("./api/routes/duplicateRecord");
25
+ const createRecord_1 = require("./api/routes/createRecord");
26
+ const customQuery_1 = require("./api/routes/customQuery");
27
+ const uploadFileFromBetterRichTextInput_1 = require("./api/routes/uploadFileFromBetterRichTextInput");
28
+ const uploadFile_1 = require("./api/routes/uploadFile");
29
+ const searchCompanies_1 = require("./api/routes/searchCompanies");
30
+ var authorization_2 = require("./api/authorization");
31
+ Object.defineProperty(exports, "ROOT_ROLE", { enumerable: true, get: function () { return authorization_2.ROOT_ROLE; } });
32
+ Object.defineProperty(exports, "roleOf", { enumerable: true, get: function () { return authorization_2.roleOf; } });
33
+ Object.defineProperty(exports, "canWriteView", { enumerable: true, get: function () { return authorization_2.canWriteView; } });
34
+ Object.defineProperty(exports, "viewFromRequest", { enumerable: true, get: function () { return authorization_2.viewFromRequest; } });
35
+ Object.defineProperty(exports, "MUTATING_VIEW_ROUTES", { enumerable: true, get: function () { return authorization_2.MUTATING_VIEW_ROUTES; } });
36
+ Object.defineProperty(exports, "areSafeColumnNames", { enumerable: true, get: function () { return authorization_2.areSafeColumnNames; } });
37
+ Object.defineProperty(exports, "writableTables", { enumerable: true, get: function () { return authorization_2.writableTables; } });
38
+ Object.defineProperty(exports, "hiddenColumnsOf", { enumerable: true, get: function () { return authorization_2.hiddenColumnsOf; } });
39
+ Object.defineProperty(exports, "stripHiddenColumns", { enumerable: true, get: function () { return authorization_2.stripHiddenColumns; } });
40
+ Object.defineProperty(exports, "touchesHiddenColumn", { enumerable: true, get: function () { return authorization_2.touchesHiddenColumn; } });
41
+ Object.defineProperty(exports, "looksLikeSqlBreakout", { enumerable: true, get: function () { return authorization_2.looksLikeSqlBreakout; } });
42
+ var config_3 = require("./api/config");
43
+ Object.defineProperty(exports, "generateUniqueIdForObject", { enumerable: true, get: function () { return config_3.generateUniqueIdForObject; } });
44
+ Object.defineProperty(exports, "enrichConfig", { enumerable: true, get: function () { return config_3.enrichConfig; } });
45
+ Object.defineProperty(exports, "enrichColumn", { enumerable: true, get: function () { return config_3.enrichColumn; } });
46
+ var queries_2 = require("./api/queries");
47
+ Object.defineProperty(exports, "sqlAnd", { enumerable: true, get: function () { return queries_2.sqlAnd; } });
48
+ Object.defineProperty(exports, "collectAllowedQueries", { enumerable: true, get: function () { return queries_2.collectAllowedQueries; } });
49
+ var values_1 = require("./api/values");
50
+ Object.defineProperty(exports, "getFormattedValue", { enumerable: true, get: function () { return values_1.getFormattedValue; } });
51
+ Object.defineProperty(exports, "evalExpression", { enumerable: true, get: function () { return values_1.evalExpression; } });
52
+ Object.defineProperty(exports, "formatValueForInsertion", { enumerable: true, get: function () { return values_1.formatValueForInsertion; } });
208
53
  exports.default = (db, config) => {
209
54
  const app = express();
210
55
  app.use((req, res, next) => {
@@ -230,7 +75,8 @@ exports.default = (db, config) => {
230
75
  column.roles.includes(req.session.user.role));
231
76
  return Object.assign(Object.assign({}, view), { columns: view.columns.filter(allowed), __hiddenColumns: view.columns
232
77
  .filter((column) => !allowed(column))
233
- .map((column) => column.name) });
78
+ .map((column) => column.name)
79
+ .filter((name) => name != null) });
234
80
  }
235
81
  else {
236
82
  return view;
@@ -240,1207 +86,54 @@ exports.default = (db, config) => {
240
86
  });
241
87
  app.use(async (req, res, next) => {
242
88
  if (!req.config.enriched) {
243
- await enrichConfig(req.config, db);
89
+ await (0, config_1.enrichConfig)(req.config, db);
244
90
  }
245
91
  next();
246
92
  });
247
93
  app.use((req, res, next) => {
248
- const role = (0, exports.roleOf)(req);
94
+ const role = (0, authorization_1.roleOf)(req);
249
95
  if (req.body && Array.isArray(req.body.filters)) {
250
- if (req.body.filters.some(exports.looksLikeSqlBreakout)) {
96
+ if (req.body.filters.some(authorization_1.looksLikeSqlBreakout)) {
251
97
  return res.status(400).send({ error: "Invalid filter" });
252
98
  }
253
99
  }
254
- if (exports.MUTATING_VIEW_ROUTES.has(req.path)) {
255
- const view = (0, exports.viewFromRequest)(req);
256
- if (!view || !(0, exports.canWriteView)(view, role)) {
100
+ if (authorization_1.MUTATING_VIEW_ROUTES.has(req.path)) {
101
+ const view = (0, authorization_1.viewFromRequest)(req);
102
+ if (!view || !(0, authorization_1.canWriteView)(view, role)) {
257
103
  return res.sendStatus(403);
258
104
  }
259
105
  }
260
106
  next();
261
107
  });
262
- async function getRecords(params, computeCount = false) {
263
- var _a;
264
- let queryString = "";
265
- if (params.filters) {
266
- queryString = " WHERE (" + params.filters + ")";
267
- }
268
- if (params.query) {
269
- const columns = params.columns;
270
- let isNewCondition = true;
271
- for (let i in columns) {
272
- if (columns[i].searchable !== false &&
273
- (columns[i].searchableName || columns[i].name)) {
274
- if (queryString.length == 0) {
275
- queryString += " WHERE (";
276
- }
277
- else if (isNewCondition) {
278
- queryString += " AND (";
279
- }
280
- else {
281
- queryString += " OR ";
282
- }
283
- if (columns[i].searchableName) {
284
- queryString += columns[i].searchableName;
285
- }
286
- else if (columns[i].name) {
287
- queryString += columns[i].name
288
- .split(".")
289
- .map((x) => (0, dbManager_1.quoteIdentifier)(x, db.dbType))
290
- .join(".");
291
- }
292
- const searchEscaped = db.dbType === "POSTGRESQL"
293
- ? params.query.replace(/'/g, "''")
294
- : params.query.replace(/'/g, "\\'");
295
- queryString += " LIKE '%" + searchEscaped + "%'";
296
- isNewCondition = false;
297
- }
298
- }
299
- queryString += ")";
300
- }
301
- const limit = params.allRecords ? 999999 : parseInt(params.limit);
302
- const query = params.customQuery ||
303
- `SELECT
304
- ${params.selectExpression || "*"}
305
- FROM ${params.table}
306
- ${params.join || ""}
307
- ${queryString}
308
- ${params.groupBy ? "GROUP BY " + params.groupBy : ""}
309
- ${params.having ? " HAVING " + params.having : ""}
310
- ${params.orderBy || params.primaryId ? " ORDER BY " + (params.orderBy || `${params.table}.${params.primaryId}`) : ""}`;
311
- const { err, rows } = await db.query(`${query} LIMIT ${limit} OFFSET ${Math.max((params.page - 1) * limit, 0)}`);
312
- if (err) {
313
- console.error(err);
314
- return {
315
- error: err,
316
- };
317
- }
318
- let count = undefined;
319
- if (computeCount) {
320
- const { err: countErr, rows: countRows } = await db.query(`SELECT COUNT(*) AS count FROM (${query}) s`);
321
- if (countErr) {
322
- const { rows: allRows } = await db.query(query);
323
- count = allRows.length;
324
- }
325
- else {
326
- count = ((_a = countRows === null || countRows === void 0 ? void 0 : countRows[0]) === null || _a === void 0 ? void 0 : _a.count) || 0;
327
- }
328
- }
329
- return {
330
- rows,
331
- queryString,
332
- input: {
333
- query,
334
- params,
335
- },
336
- count,
337
- };
338
- }
339
- async function findRecordByPosition(params) {
340
- return await getRecords(Object.assign(params, {
341
- page: parseInt(params.position) + parseInt(params.offset),
342
- limit: 1,
343
- }));
344
- }
345
- app.get("/config", async (req, res) => {
346
- try {
347
- const _a = req.config, { mysql, auth, sessionSecret } = _a, safeConfig = __rest(_a, ["mysql", "auth", "sessionSecret"]);
348
- res.send({
349
- config: serializeJs(safeConfig),
350
- });
351
- }
352
- catch (e) {
353
- console.error(e);
354
- res.sendStatus(500);
355
- }
356
- });
357
- app.get("/customComponent", async (req, res) => {
358
- try {
359
- const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "../src/front/package.json"), "utf-8"));
360
- const external = Object.keys(pkg.dependencies || {});
361
- const bundle = await rollup.rollup({
362
- input: path.join(__dirname, "../../", req.query.componentPath),
363
- plugins: [
364
- (0, plugin_node_resolve_1.default)(),
365
- (0, plugin_babel_1.default)({
366
- configFile: path.join(__dirname, "../babel.config"),
367
- babelHelpers: "bundled",
368
- }),
369
- ],
370
- external,
371
- });
372
- const { output } = await bundle.generate({
373
- format: "cjs",
374
- exports: "auto",
375
- });
376
- res.send(output[0].code);
377
- }
378
- catch (err) {
379
- console.error(err);
380
- res.sendStatus(500);
381
- }
382
- });
383
- app.post("/adjacentRecordId", async function (req, res, next) {
384
- const { rows, error } = await findRecordByPosition(req.body);
385
- if (error) {
386
- return res.status(500).send(error);
387
- }
388
- const recordId = rows[0] ? rows[0][req.body.primaryId] : null;
389
- res.send({
390
- recordId: recordId,
391
- });
392
- });
393
- app.post("/foreignSelectRecords", async (req, res, next) => {
394
- var _a, _b, _c, _d, _e;
395
- const view = req.config.views[req.body.viewIndex];
396
- const column = [
397
- ...view.columns,
398
- ...(((_c = (_b = (_a = view.recordViewPanels) === null || _a === void 0 ? void 0 : _a.map((x) => { var _a; return (_a = x === null || x === void 0 ? void 0 : x.createConfig) === null || _a === void 0 ? void 0 : _a.columns; })) === null || _b === void 0 ? void 0 : _b.filter((x) => x)) === null || _c === void 0 ? void 0 : _c.flat()) || []),
399
- ].find((x) => x.__id__ === req.body.columnId);
400
- const queryEscaped = db.dbType === "POSTGRESQL"
401
- ? (_d = req.body.query) === null || _d === void 0 ? void 0 : _d.replace(/'/g, "''")
402
- : (_e = req.body.query) === null || _e === void 0 ? void 0 : _e.replace(/'/g, "\\'");
403
- const { rows: records, error } = await getRecords({
404
- table: column.table,
405
- page: 1,
406
- filters: sqlAnd([
407
- column.filters,
408
- req.body.query
409
- ? `${column.searchableName} LIKE '${column.wholeSearch ? "%" : ""}${queryEscaped}%'`
410
- : null,
411
- column.filtersFromUser
412
- ? column.filtersFromUser(req.session.user.userId, req.session.user.role)
413
- : null,
414
- ]),
415
- join: column.join,
416
- selectExpression: column.selectExpression,
417
- orderBy: column.orderBy,
418
- limit: column.limit || 1000,
419
- });
420
- if (error) {
421
- return res.status(500).send(error);
422
- }
423
- const options = await Promise.all(records.map(async (record) => {
424
- let label;
425
- if (column.formatForeignValue) {
426
- label = await column.formatForeignValue(record);
427
- }
428
- else if (column.formatValue) {
429
- label = await column.formatValue(record);
430
- }
431
- else if (column.formattedValue) {
432
- label = evalExpression(column.formattedValue, record);
433
- }
434
- else {
435
- label = record[column.name];
436
- }
437
- const value = record[column.foreignName] || record[column.name];
438
- return {
439
- value,
440
- label,
441
- };
442
- }));
443
- res.send(options);
444
- });
445
- app.post("/records", async function (req, res, next) {
446
- const view = req.config.views[req.body.viewIndex];
447
- const isDesc = req.body.isDesc === null ? view.isDesc : req.body.isDesc;
448
- const subview = view.subviews && req.body.subviewIndex !== undefined
449
- ? view.subviews[req.body.subviewIndex]
450
- : null;
451
- const orderBy = req.body.orderBy || (subview === null || subview === void 0 ? void 0 : subview.orderBy) || view.orderBy;
452
- const { rows: records, input, error, count, } = await getRecords({
453
- table: view.tableName,
454
- page: req.body.page,
455
- filters: sqlAnd([
456
- view.filters,
457
- subview === null || subview === void 0 ? void 0 : subview.filters,
458
- ...req.body.filters,
459
- view.filtersFromUser
460
- ? view.filtersFromUser(req.session.user.userId, req.session.user.role)
461
- : null,
462
- ]),
463
- having: subview === null || subview === void 0 ? void 0 : subview.having,
464
- customQuery: view.customQuery,
465
- join: view.join,
466
- selectExpression: view.selectExpression,
467
- orderBy: [
468
- orderBy ? `${orderBy} ${isDesc ? "DESC" : "ASC"}` : null,
469
- view.primaryId,
470
- ]
471
- .filter((x) => x)
472
- .join(", "),
473
- primaryId: view.primaryId,
474
- query: req.body.query,
475
- groupBy: view.groupBy,
476
- columns: view.columns,
477
- limit: view.limit || 10,
478
- }, true);
479
- if (error) {
480
- return res.status(500).send(error);
481
- }
482
- for (const column of view.columns) {
483
- if (column.formatValue) {
484
- for (const record of records) {
485
- record[`__formatValue-${column.__id__}__`] =
486
- await column.formatValue(record);
487
- }
488
- }
489
- }
490
- for (const record of records)
491
- (0, exports.stripHiddenColumns)(view, record);
492
- res.send({
493
- records,
494
- input,
495
- count,
496
- });
497
- });
108
+ const { getRecords, findRecordByPosition } = (0, queries_1.default)(db);
109
+ app.get("/config", (0, config_2.default)());
110
+ app.get("/customComponent", (0, customComponent_1.default)(__dirname));
111
+ app.post("/adjacentRecordId", (0, adjacentRecordId_1.default)(findRecordByPosition));
112
+ app.post("/foreignSelectRecords", (0, foreignSelectRecords_1.default)(db, getRecords));
113
+ app.post("/records", (0, records_1.default)(getRecords));
498
114
  const formattedValueToFunction = {};
499
- app.post("/recordsExport", async function (req, res) {
500
- const view = req.config.views[req.body.viewIndex];
501
- const orderBy = req.body.orderBy || view.orderBy;
502
- const isDesc = req.body.isDesc === null ? view.isDesc : req.body.isDesc;
503
- const subview = view.subviews && req.body.subviewIndex !== undefined
504
- ? view.subviews[req.body.subviewIndex]
505
- : null;
506
- const { rows: records, error } = await getRecords({
507
- table: view.tableName,
508
- page: 1,
509
- allRecords: true,
510
- filters: sqlAnd([
511
- view.filters,
512
- subview === null || subview === void 0 ? void 0 : subview.filters,
513
- req.body.filters,
514
- view.filtersFromUser
515
- ? view.filtersFromUser(req.session.user.userId, req.session.user.role)
516
- : null,
517
- ]),
518
- having: subview === null || subview === void 0 ? void 0 : subview.having,
519
- customQuery: view.customQuery,
520
- join: view.join,
521
- selectExpression: view.selectExpression,
522
- orderBy: orderBy ? `${orderBy} ${isDesc ? "DESC" : "ASC"}` : null,
523
- primaryId: view.primaryId,
524
- query: req.body.query,
525
- groupBy: view.groupBy,
526
- columns: view.columns,
527
- limit: view.limit || 10,
528
- });
529
- if (error) {
530
- return res.status(500).send(error);
531
- }
532
- let output = "";
533
- const columns = view.columns;
534
- for (let j = 0; j < columns.length; j++) {
535
- if (!columns[j].hideInTable || columns[j].includeInExport) {
536
- if (j > 0)
537
- output += ";";
538
- output += columns[j].label;
539
- }
540
- }
541
- for (let i in records) {
542
- const el = records[i];
543
- output += "\r\n";
544
- for (let j = 0; j < columns.length; j++) {
545
- if (!columns[j].hideInTable || columns[j].includeInExport) {
546
- if (j > 0)
547
- output += ";";
548
- if (columns[j].dataType == "textarea") {
549
- output += '"';
550
- }
551
- output += await getFormattedValue(columns[j], el);
552
- if (columns[j].dataType == "textarea") {
553
- output += '"';
554
- }
555
- }
556
- }
557
- }
558
- res.send({
559
- content: output,
560
- });
561
- });
562
- app.post("/recordsImport", async function (req, res) {
563
- const form = new multiparty.Form();
564
- form.parse(req, async function (err, fields, files) {
565
- if (err) {
566
- return res.status(500).send(err);
567
- }
568
- const view = req.config.views[fields.viewIndex[0]];
569
- if (!view || !(0, exports.canWriteView)(view, (0, exports.roleOf)(req))) {
570
- return res.sendStatus(403);
571
- }
572
- if (typeof view.parseImportFile !== "function") {
573
- return res
574
- .status(500)
575
- .send('"parseImportFile" doit être défini dans la configuration de la vue.');
576
- }
577
- const records = await view.parseImportFile(files.data[0]);
578
- const columns = [];
579
- if (records.length === 0) {
580
- return res.send({
581
- affectedRows: 0,
582
- });
583
- }
584
- try {
585
- for (let record of records) {
586
- for (let key in record) {
587
- if (!columns.includes(key)) {
588
- columns.push(key);
589
- }
590
- }
591
- }
592
- if (columns.some((name) => (0, exports.hiddenColumnsOf)(view).includes(name))) {
593
- return res.sendStatus(403);
594
- }
595
- let queryString;
596
- if (db.dbType === "POSTGRESQL") {
597
- queryString = `INSERT INTO ?? (${columns.map((x) => (0, dbManager_1.quoteIdentifier)(x, db.dbType)).join(", ")}) VALUES`;
598
- for (let record of records) {
599
- const valuesList = columns
600
- .map((x) => formatValueForInsertion(record[x], db.dbType))
601
- .join(", ");
602
- queryString += ` (${valuesList}),`;
603
- }
604
- queryString =
605
- queryString.slice(0, -1) +
606
- ` ON CONFLICT (${view.importFileUniqueField}) DO UPDATE SET `;
607
- for (let column of columns) {
608
- queryString += `${(0, dbManager_1.quoteIdentifier)(column, db.dbType)} = EXCLUDED.${(0, dbManager_1.quoteIdentifier)(column, db.dbType)},`;
609
- }
610
- }
611
- else {
612
- queryString =
613
- "INSERT INTO ?? (" +
614
- columns.map((x) => (0, dbManager_1.quoteIdentifier)(x, db.dbType)).join(", ") +
615
- ") VALUES";
616
- for (let record of records) {
617
- queryString +=
618
- " (" +
619
- columns
620
- .map((x) => formatValueForInsertion(record[x], db.dbType))
621
- .join(", ") +
622
- "),";
623
- }
624
- queryString = queryString.slice(0, -1) + " ON DUPLICATE KEY UPDATE";
625
- for (let column of columns) {
626
- queryString += ` ${(0, dbManager_1.quoteIdentifier)(column, db.dbType)} = VALUES(${(0, dbManager_1.quoteIdentifier)(column, db.dbType)}),`;
627
- }
628
- }
629
- queryString = queryString.slice(0, -1);
630
- const { err, rows: r } = await db.query(queryString, [view.tableName]);
631
- if (err) {
632
- console.error(err);
633
- return res.status(500).send({
634
- err,
635
- message: "Une erreur est survenue.",
636
- });
637
- }
638
- res.send({
639
- affectedRows: r.affectedRows,
640
- });
641
- }
642
- catch (err) {
643
- console.error(err);
644
- res.status(500).send({
645
- err,
646
- message: "Une erreur est survenue.",
647
- });
648
- }
649
- });
650
- });
651
- app.post("/subrecordsImport", async function (req, res) {
652
- const form = new multiparty.Form();
653
- form.parse(req, async function (err, fields, files) {
654
- if (err) {
655
- return res.status(500).send(err);
656
- }
657
- const view = req.config.views[fields.viewIndex[0]];
658
- const panel = view
659
- ? view.recordViewPanels[fields.panelIndex[0]]
660
- : undefined;
661
- if (!view ||
662
- !(0, exports.canWriteView)(view, (0, exports.roleOf)(req)) ||
663
- !panel ||
664
- !(0, exports.canWriteView)(panel, (0, exports.roleOf)(req))) {
665
- return res.sendStatus(403);
666
- }
667
- if (typeof panel.parseImportFile !== "function") {
668
- return res
669
- .status(500)
670
- .send('"parseImportFile" doit être défini dans la configuration du panneau.');
671
- }
672
- if (!Boolean(panel.createConfig)) {
673
- return res
674
- .status(500)
675
- .send('"createConfig" doit être défini dans la configuration du panneau.');
676
- }
677
- const records = await panel.parseImportFile(files.data[0], fields.recordId[0]);
678
- const columns = [];
679
- if (records.length === 0) {
680
- return res.send({
681
- affectedRows: 0,
682
- });
683
- }
684
- try {
685
- for (let record of records) {
686
- for (let key in record) {
687
- if (!columns.includes(key)) {
688
- columns.push(key);
689
- }
690
- }
691
- }
692
- let queryString = "INSERT IGNORE INTO ?? (" +
693
- (0, dbManager_1.quoteIdentifier)(panel.createConfig.recordIdKey, db.dbType) +
694
- ", " +
695
- columns.map((x) => (0, dbManager_1.quoteIdentifier)(x, db.dbType)).join(", ") +
696
- ") VALUES";
697
- for (let record of records) {
698
- queryString +=
699
- " (" +
700
- fields.recordId[0] +
701
- ", " +
702
- columns
703
- .map((x) => formatValueForInsertion(record[x], db.dbType))
704
- .join(", ") +
705
- "),";
706
- }
707
- queryString = queryString.slice(0, -1) + " ON DUPLICATE KEY UPDATE";
708
- for (let column of columns) {
709
- queryString += ` ${(0, dbManager_1.quoteIdentifier)(column, db.dbType)} = VALUES(${(0, dbManager_1.quoteIdentifier)(column, db.dbType)}),`;
710
- }
711
- const { err, rows: r } = await db.query(queryString.slice(0, -1), [
712
- panel.tableName,
713
- ]);
714
- if (err) {
715
- console.error(err);
716
- return res.status(500).send({
717
- err,
718
- message: "Une erreur est survenue.",
719
- });
720
- }
721
- res.send({
722
- affectedRows: r.affectedRows,
723
- });
724
- }
725
- catch (err) {
726
- console.error(err);
727
- res.status(500).send({
728
- err,
729
- message: "Une erreur est survenue.",
730
- });
731
- }
732
- });
733
- });
734
- app.get("/record", async function (req, res) {
735
- const view = req.config.views[req.query.viewIndex];
736
- const { err, rows } = await db.query("SELECT " +
737
- (view.selectExpression || "*") +
738
- " FROM ?? " +
739
- (view.join || "") +
740
- " WHERE ?? = ?", [
741
- view.tableName,
742
- view.tableName + "." + view.primaryId,
743
- req.query.recordId,
744
- ]);
745
- if (err) {
746
- return res.status(500).send(err);
747
- }
748
- if (rows.length > 0) {
749
- const record = rows[0];
750
- for (const column of view.columns) {
751
- if (column.formatValue) {
752
- record[`__formatValue-${column.__id__}__`] =
753
- await column.formatValue(record);
754
- }
755
- }
756
- res.send((0, exports.stripHiddenColumns)(view, record));
757
- }
758
- else {
759
- res.sendStatus(404);
760
- }
761
- });
762
- app.post("/updateRecord", async function (req, res, next) {
763
- const view = req.config.views[req.body.viewIndex];
764
- if (!(0, exports.areSafeColumnNames)(req.body.data)) {
765
- return res.status(400).send({ error: "Invalid column name" });
766
- }
767
- if ((0, exports.touchesHiddenColumn)(view, req.body.data)) {
768
- return res.sendStatus(403);
769
- }
770
- for (let key in req.body.data) {
771
- if (req.body.data[key] == "NULL" ||
772
- req.body.data[key] === "" ||
773
- req.body.data[key] === "Invalid date") {
774
- req.body.data[key] = null;
775
- }
776
- }
777
- if (Object.keys(req.body.data).length === 0) {
778
- return res.sendStatus(200);
779
- }
780
- const queryExpression = Object.keys(req.body.data)
781
- .map((x) => `${(0, dbManager_1.quoteIdentifier)(x, db.dbType)} = ?`)
782
- .join(", ");
783
- const queryParameters = Object.keys(req.body.data).map((x) => req.body.data[x]);
784
- const { err } = await db.query(`UPDATE ?? SET ${queryExpression} WHERE ?? = ?`, [
785
- view.tableName,
786
- ...queryParameters,
787
- view.primaryId,
788
- req.body.primaryValue,
789
- ]);
790
- if (err) {
791
- return res.status(500).send(err);
792
- }
793
- if (view.editCallback) {
794
- try {
795
- await axios_1.default.post(view.editCallback, {
796
- id: req.body.primaryValue,
797
- data: req.body.data,
798
- previousData: req.body.previousData,
799
- });
800
- }
801
- catch (e) { }
802
- }
803
- if (view.editCallbackFunction) {
804
- await view.editCallbackFunction({
805
- id: req.body.primaryValue,
806
- data: req.body.data,
807
- });
808
- }
809
- res.sendStatus(200);
810
- });
811
- app.post("/customAction", async function (req, res, next) {
812
- const view = req.config.views[req.body.viewIndex];
813
- const action = view.customActions[req.body.actionIndex];
814
- for (const recordId of req.body.selectedRecordIds) {
815
- try {
816
- const { rows } = await db.query("SELECT " +
817
- (view.selectExpression || "*") +
818
- " FROM ?? " +
819
- (view.join || "") +
820
- " WHERE ?? = ?", [view.tableName, view.tableName + "." + view.primaryId, recordId]);
821
- const record = rows[0];
822
- const actionResult = await action.action(record, req.session.user.userId);
823
- if (actionResult) {
824
- return res.send({
825
- success: true,
826
- message: actionResult,
827
- });
828
- }
829
- }
830
- catch (err) {
831
- console.error(err);
832
- return res.send({
833
- success: false,
834
- error: err,
835
- });
836
- }
837
- }
838
- res.send({
839
- success: true,
840
- message: action.successMessage,
841
- });
842
- });
843
- app.post("/deleteRecord", async function (req, res) {
844
- const view = req.config.views[req.body.viewIndex];
845
- const { rows, err: err2 } = await db.query("SELECT " +
846
- (view.selectExpression || "*") +
847
- " FROM ?? " +
848
- (view.join || "") +
849
- " WHERE ?? = ?", [
850
- view.tableName,
851
- view.tableName + "." + view.primaryId,
852
- req.body.primaryValue,
853
- ]);
854
- if (err2) {
855
- return res.status(500).send(err2);
856
- }
857
- const deletedRecord = rows[0];
858
- if (!deletedRecord) {
859
- return res.status(404).send("Record not found");
860
- }
861
- const { err } = await db.query("DELETE FROM ?? WHERE ?? = ?", [
862
- view.tableName,
863
- view.primaryId,
864
- req.body.primaryValue,
865
- ]);
866
- if (err) {
867
- return res.status(500).send(err);
868
- }
869
- if (view.deleteCallback) {
870
- try {
871
- await axios_1.default.post(view.deleteCallback, {
872
- id: req.body.primaryValue,
873
- });
874
- }
875
- catch (e) { }
876
- }
877
- if (view.deleteCallbackFunction) {
878
- await view.deleteCallbackFunction({
879
- id: req.body.primaryValue,
880
- deletedRecord,
881
- });
882
- }
883
- res.sendStatus(200);
884
- });
885
- app.post("/deleteRecordFromPanel", async function (req, res) {
886
- const view = req.config.views[req.body.viewIndex];
887
- const panel = view.recordViewPanels.find((x) => x.__id__ === req.body.panelId);
888
- const { rows, err: err2 } = await db.query("SELECT * FROM ?? WHERE ?? = ?", [panel.tableName, panel.primaryId, req.body.primaryValue]);
889
- if (err2) {
890
- return res.status(500).send(err2);
891
- }
892
- const deletedRecord = rows[0];
893
- const { err } = await db.query("DELETE FROM ?? WHERE ?? = ?", [
894
- panel.tableName,
895
- panel.primaryId,
896
- req.body.primaryValue,
897
- ]);
898
- if (err) {
899
- return res.status(500).send(err);
900
- }
901
- if (panel.deleteCallback) {
902
- try {
903
- await axios_1.default.post(panel.deleteCallback, {
904
- id: req.body.primaryValue,
905
- });
906
- }
907
- catch (e) { }
908
- }
909
- if (panel.deleteCallbackFunction) {
910
- await panel.deleteCallbackFunction({
911
- id: req.body.primaryValue,
912
- deletedRecord,
913
- });
914
- }
915
- res.sendStatus(200);
916
- });
917
- app.post("/deleteRecords", async function (req, res, next) {
918
- const view = req.config.views[req.body.viewIndex];
919
- const placeholders = req.body.primaryValues.map(() => "?").join(", ");
920
- const { err } = await db.query(`DELETE FROM ?? WHERE ?? IN(${placeholders})`, [view.tableName, view.primaryId, ...req.body.primaryValues]);
921
- if (err) {
922
- return res.status(500).send(err);
923
- }
924
- res.sendStatus(200);
925
- });
926
- app.get("/notificationBadges", async function (req, res) {
927
- const notificationBadges = {};
928
- async function checkAndGetNotificationBadge(obj) {
929
- if (obj.notificationBadge) {
930
- const { err, rows } = await db.query(obj.notificationBadge.query);
931
- if (err) {
932
- console.error(err);
933
- }
934
- else if (rows.length > 0 &&
935
- rows[0][obj.notificationBadge.attribute]) {
936
- const notificationBadge = rows[0][obj.notificationBadge.attribute];
937
- if (!obj.notificationBadge.displayCondition ||
938
- obj.notificationBadge.displayCondition(notificationBadge)) {
939
- notificationBadges[obj.__id__] = notificationBadge;
940
- }
941
- }
942
- }
943
- }
944
- for (const view of req.config.views) {
945
- await checkAndGetNotificationBadge(view);
946
- if (view.subviews) {
947
- for (const subview of view.subviews) {
948
- await checkAndGetNotificationBadge(subview);
949
- }
950
- }
951
- }
952
- res.send(notificationBadges);
953
- });
954
- app.post("/duplicateRecord", async function (req, res, next) {
955
- var _a;
956
- const allowedTables = (0, exports.writableTables)(req);
957
- const requestedTables = [
958
- req.body.table,
959
- ...(((_a = req.body.duplicateConfig) === null || _a === void 0 ? void 0 : _a.foreignTables) || []).map((t) => t.table),
960
- ];
961
- if (requestedTables.some((t) => !allowedTables.has(t))) {
962
- return res.sendStatus(403);
963
- }
964
- const primaryId = req.body.duplicateConfig.primaryId;
965
- const { err, rows } = await db.query("SELECT * FROM ?? WHERE ?? = ?", [
966
- req.body.table,
967
- primaryId,
968
- req.body.primaryValue,
969
- ]);
970
- if (err) {
971
- return res.status(500).send(err);
972
- }
973
- const record = rows[0];
974
- const data = {};
975
- for (let field of req.body.duplicateConfig.fields) {
976
- data[field] = record[field];
977
- }
978
- const { err: err2, rows: r } = await db.query("INSERT IGNORE INTO ?? SET ?", [req.body.table, data]);
979
- if (err2) {
980
- return res.status(500).send(err);
981
- }
982
- const newRecordId = r.insertId;
983
- for (let foreignTable of req.body.duplicateConfig.foreignTables) {
984
- const { err, rows } = await db.query("SELECT * FROM ?? WHERE ?? = ?", [
985
- foreignTable.table,
986
- primaryId,
987
- req.body.primaryValue,
988
- ]);
989
- if (err)
990
- console.log(err);
991
- for (let record of rows) {
992
- const data = {};
993
- data[primaryId] = newRecordId;
994
- for (let field of foreignTable.fields) {
995
- data[field] = record[field];
996
- }
997
- await db.query("INSERT IGNORE INTO ?? SET ?", [
998
- foreignTable.table,
999
- data,
1000
- ]);
1001
- }
1002
- }
1003
- res.sendStatus(200);
1004
- });
1005
- app.post("/createRecord", async function (req, res, next) {
1006
- var _a, _b, _c;
1007
- const view = req.config.views[req.body.viewIndex];
1008
- const hasPanel = req.body.panelIndex !== undefined && req.body.panelIndex !== null;
1009
- const panel = hasPanel ? view.recordViewPanels[req.body.panelIndex] : null;
1010
- if (!hasPanel && (0, exports.touchesHiddenColumn)(view, req.body.data)) {
1011
- return res.sendStatus(403);
1012
- }
1013
- try {
1014
- for (let key in req.body.data) {
1015
- if (req.body.data[key] == "NULL" ||
1016
- req.body.data[key] === "Invalid date") {
1017
- req.body.data[key] = null;
1018
- }
1019
- }
1020
- if (panel) {
1021
- req.body.data[panel.createConfig.recordIdKey] = req.body.recordId;
1022
- }
1023
- const primaryColumn = (_b = (_a = (view || panel)) === null || _a === void 0 ? void 0 : _a.columns) === null || _b === void 0 ? void 0 : _b.find((x) => x.name === (view || panel).primaryId);
1024
- if ((primaryColumn === null || primaryColumn === void 0 ? void 0 : primaryColumn.dataType) == "uuid") {
1025
- req.body.data[primaryColumn.name] = (0, uuid_1.v4)();
1026
- }
1027
- const createPayload = JSON.parse(JSON.stringify(req.body.data));
1028
- const columns = panel ? panel.createConfig.columns : view.columns;
1029
- for (let key in createPayload) {
1030
- if (((_c = columns === null || columns === void 0 ? void 0 : columns.find((x) => x.name === key)) === null || _c === void 0 ? void 0 : _c.includedInCreatePayload) ===
1031
- false) {
1032
- delete createPayload[key];
1033
- }
1034
- }
1035
- if (!(0, exports.areSafeColumnNames)(createPayload)) {
1036
- return res.status(400).send({ error: "Invalid column name" });
1037
- }
1038
- const queryExpression = Object.keys(createPayload)
1039
- .map((x) => (0, dbManager_1.quoteIdentifier)(x, db.dbType))
1040
- .join(", ");
1041
- const queryPlaceholders = Object.keys(createPayload)
1042
- .map((x) => "?")
1043
- .join(", ");
1044
- const queryParameters = Object.keys(createPayload).map((x) => createPayload[x]);
1045
- const { err, rows: r } = await db.query(`INSERT INTO ?? (${queryExpression}) VALUES(${queryPlaceholders})`, [panel ? panel.tableName : view.tableName, ...queryParameters]);
1046
- if (err) {
1047
- console.error(err);
1048
- return res.status(500).send({
1049
- err,
1050
- message: err.code === "ER_DUP_ENTRY"
1051
- ? "Cet élément existe déjà."
1052
- : "Une erreur est survenue.",
1053
- });
1054
- }
1055
- if (panel ? panel.createCallback : view.createCallback) {
1056
- try {
1057
- await axios_1.default.post(panel ? panel.createCallback : view.createCallback, {
1058
- id: r.insertId,
1059
- data: req.body.data,
1060
- });
1061
- }
1062
- catch (e) { }
1063
- }
1064
- if (panel ? panel.createCallbackFunction : view.createCallbackFunction) {
1065
- try {
1066
- await (panel ? panel.createCallbackFunction : view.createCallbackFunction)({
1067
- id: r.insertId,
1068
- data: req.body.data,
1069
- });
1070
- }
1071
- catch (callbackErr) {
1072
- console.error(callbackErr);
1073
- }
1074
- }
1075
- res.send({
1076
- id: r.insertId,
1077
- });
1078
- }
1079
- catch (err) {
1080
- console.error(err);
1081
- res.status(500).send({
1082
- err,
1083
- message: "Une erreur est survenue.",
1084
- });
1085
- }
1086
- });
1087
- const CONFIG_USES_CUSTOM_QUERY = collectAllowedQueries(config.views).size > 0;
115
+ app.post("/recordsExport", (0, recordsExport_1.default)(getRecords));
116
+ app.post("/recordsImport", (0, recordsImport_1.default)(db));
117
+ app.post("/subrecordsImport", (0, subrecordsImport_1.default)(db));
118
+ app.get("/record", (0, record_1.default)(db));
119
+ app.post("/updateRecord", (0, updateRecord_1.default)(db));
120
+ app.post("/customAction", (0, customAction_1.default)(db));
121
+ app.post("/deleteRecord", (0, deleteRecord_1.default)(db));
122
+ app.post("/deleteRecordFromPanel", (0, deleteRecordFromPanel_1.default)(db));
123
+ app.post("/deleteRecords", (0, deleteRecords_1.default)(db));
124
+ app.get("/notificationBadges", (0, notificationBadges_1.default)(db));
125
+ app.post("/duplicateRecord", (0, duplicateRecord_1.default)(db));
126
+ app.post("/createRecord", (0, createRecord_1.default)(db));
127
+ const CONFIG_USES_CUSTOM_QUERY = (0, queries_1.collectAllowedQueries)(config.views).size > 0;
1088
128
  if (!CONFIG_USES_CUSTOM_QUERY) {
1089
129
  app.get("/customQuery", (req, res) => res.sendStatus(404));
1090
130
  }
1091
131
  else {
1092
- app.get("/customQuery", async function (req, res, next) {
1093
- const template = typeof req.query.query === "string" ? req.query.query : "";
1094
- const allowed = collectAllowedQueries(req.config.views);
1095
- if (!allowed.has(template.trim())) {
1096
- return res.status(403).send({ error: "Query not allowed" });
1097
- }
1098
- if (!/^\s*\(?\s*(select|with)\b/i.test(template) || /;/.test(template)) {
1099
- return res
1100
- .status(400)
1101
- .send({ error: "Only read-only queries are allowed" });
1102
- }
1103
- const placeholderCount = (template.match(/\?/g) || []).length;
1104
- const params = new Array(placeholderCount).fill(req.query.primaryValue);
1105
- const { err, rows } = await db.query(template, params);
1106
- if (err) {
1107
- return res.status(500).send(err);
1108
- }
1109
- if (req.query.viewIndex && req.query.panelIndex) {
1110
- const panel = req.config.views[req.query.viewIndex].recordViewPanels[req.query.panelIndex];
1111
- if (panel.formatValue) {
1112
- for (const row of rows) {
1113
- for (const key in panel.formatValue) {
1114
- row[key] = await panel.formatValue[key](row);
1115
- }
1116
- }
1117
- }
1118
- }
1119
- res.send(rows);
1120
- });
132
+ app.get("/customQuery", (0, customQuery_1.default)(db));
1121
133
  }
1122
- function uploadFile(column, fileParamName, req, res) {
1123
- if (column.s3Config || column.gcpConfig) {
1124
- const form = new multiparty.Form();
1125
- form.parse(req, async function (err, fields, files) {
1126
- var _a;
1127
- if (err) {
1128
- return res.status(500).send(err);
1129
- }
1130
- const originalFilename = files[fileParamName][0].originalFilename;
1131
- const contentType = mime.getType(originalFilename) || "application/octet-stream";
1132
- const extension = originalFilename.match(/(?:\.([^.]+))?$/)[1];
1133
- let aspectRatio = null;
1134
- if (["png", "jpeg", "jpg", "gif"].includes(extension)) {
1135
- try {
1136
- const dimensions = await (0, imageDimensions_1.getImageDimensions)(files[fileParamName][0].path);
1137
- if (dimensions) {
1138
- aspectRatio = dimensions.height / dimensions.width;
1139
- }
1140
- }
1141
- catch (_b) {
1142
- }
1143
- }
1144
- const originalFilenameWithoutExtension = originalFilename.replace("." + extension, "");
1145
- if (column.gcpConfig) {
1146
- const gcpConfig = column.gcpConfig;
1147
- const path = (gcpConfig.subfolder ? gcpConfig.subfolder + "/" : "") +
1148
- originalFilenameWithoutExtension +
1149
- "-" +
1150
- Math.random().toString().substr(2) +
1151
- "." +
1152
- extension;
1153
- const storage = new storage_1.Storage();
1154
- const bucketName = gcpConfig.bucket;
1155
- storage
1156
- .bucket(bucketName)
1157
- .upload(files[fileParamName][0].path, {
1158
- destination: path,
1159
- })
1160
- .then(() => {
1161
- res.status(200).send({
1162
- path: gcpConfig.pathTransform
1163
- ? gcpConfig.pathTransform(path)
1164
- : path,
1165
- aspectRatio,
1166
- originalFilename,
1167
- });
1168
- })
1169
- .catch((e) => {
1170
- res.status(500).send(e);
1171
- });
1172
- }
1173
- else {
1174
- const s3Config = column.s3Config;
1175
- const path = (s3Config.subfolder ? s3Config.subfolder + "/" : "") +
1176
- originalFilenameWithoutExtension +
1177
- "-" +
1178
- Math.random().toString().substr(2) +
1179
- "." +
1180
- extension;
1181
- const rawHost = String(s3Config.host || "");
1182
- const endpoint = /^https?:\/\//i.test(rawHost)
1183
- ? rawHost
1184
- : `https://${rawHost}`;
1185
- const s3 = new client_s3_1.S3Client(Object.assign(Object.assign({ endpoint, region: s3Config.region }, (s3Config.accessKeyId && {
1186
- credentials: {
1187
- accessKeyId: s3Config.accessKeyId,
1188
- secretAccessKey: (_a = s3Config.secretAccessKey) !== null && _a !== void 0 ? _a : "",
1189
- },
1190
- })), { forcePathStyle: false }));
1191
- if (s3Config.signedUrlNeeded) {
1192
- (0, s3_request_presigner_1.getSignedUrl)(s3, new client_s3_1.PutObjectCommand({
1193
- Bucket: s3Config.bucket,
1194
- Key: path,
1195
- ContentType: contentType,
1196
- }), { expiresIn: 150 })
1197
- .then((signedUrl) => axios_1.default.put(signedUrl, fs.readFileSync(files[fileParamName][0].path), {
1198
- maxContentLength: 100000000000,
1199
- maxBodyLength: 100000000000,
1200
- headers: {
1201
- "Content-Type": contentType,
1202
- },
1203
- }))
1204
- .then(() => {
1205
- res.status(200).send({
1206
- path: s3Config.pathTransform
1207
- ? s3Config.pathTransform(path)
1208
- : path,
1209
- aspectRatio,
1210
- originalFilename,
1211
- });
1212
- })
1213
- .catch((e) => {
1214
- res.status(500).send(e);
1215
- });
1216
- }
1217
- else {
1218
- s3.send(new client_s3_1.PutObjectCommand({
1219
- Body: fs.readFileSync(files[fileParamName][0].path),
1220
- Bucket: s3Config.bucket,
1221
- ContentType: contentType,
1222
- ACL: "public-read",
1223
- Key: path,
1224
- }))
1225
- .then(() => {
1226
- res.send({
1227
- url: `https://${s3Config.host}/${s3Config.bucket}/${path}`,
1228
- path: s3Config.pathTransform
1229
- ? s3Config.pathTransform(path)
1230
- : path,
1231
- aspectRatio,
1232
- originalFilename,
1233
- });
1234
- })
1235
- .catch((err) => res.status(500).send(err));
1236
- }
1237
- }
1238
- });
1239
- }
1240
- else if (column.sftpConfig) {
1241
- if (!column.publicPath) {
1242
- return res
1243
- .status(500)
1244
- .send("You need to pass publicPath parameter when using sftpConfig");
1245
- }
1246
- const form = new multiparty.Form();
1247
- form.parse(req, function (err, fields, files) {
1248
- if (err) {
1249
- return res.status(500).send(err);
1250
- }
1251
- const pathSplitted = files[fileParamName][0].path.split(/[\/\\]+/);
1252
- const filename = pathSplitted[pathSplitted.length - 1];
1253
- (async () => {
1254
- const sftp = new SftpClient();
1255
- await sftp.connect({
1256
- host: column.sftpConfig.host,
1257
- port: 22,
1258
- username: column.sftpConfig.user,
1259
- password: column.sftpConfig.password,
1260
- });
1261
- await sftp.fastPut(files[fileParamName][0].path, column.publicPath +
1262
- (column.subdirectory ? "/" + column.subdirectory : "") +
1263
- "/" +
1264
- filename);
1265
- await sftp.end();
1266
- res.send({
1267
- path: filename,
1268
- originalFilename: files[fileParamName][0].originalFilename,
1269
- });
1270
- fs.unlinkSync(files[fileParamName][0].path);
1271
- })();
1272
- });
1273
- }
1274
- else {
1275
- const form = new multiparty.Form({
1276
- uploadDir: column.publicPath + column.subdirectory,
1277
- });
1278
- form.parse(req, function (err, fields, files) {
1279
- if (err) {
1280
- return res.status(500).send(err);
1281
- }
1282
- res.send({
1283
- path: files[fileParamName][0].path.replace(column.publicPath, ""),
1284
- originalFilename: files[fileParamName][0].originalFilename,
1285
- });
1286
- });
1287
- }
1288
- }
1289
- app.post("/uploadFileFromBetterRichTextInput", async function (req, res, next) {
1290
- var _a;
1291
- const role = (0, exports.roleOf)(req);
1292
- const { viewIndex, columnId } = req.query;
1293
- if (typeof viewIndex !== "string" ||
1294
- !/^\d+$/.test(viewIndex) ||
1295
- typeof columnId !== "string") {
1296
- return res.sendStatus(403);
1297
- }
1298
- const view = req.config.views[viewIndex];
1299
- if (!view || !(0, exports.canWriteView)(view, role)) {
1300
- return res.sendStatus(403);
1301
- }
1302
- const column = [
1303
- ...(view.columns || []),
1304
- ...(((_a = view.recordViewPanels) === null || _a === void 0 ? void 0 : _a.flatMap((panel) => { var _a; return ((_a = panel.createConfig) === null || _a === void 0 ? void 0 : _a.columns) || []; })) || []),
1305
- ].find((column) => column.__id__ === columnId);
1306
- if (!column || (column.roles && !column.roles.includes(role))) {
1307
- return res.sendStatus(403);
1308
- }
1309
- if (column.dataType !== "betterRichText" || !column.fileUploadProperties) {
1310
- return res.status(400).send({ error: "Invalid rich-text upload column" });
1311
- }
1312
- uploadFile(column.fileUploadProperties, "upload", req, res);
1313
- });
1314
- app.post("/uploadFile", async function (req, res, next) {
1315
- var _a, _b, _c;
1316
- const view = req.config.views[req.query.viewIndex];
1317
- const column = [
1318
- ...view.columns,
1319
- ...(((_c = (_b = (_a = view.recordViewPanels) === null || _a === void 0 ? void 0 : _a.map((x) => { var _a; return (_a = x === null || x === void 0 ? void 0 : x.createConfig) === null || _a === void 0 ? void 0 : _a.columns; })) === null || _b === void 0 ? void 0 : _b.filter((x) => x)) === null || _c === void 0 ? void 0 : _c.flat()) || []),
1320
- ].find((x) => x.__id__ == req.query.columnId);
1321
- uploadFile(column, "file", req, res);
1322
- });
1323
- app.get("/searchCompanies", async (req, res) => {
1324
- const processedQuery = req.query.query.replaceAll(" ", "-");
1325
- try {
1326
- const response = await axios_1.default.get(`https://public.opendatasoft.com/api/explore/v2.1/catalog/datasets/economicref-france-sirene-v3/records`, {
1327
- params: {
1328
- where: `denominationunitelegale LIKE '${processedQuery}*' OR siret LIKE '${processedQuery}*'`,
1329
- limit: 100,
1330
- },
1331
- });
1332
- const results = response.data.results
1333
- .filter((etablissement) => etablissement.etatadministratifetablissement === "Actif")
1334
- .map((etablissement) => ({
1335
- id: Math.random().toString().slice(2),
1336
- companyName: etablissement.denominationunitelegale,
1337
- siret: etablissement.siret,
1338
- siren: etablissement.siren,
1339
- address: `${etablissement.numerovoieetablissement || ""} ${etablissement.typevoieetablissement || ""} ${etablissement.libellevoieetablissement || ""}`,
1340
- city: etablissement.libellecommuneetablissement,
1341
- zipCode: etablissement.codepostaletablissement,
1342
- activityNumber: etablissement.activiteprincipaleunitelegale,
1343
- }))
1344
- .slice(0, 30);
1345
- res.send(results);
1346
- }
1347
- catch (e) {
1348
- res.send([]);
1349
- }
1350
- });
134
+ app.post("/uploadFileFromBetterRichTextInput", (0, uploadFileFromBetterRichTextInput_1.default)());
135
+ app.post("/uploadFile", (0, uploadFile_1.default)());
136
+ app.get("/searchCompanies", (0, searchCompanies_1.default)());
1351
137
  return app;
1352
138
  };
1353
- function collectAllowedQueries(node, acc = new Set()) {
1354
- if (!node || typeof node !== "object")
1355
- return acc;
1356
- if (Array.isArray(node)) {
1357
- for (const item of node)
1358
- collectAllowedQueries(item, acc);
1359
- return acc;
1360
- }
1361
- for (const key of Object.keys(node)) {
1362
- const value = node[key];
1363
- if (typeof value === "string" && (key === "query" || /Query$/.test(key))) {
1364
- acc.add(value.trim());
1365
- }
1366
- else if (value && typeof value === "object") {
1367
- collectAllowedQueries(value, acc);
1368
- }
1369
- }
1370
- return acc;
1371
- }
1372
- async function enrichConfig(config, db) {
1373
- var _a, _b;
1374
- const { rows: info, err } = await db.query("SELECT * FROM information_schema.columns WHERE table_schema = ?", [((_a = config.mysql) === null || _a === void 0 ? void 0 : _a.database) || ((_b = config.postgresql) === null || _b === void 0 ? void 0 : _b.database)]);
1375
- if (err) {
1376
- console.error(err);
1377
- return;
1378
- }
1379
- for (const view of config.views) {
1380
- if (view.type == "table") {
1381
- const tableName = view.tableName;
1382
- for (const infoEl of info) {
1383
- if (infoEl.TABLE_NAME == tableName && infoEl.COLUMN_KEY == "PRI") {
1384
- view.primaryId = infoEl.COLUMN_NAME;
1385
- }
1386
- }
1387
- for (const column of view.columns) {
1388
- enrichColumn(column, tableName, info);
1389
- }
1390
- if (view.recordViewPanels) {
1391
- for (const panel of view.recordViewPanels) {
1392
- if (panel.createConfig) {
1393
- for (const column of panel.createConfig.columns) {
1394
- enrichColumn(column, tableName, info);
1395
- }
1396
- }
1397
- if (!panel.__id__) {
1398
- panel.__id__ = generateUniqueIdForObject(panel);
1399
- }
1400
- }
1401
- }
1402
- }
1403
- if (view.subviews) {
1404
- for (const subview of view.subviews) {
1405
- if (!subview.__id__) {
1406
- subview.__id__ = generateUniqueIdForObject(subview);
1407
- }
1408
- }
1409
- }
1410
- if (!view.__id__) {
1411
- view.__id__ = generateUniqueIdForObject(view);
1412
- }
1413
- }
1414
- config.enriched = true;
1415
- }
1416
- function enrichColumn(column, tableName, info) {
1417
- var _a, _b, _c, _d;
1418
- if (!column.__id__) {
1419
- column.__id__ = generateUniqueIdForObject(column);
1420
- }
1421
- const infoEl = info.find((x) => x.TABLE_NAME == tableName && x.COLUMN_NAME == column.name);
1422
- if ((infoEl === null || infoEl === void 0 ? void 0 : infoEl.IS_NULLABLE) == "NO" &&
1423
- (infoEl === null || infoEl === void 0 ? void 0 : infoEl.DATA_TYPE) != "text" &&
1424
- column.required !== true &&
1425
- column.required !== false) {
1426
- column.required = true;
1427
- }
1428
- if (!column.dataType && infoEl) {
1429
- column.dataType = infoEl.DATA_TYPE;
1430
- if (column.dataType == "enum") {
1431
- column.dataType = "select";
1432
- column.options = JSON.parse(infoEl.COLUMN_TYPE.replace("enum(", "[")
1433
- .replace(")", "]")
1434
- .replace(/'/g, '"'));
1435
- }
1436
- }
1437
- if (column.dataType == "richText") {
1438
- column.name = column.contentField;
1439
- }
1440
- if (column.dataType == "file" && (column.s3Config || column.gcpConfig)) {
1441
- const host = ((_a = column.s3Config) === null || _a === void 0 ? void 0 : _a.host) || ((_b = column.gcpConfig) === null || _b === void 0 ? void 0 : _b.host);
1442
- const bucket = ((_c = column.s3Config) === null || _c === void 0 ? void 0 : _c.bucket) || ((_d = column.gcpConfig) === null || _d === void 0 ? void 0 : _d.bucket);
1443
- column.baseUrl = `https://${host}/${bucket}/`;
1444
- }
1445
- }
1446
139
  //# sourceMappingURL=api.js.map