adminforth 1.4.3-next.20 → 1.4.3-next.21

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 (146) hide show
  1. package/dist/adminforth/auth.d.ts +31 -0
  2. package/dist/adminforth/auth.d.ts.map +1 -0
  3. package/dist/adminforth/auth.js +119 -0
  4. package/dist/adminforth/auth.js.map +1 -0
  5. package/dist/adminforth/basePlugin.d.ts +23 -0
  6. package/dist/adminforth/basePlugin.d.ts.map +1 -0
  7. package/dist/adminforth/basePlugin.js +51 -0
  8. package/dist/adminforth/basePlugin.js.map +1 -0
  9. package/dist/adminforth/dataConnectors/baseConnector.d.ts +95 -0
  10. package/dist/adminforth/dataConnectors/baseConnector.d.ts.map +1 -0
  11. package/dist/adminforth/dataConnectors/baseConnector.js +178 -0
  12. package/dist/adminforth/dataConnectors/baseConnector.js.map +1 -0
  13. package/dist/adminforth/dataConnectors/clickhouse.d.ts +93 -0
  14. package/dist/adminforth/dataConnectors/clickhouse.d.ts.map +1 -0
  15. package/dist/adminforth/dataConnectors/clickhouse.js +297 -0
  16. package/dist/adminforth/dataConnectors/clickhouse.js.map +1 -0
  17. package/dist/adminforth/dataConnectors/mongo.d.ts +94 -0
  18. package/dist/adminforth/dataConnectors/mongo.d.ts.map +1 -0
  19. package/dist/adminforth/dataConnectors/mongo.js +168 -0
  20. package/dist/adminforth/dataConnectors/mongo.js.map +1 -0
  21. package/dist/adminforth/dataConnectors/postgres.d.ts +72 -0
  22. package/dist/adminforth/dataConnectors/postgres.d.ts.map +1 -0
  23. package/dist/adminforth/dataConnectors/postgres.js +298 -0
  24. package/dist/adminforth/dataConnectors/postgres.js.map +1 -0
  25. package/dist/adminforth/dataConnectors/sqlite.d.ts +67 -0
  26. package/dist/adminforth/dataConnectors/sqlite.d.ts.map +1 -0
  27. package/dist/adminforth/dataConnectors/sqlite.js +251 -0
  28. package/dist/adminforth/dataConnectors/sqlite.js.map +1 -0
  29. package/dist/adminforth/index.d.ts +94 -0
  30. package/dist/adminforth/index.d.ts.map +1 -0
  31. package/dist/adminforth/index.js +357 -0
  32. package/dist/adminforth/index.js.map +1 -0
  33. package/dist/adminforth/modules/codeInjector.d.ts +38 -0
  34. package/dist/adminforth/modules/codeInjector.d.ts.map +1 -0
  35. package/dist/adminforth/modules/codeInjector.js +673 -0
  36. package/dist/adminforth/modules/codeInjector.js.map +1 -0
  37. package/dist/adminforth/modules/configValidator.d.ts +13 -0
  38. package/dist/adminforth/modules/configValidator.d.ts.map +1 -0
  39. package/dist/adminforth/modules/configValidator.js +511 -0
  40. package/dist/adminforth/modules/configValidator.js.map +1 -0
  41. package/dist/adminforth/modules/operationalResource.d.ts +17 -0
  42. package/dist/adminforth/modules/operationalResource.d.ts.map +1 -0
  43. package/dist/adminforth/modules/operationalResource.js +75 -0
  44. package/dist/adminforth/modules/operationalResource.js.map +1 -0
  45. package/dist/adminforth/modules/restApi.d.ts +11 -0
  46. package/dist/adminforth/modules/restApi.d.ts.map +1 -0
  47. package/dist/adminforth/modules/restApi.js +657 -0
  48. package/dist/adminforth/modules/restApi.js.map +1 -0
  49. package/dist/adminforth/modules/styleGenerator.d.ts +9 -0
  50. package/dist/adminforth/modules/styleGenerator.d.ts.map +1 -0
  51. package/dist/adminforth/modules/styleGenerator.js +47 -0
  52. package/dist/adminforth/modules/styleGenerator.js.map +1 -0
  53. package/dist/adminforth/modules/styles.d.ts +96 -0
  54. package/dist/adminforth/modules/styles.d.ts.map +1 -0
  55. package/dist/adminforth/modules/styles.js +105 -0
  56. package/dist/adminforth/modules/styles.js.map +1 -0
  57. package/dist/adminforth/modules/utils.d.ts +39 -0
  58. package/dist/adminforth/modules/utils.d.ts.map +1 -0
  59. package/dist/adminforth/modules/utils.js +421 -0
  60. package/dist/adminforth/modules/utils.js.map +1 -0
  61. package/dist/adminforth/plugins/audit-log/index.d.ts +25 -0
  62. package/dist/adminforth/plugins/audit-log/index.d.ts.map +1 -0
  63. package/dist/adminforth/plugins/audit-log/index.js +129 -0
  64. package/dist/adminforth/plugins/audit-log/index.js.map +1 -0
  65. package/dist/adminforth/plugins/audit-log/types.d.ts +35 -0
  66. package/dist/adminforth/plugins/audit-log/types.d.ts.map +1 -0
  67. package/dist/adminforth/plugins/audit-log/types.js +2 -0
  68. package/dist/adminforth/plugins/audit-log/types.js.map +1 -0
  69. package/dist/adminforth/plugins/chat-gpt/index.d.ts +14 -0
  70. package/dist/adminforth/plugins/chat-gpt/index.d.ts.map +1 -0
  71. package/dist/adminforth/plugins/chat-gpt/index.js +147 -0
  72. package/dist/adminforth/plugins/chat-gpt/index.js.map +1 -0
  73. package/dist/adminforth/plugins/chat-gpt/types.d.ts +82 -0
  74. package/dist/adminforth/plugins/chat-gpt/types.d.ts.map +1 -0
  75. package/dist/adminforth/plugins/chat-gpt/types.js +2 -0
  76. package/dist/adminforth/plugins/chat-gpt/types.js.map +1 -0
  77. package/dist/adminforth/plugins/email-password-reset/index.d.ts +15 -0
  78. package/dist/adminforth/plugins/email-password-reset/index.d.ts.map +1 -0
  79. package/dist/adminforth/plugins/email-password-reset/index.js +176 -0
  80. package/dist/adminforth/plugins/email-password-reset/index.js.map +1 -0
  81. package/dist/adminforth/plugins/email-password-reset/types.d.ts +28 -0
  82. package/dist/adminforth/plugins/email-password-reset/types.d.ts.map +1 -0
  83. package/dist/adminforth/plugins/email-password-reset/types.js +2 -0
  84. package/dist/adminforth/plugins/email-password-reset/types.js.map +1 -0
  85. package/dist/adminforth/plugins/foreign-inline-list/index.d.ts +13 -0
  86. package/dist/adminforth/plugins/foreign-inline-list/index.d.ts.map +1 -0
  87. package/dist/adminforth/plugins/foreign-inline-list/index.js +56 -0
  88. package/dist/adminforth/plugins/foreign-inline-list/index.js.map +1 -0
  89. package/dist/adminforth/plugins/foreign-inline-list/types.d.ts +19 -0
  90. package/dist/adminforth/plugins/foreign-inline-list/types.d.ts.map +1 -0
  91. package/dist/adminforth/plugins/foreign-inline-list/types.js +2 -0
  92. package/dist/adminforth/plugins/foreign-inline-list/types.js.map +1 -0
  93. package/dist/adminforth/plugins/import-export/index.d.ts +15 -0
  94. package/dist/adminforth/plugins/import-export/index.d.ts.map +1 -0
  95. package/dist/adminforth/plugins/import-export/index.js +127 -0
  96. package/dist/adminforth/plugins/import-export/index.js.map +1 -0
  97. package/dist/adminforth/plugins/import-export/types.d.ts +3 -0
  98. package/dist/adminforth/plugins/import-export/types.d.ts.map +1 -0
  99. package/dist/adminforth/plugins/import-export/types.js +2 -0
  100. package/dist/adminforth/plugins/import-export/types.js.map +1 -0
  101. package/dist/adminforth/plugins/rich-editor/index.d.ts +17 -0
  102. package/dist/adminforth/plugins/rich-editor/index.d.ts.map +1 -0
  103. package/dist/adminforth/plugins/rich-editor/index.js +262 -0
  104. package/dist/adminforth/plugins/rich-editor/index.js.map +1 -0
  105. package/dist/adminforth/plugins/rich-editor/types.d.ts +153 -0
  106. package/dist/adminforth/plugins/rich-editor/types.d.ts.map +1 -0
  107. package/dist/adminforth/plugins/rich-editor/types.js +16 -0
  108. package/dist/adminforth/plugins/rich-editor/types.js.map +1 -0
  109. package/dist/adminforth/plugins/two-factors-auth/index.d.ts +16 -0
  110. package/dist/adminforth/plugins/two-factors-auth/index.d.ts.map +1 -0
  111. package/dist/adminforth/plugins/two-factors-auth/index.js +134 -0
  112. package/dist/adminforth/plugins/two-factors-auth/index.js.map +1 -0
  113. package/dist/adminforth/plugins/two-factors-auth/types.d.ts +18 -0
  114. package/dist/adminforth/plugins/two-factors-auth/types.d.ts.map +1 -0
  115. package/dist/adminforth/plugins/two-factors-auth/types.js +2 -0
  116. package/dist/adminforth/plugins/two-factors-auth/types.js.map +1 -0
  117. package/dist/adminforth/plugins/upload/index.d.ts +14 -0
  118. package/dist/adminforth/plugins/upload/index.d.ts.map +1 -0
  119. package/dist/adminforth/plugins/upload/index.js +450 -0
  120. package/dist/adminforth/plugins/upload/index.js.map +1 -0
  121. package/dist/adminforth/plugins/upload/types.d.ts +132 -0
  122. package/dist/adminforth/plugins/upload/types.d.ts.map +1 -0
  123. package/dist/adminforth/plugins/upload/types.js +2 -0
  124. package/dist/adminforth/plugins/upload/types.js.map +1 -0
  125. package/dist/adminforth/servers/express.d.ts +18 -0
  126. package/dist/adminforth/servers/express.d.ts.map +1 -0
  127. package/dist/adminforth/servers/express.js +238 -0
  128. package/dist/adminforth/servers/express.js.map +1 -0
  129. package/dist/adminforth/types/Back.d.ts +1103 -0
  130. package/dist/adminforth/types/Back.d.ts.map +1 -0
  131. package/dist/adminforth/types/Back.js +86 -0
  132. package/dist/adminforth/types/Back.js.map +1 -0
  133. package/dist/adminforth/types/Common.d.ts +616 -0
  134. package/dist/adminforth/types/Common.d.ts.map +1 -0
  135. package/dist/adminforth/types/Common.js +65 -0
  136. package/dist/adminforth/types/Common.js.map +1 -0
  137. package/dist/adminforth/types/FrontendAPI.d.ts +134 -0
  138. package/dist/adminforth/types/FrontendAPI.d.ts.map +1 -0
  139. package/dist/adminforth/types/FrontendAPI.js +8 -0
  140. package/dist/adminforth/types/FrontendAPI.js.map +1 -0
  141. package/dist/dev-demo/index.d.ts +3 -0
  142. package/dist/dev-demo/index.d.ts.map +1 -0
  143. package/dist/dev-demo/index.js +1052 -0
  144. package/dist/dev-demo/index.js.map +1 -0
  145. package/dist/spa/src/types/Back.ts +25 -5
  146. package/package.json +1 -1
@@ -0,0 +1,657 @@
1
+ import { ADMINFORTH_VERSION, listify } from './utils.js';
2
+ import AdminForthAuth from "../auth.js";
3
+ import { ActionCheckSource, AdminForthDataTypes, AdminForthFilterOperators, AdminForthResourcePages, AllowedActionsEnum } from "../types/Common.js";
4
+ export async function interpretResource(adminUser, resource, meta, source) {
5
+ var _a;
6
+ // if (process.env.HEAVY_DEBUG) {
7
+ // console.log('🪲Interpreting resource', resource.resourceId, source, 'adminUser', adminUser);
8
+ // }
9
+ const allowedActions = {};
10
+ await Promise.all(Object.entries(((_a = resource.options) === null || _a === void 0 ? void 0 : _a.allowedActions) || {}).map(async ([key, value]) => {
11
+ if (process.env.HEAVY_DEBUG) {
12
+ console.log(`🪲🚥check allowed ${key}, ${value}`);
13
+ }
14
+ // if callable then call
15
+ if (typeof value === 'function') {
16
+ allowedActions[key] = await value({ adminUser, resource, meta, source });
17
+ }
18
+ else {
19
+ allowedActions[key] = value;
20
+ }
21
+ }));
22
+ return { allowedActions };
23
+ }
24
+ export default class AdminForthRestAPI {
25
+ constructor(adminforth) {
26
+ this.adminforth = adminforth;
27
+ }
28
+ registerEndpoints(server) {
29
+ server.endpoint({
30
+ noAuth: true,
31
+ method: 'POST',
32
+ path: '/login',
33
+ handler: async ({ body, response }) => {
34
+ var _a, _b, _c, _d;
35
+ const INVALID_MESSAGE = 'Invalid Username or Password';
36
+ const { username, password, rememberMe } = body;
37
+ let adminUser;
38
+ let toReturn = { ok: true, allowedLogin: true };
39
+ // get resource from db
40
+ if (!this.adminforth.config.auth) {
41
+ throw new Error('No config.auth defined we need it to find user, please follow the docs');
42
+ }
43
+ const userResource = this.adminforth.config.resources.find((res) => res.resourceId === this.adminforth.config.auth.usersResourceId);
44
+ // if there is no passwordHashField, in columns, add it, with backendOnly and showIn: []
45
+ if (!userResource.dataSourceColumns.find((col) => col.name === this.adminforth.config.auth.passwordHashField)) {
46
+ userResource.dataSourceColumns.push({
47
+ name: this.adminforth.config.auth.passwordHashField,
48
+ backendOnly: true,
49
+ showIn: [],
50
+ type: AdminForthDataTypes.STRING,
51
+ });
52
+ console.log('Adding passwordHashField to userResource', userResource);
53
+ }
54
+ const userRecord = (_a = (await this.adminforth.connectors[userResource.dataSource].getData({
55
+ resource: userResource,
56
+ filters: [
57
+ { field: this.adminforth.config.auth.usernameField, operator: AdminForthFilterOperators.EQ, value: username },
58
+ ],
59
+ limit: 1,
60
+ offset: 0,
61
+ sort: [],
62
+ })).data) === null || _a === void 0 ? void 0 : _a[0];
63
+ if (!userRecord) {
64
+ return { error: INVALID_MESSAGE };
65
+ }
66
+ const passwordHash = userRecord[this.adminforth.config.auth.passwordHashField];
67
+ const valid = await AdminForthAuth.verifyPassword(password, passwordHash);
68
+ if (valid) {
69
+ adminUser = {
70
+ dbUser: userRecord,
71
+ pk: userRecord[userResource.columns.find((col) => col.primaryKey).name],
72
+ username,
73
+ };
74
+ const beforeLoginConfirmation = this.adminforth.config.auth.beforeLoginConfirmation;
75
+ if (beforeLoginConfirmation === null || beforeLoginConfirmation === void 0 ? void 0 : beforeLoginConfirmation.length) {
76
+ for (const hook of beforeLoginConfirmation) {
77
+ const resp = await hook({
78
+ adminUser,
79
+ response,
80
+ adminforth: this.adminforth,
81
+ });
82
+ if ((_b = resp === null || resp === void 0 ? void 0 : resp.body) === null || _b === void 0 ? void 0 : _b.redirectTo) {
83
+ toReturn = { ok: resp.ok, redirectTo: (_c = resp === null || resp === void 0 ? void 0 : resp.body) === null || _c === void 0 ? void 0 : _c.redirectTo, allowedLogin: (_d = resp === null || resp === void 0 ? void 0 : resp.body) === null || _d === void 0 ? void 0 : _d.allowedLogin };
84
+ break;
85
+ }
86
+ }
87
+ }
88
+ if (toReturn.allowedLogin) {
89
+ const expireInDays = rememberMe && this.adminforth.config.auth.rememberMeDays;
90
+ this.adminforth.auth.setAuthCookie({
91
+ expireInDays,
92
+ response,
93
+ username,
94
+ pk: userRecord[userResource.columns.find((col) => col.primaryKey).name]
95
+ });
96
+ }
97
+ }
98
+ else {
99
+ return { error: INVALID_MESSAGE };
100
+ }
101
+ return toReturn;
102
+ }
103
+ });
104
+ server.endpoint({
105
+ method: 'POST',
106
+ path: '/check_auth',
107
+ handler: async ({ adminUser }) => {
108
+ return { ok: true };
109
+ },
110
+ });
111
+ server.endpoint({
112
+ noAuth: true,
113
+ method: 'POST',
114
+ path: '/logout',
115
+ handler: async ({ response }) => {
116
+ this.adminforth.auth.removeAuthCookie(response);
117
+ return { ok: true };
118
+ },
119
+ });
120
+ server.endpoint({
121
+ noAuth: true,
122
+ method: 'GET',
123
+ path: '/get_public_config',
124
+ handler: async ({ body }) => {
125
+ // TODO we need to remove this method and make get_config to return public and private parts for logged in user and only public for not logged in
126
+ var _a;
127
+ // find resource
128
+ if (!this.adminforth.config.auth) {
129
+ throw new Error('No config.auth defined');
130
+ }
131
+ const usernameField = this.adminforth.config.auth.usernameField;
132
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId === this.adminforth.config.auth.usersResourceId);
133
+ const usernameColumn = resource.columns.find((col) => col.name === usernameField);
134
+ return {
135
+ brandName: this.adminforth.config.customization.brandName,
136
+ usernameFieldName: usernameColumn.label,
137
+ loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
138
+ loginBackgroundPosition: this.adminforth.config.auth.loginBackgroundPosition,
139
+ title: (_a = this.adminforth.config.customization) === null || _a === void 0 ? void 0 : _a.title,
140
+ demoCredentials: this.adminforth.config.auth.demoCredentials,
141
+ loginPromptHTML: this.adminforth.config.auth.loginPromptHTML,
142
+ loginPageInjections: this.adminforth.config.customization.loginPageInjections,
143
+ rememberMeDays: this.adminforth.config.auth.rememberMeDays,
144
+ };
145
+ },
146
+ });
147
+ server.endpoint({
148
+ method: 'GET',
149
+ path: '/get_base_config',
150
+ handler: async ({ input, adminUser, cookies }) => {
151
+ var _a, _b, _c, _d, _e, _f;
152
+ let username = '';
153
+ let userFullName = '';
154
+ // find resource
155
+ if (!this.adminforth.config.auth) {
156
+ throw new Error('No config.auth defined');
157
+ }
158
+ const dbUser = adminUser.dbUser;
159
+ username = dbUser[this.adminforth.config.auth.usernameField];
160
+ userFullName = dbUser[this.adminforth.config.auth.userFullNameField];
161
+ const userResource = this.adminforth.config.resources.find((res) => res.resourceId === this.adminforth.config.auth.usersResourceId);
162
+ const usernameField = this.adminforth.config.auth.usernameField;
163
+ const usernameColumn = userResource.columns.find((col) => col.name === usernameField);
164
+ const userPk = dbUser[userResource.columns.find((col) => col.primaryKey).name];
165
+ const userData = {
166
+ [this.adminforth.config.auth.usernameField]: username,
167
+ [this.adminforth.config.auth.userFullNameField]: userFullName,
168
+ pk: userPk,
169
+ };
170
+ const checkIsMenuItemVisible = (menuItem) => {
171
+ if (typeof menuItem.visible === 'function') {
172
+ const toReturn = menuItem.visible(adminUser);
173
+ if (typeof toReturn !== 'boolean') {
174
+ throw new Error(`'visible' function of ${menuItem.label || menuItem.type} must return boolean value`);
175
+ }
176
+ return toReturn;
177
+ }
178
+ };
179
+ async function processMenuItem(menuItem) {
180
+ if (menuItem.badge) {
181
+ if (typeof menuItem.badge === 'function') {
182
+ menuItem.badge = await menuItem.badge(adminUser);
183
+ }
184
+ }
185
+ }
186
+ let newMenu = [];
187
+ for (let menuItem of this.adminforth.config.menu) {
188
+ let newMenuItem = Object.assign({}, menuItem);
189
+ if (menuItem.visible) {
190
+ if (!checkIsMenuItemVisible(menuItem)) {
191
+ continue;
192
+ }
193
+ }
194
+ if (menuItem.children) {
195
+ let newChildren = [];
196
+ for (let child of menuItem.children) {
197
+ let newChild = Object.assign({}, child);
198
+ if (child.visible) {
199
+ if (!checkIsMenuItemVisible(child)) {
200
+ continue;
201
+ }
202
+ }
203
+ await processMenuItem(newChild);
204
+ newChildren.push(newChild);
205
+ }
206
+ newMenuItem = Object.assign(Object.assign({}, newMenuItem), { children: newChildren });
207
+ }
208
+ await processMenuItem(newMenuItem);
209
+ newMenu.push(newMenuItem);
210
+ }
211
+ const announcementBadge = (_b = (_a = this.adminforth.config.customization).announcementBadge) === null || _b === void 0 ? void 0 : _b.call(_a, adminUser);
212
+ const publicPart = {
213
+ brandName: this.adminforth.config.customization.brandName,
214
+ usernameFieldName: usernameColumn.label,
215
+ loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
216
+ loginBackgroundPosition: this.adminforth.config.auth.loginBackgroundPosition,
217
+ title: (_c = this.adminforth.config.customization) === null || _c === void 0 ? void 0 : _c.title,
218
+ demoCredentials: this.adminforth.config.auth.demoCredentials,
219
+ loginPromptHTML: this.adminforth.config.auth.loginPromptHTML,
220
+ loginPageInjections: this.adminforth.config.customization.loginPageInjections,
221
+ rememberMeDays: this.adminforth.config.auth.rememberMeDays,
222
+ };
223
+ const loggedInPart = {
224
+ showBrandNameInSidebar: this.adminforth.config.customization.showBrandNameInSidebar,
225
+ brandLogo: this.adminforth.config.customization.brandLogo,
226
+ datesFormat: this.adminforth.config.customization.datesFormat,
227
+ timeFormat: this.adminforth.config.customization.timeFormat,
228
+ deleteConfirmation: this.adminforth.config.deleteConfirmation,
229
+ auth: this.adminforth.config.auth,
230
+ usernameField: this.adminforth.config.auth.usernameField,
231
+ title: (_d = this.adminforth.config.customization) === null || _d === void 0 ? void 0 : _d.title,
232
+ emptyFieldPlaceholder: (_e = this.adminforth.config.customization) === null || _e === void 0 ? void 0 : _e.emptyFieldPlaceholder,
233
+ announcementBadge,
234
+ globalInjections: (_f = this.adminforth.config.customization) === null || _f === void 0 ? void 0 : _f.globalInjections,
235
+ };
236
+ return {
237
+ user: userData,
238
+ resources: this.adminforth.config.resources.map((res) => ({
239
+ resourceId: res.resourceId,
240
+ label: res.label,
241
+ })),
242
+ menu: newMenu,
243
+ config: Object.assign(Object.assign({}, publicPart), loggedInPart),
244
+ adminUser,
245
+ version: ADMINFORTH_VERSION,
246
+ };
247
+ },
248
+ });
249
+ function checkAccess(action, allowedActions) {
250
+ const allowed = allowedActions[action];
251
+ if (allowed !== true) {
252
+ return { error: typeof allowed === 'string' ? allowed : 'Action is not allowed', allowed: false };
253
+ }
254
+ return { allowed: true };
255
+ }
256
+ server.endpoint({
257
+ method: 'POST',
258
+ path: '/get_resource',
259
+ handler: async ({ body, adminUser }) => {
260
+ const { resourceId } = body;
261
+ if (!this.adminforth.statuses.dbDiscover) {
262
+ return { error: 'Database discovery not started' };
263
+ }
264
+ if (this.adminforth.statuses.dbDiscover !== 'done') {
265
+ return { error: 'Database discovery is still in progress, please try later' };
266
+ }
267
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
268
+ if (!resource) {
269
+ return { error: `Resource ${resourceId} not found` };
270
+ }
271
+ const { allowedActions } = await interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
272
+ const allowedBulkActions = [];
273
+ await Promise.all(resource.options.bulkActions.map(async (action) => {
274
+ if (action.allowed) {
275
+ const res = await action.allowed({ adminUser, resource, allowedActions });
276
+ if (res) {
277
+ allowedBulkActions.push(action);
278
+ }
279
+ }
280
+ else {
281
+ allowedBulkActions.push(action);
282
+ }
283
+ }));
284
+ // exclude "plugins" key
285
+ return {
286
+ resource: Object.assign(Object.assign({}, resource), { plugins: undefined, options: Object.assign(Object.assign({}, resource.options), { bulkActions: allowedBulkActions, allowedActions }) })
287
+ };
288
+ },
289
+ });
290
+ server.endpoint({
291
+ method: 'POST',
292
+ path: '/get_resource_data',
293
+ handler: async ({ body, adminUser, headers, query, cookies }) => {
294
+ var _a, _b, _c, _d;
295
+ const { resourceId, source } = body;
296
+ if (['show', 'list'].includes(source) === false) {
297
+ return { error: 'Invalid source, should be list or show' };
298
+ }
299
+ if (!this.adminforth.statuses.dbDiscover) {
300
+ return { error: 'Database discovery not started' };
301
+ }
302
+ if (this.adminforth.statuses.dbDiscover !== 'done') {
303
+ return { error: 'Database discovery is still in progress, please try later' };
304
+ }
305
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
306
+ if (!resource) {
307
+ return { error: `Resource ${resourceId} not found` };
308
+ }
309
+ const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
310
+ const { allowed, error } = checkAccess(source, allowedActions);
311
+ if (!allowed) {
312
+ return { error };
313
+ }
314
+ for (const hook of listify((_b = (_a = resource.hooks) === null || _a === void 0 ? void 0 : _a[source]) === null || _b === void 0 ? void 0 : _b.beforeDatasourceRequest)) {
315
+ const resp = await hook({
316
+ resource,
317
+ query: body,
318
+ adminUser,
319
+ extra: {
320
+ body, query, headers, cookies
321
+ },
322
+ adminforth: this.adminforth,
323
+ });
324
+ if (!resp || (!resp.ok && !resp.error)) {
325
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
326
+ }
327
+ if (resp.error) {
328
+ return { error: resp.error };
329
+ }
330
+ }
331
+ const { limit, offset, filters, sort } = body;
332
+ for (const filter of (filters || [])) {
333
+ if (!Object.values(AdminForthFilterOperators).includes(filter.operator)) {
334
+ throw new Error(`Operator '${filter.operator}' is not allowed`);
335
+ }
336
+ if (!resource.columns.some((col) => col.name === filter.field)) {
337
+ throw new Error(`Field '${filter.field}' is not in resource '${resource.resourceId}'. Available fields: ${resource.columns.map((col) => col.name).join(', ')}`);
338
+ }
339
+ if (filter.operator === AdminForthFilterOperators.IN || filter.operator === AdminForthFilterOperators.NIN) {
340
+ if (!Array.isArray(filter.value)) {
341
+ throw new Error(`Value for operator '${filter.operator}' should be an array`);
342
+ }
343
+ }
344
+ }
345
+ const data = await this.adminforth.connectors[resource.dataSource].getData({
346
+ resource,
347
+ limit,
348
+ offset,
349
+ filters,
350
+ sort,
351
+ getTotals: true,
352
+ });
353
+ // for foreign keys, add references
354
+ await Promise.all(resource.columns.filter((col) => col.foreignResource).map(async (col) => {
355
+ const targetResource = this.adminforth.config.resources.find((res) => res.resourceId == col.foreignResource.resourceId);
356
+ const targetConnector = this.adminforth.connectors[targetResource.dataSource];
357
+ const targetResourcePkField = targetResource.columns.find((col) => col.primaryKey).name;
358
+ const pksUnique = [...new Set(data.data.map((item) => item[col.name]))];
359
+ if (pksUnique.length === 0) {
360
+ return;
361
+ }
362
+ const targetData = await targetConnector.getData({
363
+ resource: targetResource,
364
+ limit: limit,
365
+ offset: 0,
366
+ filters: [
367
+ {
368
+ field: targetResourcePkField,
369
+ operator: AdminForthFilterOperators.IN,
370
+ value: pksUnique,
371
+ }
372
+ ],
373
+ sort: [],
374
+ });
375
+ const targetDataMap = targetData.data.reduce((acc, item) => {
376
+ acc[item[targetResourcePkField]] = {
377
+ label: targetResource.recordLabel(item),
378
+ pk: item[targetResourcePkField],
379
+ };
380
+ return acc;
381
+ }, {});
382
+ data.data.forEach((item) => {
383
+ item[col.name] = targetDataMap[item[col.name]];
384
+ });
385
+ }));
386
+ // remove all columns which are not defined in resources, or defined but backendOnly
387
+ data.data.forEach((item) => {
388
+ Object.keys(item).forEach((key) => {
389
+ if (!resource.columns.find((col) => col.name === key) || resource.columns.find((col) => col.name === key && col.backendOnly)) {
390
+ delete item[key];
391
+ }
392
+ });
393
+ item._label = resource.recordLabel(item);
394
+ });
395
+ if (resource.options.listTableClickUrl) {
396
+ await Promise.all(data.data.map(async (item) => {
397
+ item._clickUrl = await resource.options.listTableClickUrl(item, adminUser);
398
+ }));
399
+ }
400
+ // only after adminforth made all post processing, give user ability to edit it
401
+ for (const hook of listify((_d = (_c = resource.hooks) === null || _c === void 0 ? void 0 : _c[source]) === null || _d === void 0 ? void 0 : _d.afterDatasourceResponse)) {
402
+ const resp = await hook({
403
+ resource,
404
+ response: data.data,
405
+ adminUser,
406
+ extra: {
407
+ body, query, headers, cookies
408
+ },
409
+ adminforth: this.adminforth,
410
+ });
411
+ if (!resp || (!resp.ok && !resp.error)) {
412
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
413
+ }
414
+ if (resp.error) {
415
+ return { error: resp.error };
416
+ }
417
+ }
418
+ return Object.assign(Object.assign({}, data), { options: resource === null || resource === void 0 ? void 0 : resource.options });
419
+ },
420
+ });
421
+ server.endpoint({
422
+ method: 'POST',
423
+ path: '/get_resource_foreign_data',
424
+ handler: async ({ body, adminUser, headers, query, cookies }) => {
425
+ var _a, _b, _c, _d;
426
+ const { resourceId, column } = body;
427
+ if (!this.adminforth.statuses.dbDiscover) {
428
+ return { error: 'Database discovery not started' };
429
+ }
430
+ if (this.adminforth.statuses.dbDiscover !== 'done') {
431
+ return { error: 'Database discovery is still in progress, please try later' };
432
+ }
433
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
434
+ if (!resource) {
435
+ return { error: `Resource '${resourceId}' not found` };
436
+ }
437
+ const columnConfig = resource.columns.find((col) => col.name == column);
438
+ if (!columnConfig) {
439
+ return { error: `Column "${column}' not found in resource with resourceId '${resourceId}'` };
440
+ }
441
+ if (!columnConfig.foreignResource) {
442
+ return { error: `Column '${column}' in resource '${resourceId}' is not a foreign key` };
443
+ }
444
+ const targetResourceId = columnConfig.foreignResource.resourceId;
445
+ const targetResource = this.adminforth.config.resources.find((res) => res.resourceId == targetResourceId);
446
+ for (const hook of listify((_b = (_a = columnConfig.foreignResource.hooks) === null || _a === void 0 ? void 0 : _a.dropdownList) === null || _b === void 0 ? void 0 : _b.beforeDatasourceRequest)) {
447
+ const resp = await hook({
448
+ query: body,
449
+ adminUser,
450
+ resource: targetResource,
451
+ extra: {
452
+ body, query, headers, cookies
453
+ },
454
+ adminforth: this.adminforth,
455
+ });
456
+ if (!resp || (!resp.ok && !resp.error)) {
457
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
458
+ }
459
+ if (resp.error) {
460
+ return { error: resp.error };
461
+ }
462
+ }
463
+ const { limit, offset, filters, sort } = body;
464
+ const dbDataItems = await this.adminforth.connectors[targetResource.dataSource].getData({
465
+ resource: targetResource,
466
+ limit,
467
+ offset,
468
+ filters: filters || [],
469
+ sort: sort || [],
470
+ });
471
+ const items = dbDataItems.data.map((item) => {
472
+ const pk = item[targetResource.columns.find((col) => col.primaryKey).name];
473
+ const labler = targetResource.recordLabel;
474
+ return {
475
+ value: pk,
476
+ label: labler(item),
477
+ _item: item, // user might need it in hook to form new label
478
+ };
479
+ });
480
+ const response = {
481
+ items
482
+ };
483
+ for (const hook of listify((_d = (_c = columnConfig.foreignResource.hooks) === null || _c === void 0 ? void 0 : _c.dropdownList) === null || _d === void 0 ? void 0 : _d.afterDatasourceResponse)) {
484
+ const resp = await hook({
485
+ response,
486
+ adminUser,
487
+ resource: targetResource,
488
+ extra: {
489
+ body, query, headers, cookies
490
+ },
491
+ adminforth: this.adminforth,
492
+ });
493
+ if (!resp || (!resp.ok && !resp.error)) {
494
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
495
+ }
496
+ if (resp.error) {
497
+ return { error: resp.error };
498
+ }
499
+ }
500
+ return response;
501
+ },
502
+ });
503
+ server.endpoint({
504
+ method: 'POST',
505
+ path: '/get_min_max_for_columns',
506
+ handler: async ({ body }) => {
507
+ const { resourceId } = body;
508
+ if (!this.adminforth.statuses.dbDiscover) {
509
+ return { error: 'Database discovery not started' };
510
+ }
511
+ if (this.adminforth.statuses.dbDiscover !== 'done') {
512
+ return { error: 'Database discovery is still in progress, please try later' };
513
+ }
514
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
515
+ if (!resource) {
516
+ return { error: `Resource '${resourceId}' not found` };
517
+ }
518
+ const item = await this.adminforth.connectors[resource.dataSource].getMinMaxForColumns({
519
+ resource,
520
+ columns: resource.columns.filter((col) => [
521
+ AdminForthDataTypes.INTEGER,
522
+ AdminForthDataTypes.FLOAT,
523
+ AdminForthDataTypes.DATE,
524
+ AdminForthDataTypes.DATETIME,
525
+ AdminForthDataTypes.TIME,
526
+ AdminForthDataTypes.DECIMAL,
527
+ ].includes(col.type) && col.allowMinMaxQuery === true),
528
+ });
529
+ return item;
530
+ },
531
+ });
532
+ server.endpoint({
533
+ method: 'POST',
534
+ path: '/create_record',
535
+ handler: async ({ body, adminUser }) => {
536
+ var _a;
537
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
538
+ if (!resource) {
539
+ return { error: `Resource '${body['resourceId']}' not found` };
540
+ }
541
+ const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.CreateRequest);
542
+ const { allowed, error } = checkAccess(AllowedActionsEnum.create, allowedActions);
543
+ if (!allowed) {
544
+ return { error };
545
+ }
546
+ const { record } = body;
547
+ for (const column of resource.columns) {
548
+ if (((_a = column.required) === null || _a === void 0 ? void 0 : _a.create) &&
549
+ record[column.name] === undefined &&
550
+ column.showIn.includes(AdminForthResourcePages.create)) {
551
+ return { error: `Column '${column.name}' is required`, ok: false };
552
+ }
553
+ }
554
+ const response = await this.adminforth.createResourceRecord({ resource, record, adminUser });
555
+ if (response.error) {
556
+ return { error: response.error, ok: false };
557
+ }
558
+ const connector = this.adminforth.connectors[resource.dataSource];
559
+ return {
560
+ newRecordId: response.createdRecord[connector.getPrimaryKey(resource)],
561
+ ok: true
562
+ };
563
+ }
564
+ });
565
+ server.endpoint({
566
+ method: 'POST',
567
+ path: '/update_record',
568
+ handler: async ({ body, adminUser }) => {
569
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
570
+ if (!resource) {
571
+ return { error: `Resource '${body['resourceId']}' not found` };
572
+ }
573
+ const recordId = body['recordId'];
574
+ const connector = this.adminforth.connectors[resource.dataSource];
575
+ const oldRecord = await connector.getRecordByPrimaryKey(resource, recordId);
576
+ if (!oldRecord) {
577
+ const primaryKeyColumn = resource.columns.find((col) => col.primaryKey);
578
+ return { error: `Record with ${primaryKeyColumn.name} ${recordId} not found` };
579
+ }
580
+ const record = body['record'];
581
+ const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body, newRecord: record, oldRecord }, ActionCheckSource.EditRequest);
582
+ const { allowed, error: allowedError } = checkAccess(AllowedActionsEnum.edit, allowedActions);
583
+ if (!allowed) {
584
+ return { allowedError };
585
+ }
586
+ const { error } = await this.adminforth.updateResourceRecord({ resource, record, adminUser, oldRecord, recordId });
587
+ if (error) {
588
+ return { error };
589
+ }
590
+ return {
591
+ ok: true
592
+ };
593
+ }
594
+ });
595
+ server.endpoint({
596
+ method: 'POST',
597
+ path: '/delete_record',
598
+ handler: async ({ body, adminUser }) => {
599
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
600
+ const record = await this.adminforth.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
601
+ if (!resource) {
602
+ return { error: `Resource '${body['resourceId']}' not found` };
603
+ }
604
+ if (!record) {
605
+ return { error: `Record with ${body['primaryKey']} not found` };
606
+ }
607
+ if (resource.options.allowedActions.delete === false) {
608
+ return { error: `Resource '${resource.resourceId}' does not allow delete action` };
609
+ }
610
+ const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
611
+ const { allowed, error } = checkAccess(AllowedActionsEnum.delete, allowedActions);
612
+ if (!allowed) {
613
+ return { error };
614
+ }
615
+ const { error: deleteError } = await this.adminforth.deleteResourceRecord({ resource, record, adminUser, recordId: body['primaryKey'] });
616
+ if (deleteError) {
617
+ return { error: deleteError };
618
+ }
619
+ return {
620
+ ok: true,
621
+ recordId: body['primaryKey']
622
+ };
623
+ }
624
+ });
625
+ server.endpoint({
626
+ method: 'POST',
627
+ path: '/start_bulk_action',
628
+ handler: async ({ body, adminUser }) => {
629
+ const { resourceId, actionId, recordIds } = body;
630
+ const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
631
+ if (!resource) {
632
+ return { error: `Resource '${resourceId}' not found` };
633
+ }
634
+ const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.BulkActionRequest);
635
+ const action = resource.options.bulkActions.find((act) => act.id == actionId);
636
+ if (!action) {
637
+ return { error: `Action '${actionId}' not found` };
638
+ }
639
+ if (action.allowed) {
640
+ const execAllowed = await action.allowed({ adminUser, resource, selectedIds: recordIds, allowedActions });
641
+ if (!execAllowed) {
642
+ return { error: `Action '${actionId}' is not allowed` };
643
+ }
644
+ }
645
+ const response = await action.action({ selectedIds: recordIds, adminUser, resource });
646
+ return Object.assign({ actionId,
647
+ recordIds,
648
+ resourceId }, response);
649
+ }
650
+ });
651
+ // setup endpoints for all plugins
652
+ this.adminforth.activatedPlugins.forEach((plugin) => {
653
+ plugin.setupEndpoints(server);
654
+ });
655
+ }
656
+ }
657
+ //# sourceMappingURL=restApi.js.map