adminforth 1.3.27 → 1.3.29

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.
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { AdminForthFilterOperators, AdminForthDataTypes, AllowedActionsEnum, ActionCheckSource } from "../types/AdminForthConfig.js";
10
+ import { AdminForthFilterOperators, AdminForthDataTypes, AllowedActionsEnum, ActionCheckSource, AdminForthResourcePages } from "../types/AdminForthConfig.js";
11
11
  import { ADMINFORTH_VERSION, listify } from './utils.js';
12
12
  import AdminForthAuth from "../auth.js";
13
13
  export function interpretResource(adminUser, resource, meta, source) {
@@ -19,7 +19,7 @@ export function interpretResource(adminUser, resource, meta, source) {
19
19
  const allowedActions = {};
20
20
  yield Promise.all(Object.entries(((_a = resource.options) === null || _a === void 0 ? void 0 : _a.allowedActions) || {}).map((_b) => __awaiter(this, [_b], void 0, function* ([key, value]) {
21
21
  if (process.env.HEAVY_DEBUG) {
22
- console.log('🪲checking for allowed call', key, 'value:', value, 'typeof', typeof value);
22
+ console.log(`🪲🚥check allowed ${key}, ${value}`);
23
23
  }
24
24
  // if callable then call
25
25
  if (typeof value === 'function') {
@@ -485,6 +485,7 @@ export default class AdminForthRestAPI {
485
485
  method: 'POST',
486
486
  path: '/create_record',
487
487
  handler: (_2) => __awaiter(this, [_2], void 0, function* ({ body, adminUser }) {
488
+ var _3;
488
489
  const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
489
490
  if (!resource) {
490
491
  return { error: `Resource '${body['resourceId']}' not found` };
@@ -495,6 +496,13 @@ export default class AdminForthRestAPI {
495
496
  return { error };
496
497
  }
497
498
  const { record } = body;
499
+ for (const column of resource.columns) {
500
+ if (((_3 = column.required) === null || _3 === void 0 ? void 0 : _3.create) &&
501
+ record[column.name] === undefined &&
502
+ column.showIn.includes(AdminForthResourcePages.create)) {
503
+ return { error: `Column '${column.name}' is required`, ok: false };
504
+ }
505
+ }
498
506
  const response = yield this.adminforth.createResourceRecord({ resource, record, adminUser });
499
507
  if (response.error) {
500
508
  return { error: response.error, ok: false };
@@ -509,8 +517,7 @@ export default class AdminForthRestAPI {
509
517
  server.endpoint({
510
518
  method: 'POST',
511
519
  path: '/update_record',
512
- handler: (_3) => __awaiter(this, [_3], void 0, function* ({ body, adminUser }) {
513
- var _4, _5, _6, _7;
520
+ handler: (_4) => __awaiter(this, [_4], void 0, function* ({ body, adminUser }) {
514
521
  const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
515
522
  if (!resource) {
516
523
  return { error: `Resource '${body['resourceId']}' not found` };
@@ -524,68 +531,23 @@ export default class AdminForthRestAPI {
524
531
  }
525
532
  const record = body['record'];
526
533
  const { allowedActions } = yield interpretResource(adminUser, resource, { requestBody: body, newRecord: record, oldRecord }, ActionCheckSource.EditRequest);
527
- const { allowed, error } = checkAccess(AllowedActionsEnum.edit, allowedActions);
534
+ const { allowed, error: allowedError } = checkAccess(AllowedActionsEnum.edit, allowedActions);
528
535
  if (!allowed) {
529
- return { error };
530
- }
531
- // execute hook if needed
532
- for (const hook of listify((_5 = (_4 = resource.hooks) === null || _4 === void 0 ? void 0 : _4.edit) === null || _5 === void 0 ? void 0 : _5.beforeSave)) {
533
- const resp = yield hook({
534
- recordId,
535
- resource,
536
- record,
537
- adminUser
538
- });
539
- if (!resp || (!resp.ok && !resp.error)) {
540
- throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
541
- }
542
- if (resp.error) {
543
- return { error: resp.error };
544
- }
536
+ return { allowedError };
545
537
  }
546
- const newValues = {};
547
- for (const recordField in record) {
548
- if (record[recordField] !== oldRecord[recordField]) {
549
- const column = resource.columns.find((col) => col.name === recordField);
550
- if (column) {
551
- if (!column.virtual) {
552
- newValues[recordField] = connector.setFieldValue(column, record[recordField]);
553
- }
554
- }
555
- else {
556
- newValues[recordField] = record[recordField];
557
- }
558
- }
559
- }
560
- if (Object.keys(newValues).length > 0) {
561
- yield connector.updateRecord({ resource, recordId, newValues });
562
- }
563
- // execute hook if needed
564
- for (const hook of listify((_7 = (_6 = resource.hooks) === null || _6 === void 0 ? void 0 : _6.edit) === null || _7 === void 0 ? void 0 : _7.afterSave)) {
565
- const resp = yield hook({
566
- resource,
567
- record,
568
- adminUser,
569
- oldRecord,
570
- recordId,
571
- });
572
- if (!resp || (!resp.ok && !resp.error)) {
573
- throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
574
- }
575
- if (resp.error) {
576
- return { error: resp.error };
577
- }
538
+ const { error } = yield this.adminforth.updateResourceRecord({ resource, record, adminUser, oldRecord, recordId });
539
+ if (error) {
540
+ return { error };
578
541
  }
579
542
  return {
580
- newRecordId: recordId
543
+ ok: true
581
544
  };
582
545
  })
583
546
  });
584
547
  server.endpoint({
585
548
  method: 'POST',
586
549
  path: '/delete_record',
587
- handler: (_8) => __awaiter(this, [_8], void 0, function* ({ body, adminUser }) {
588
- var _9, _10, _11, _12;
550
+ handler: (_5) => __awaiter(this, [_5], void 0, function* ({ body, adminUser }) {
589
551
  const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
590
552
  const record = yield this.adminforth.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
591
553
  if (!resource) {
@@ -602,39 +564,12 @@ export default class AdminForthRestAPI {
602
564
  if (!allowed) {
603
565
  return { error };
604
566
  }
605
- // execute hook if needed
606
- for (const hook of listify((_10 = (_9 = resource.hooks) === null || _9 === void 0 ? void 0 : _9.delete) === null || _10 === void 0 ? void 0 : _10.beforeSave)) {
607
- const resp = yield hook({
608
- resource,
609
- record,
610
- adminUser,
611
- recordId: body['primaryKey']
612
- });
613
- if (!resp || (!resp.ok && !resp.error)) {
614
- throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
615
- }
616
- if (resp.error) {
617
- return { error: resp.error };
618
- }
619
- }
620
- const connector = this.adminforth.connectors[resource.dataSource];
621
- yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
622
- // execute hook if needed
623
- for (const hook of listify((_12 = (_11 = resource.hooks) === null || _11 === void 0 ? void 0 : _11.delete) === null || _12 === void 0 ? void 0 : _12.afterSave)) {
624
- const resp = yield hook({
625
- resource,
626
- record,
627
- adminUser,
628
- recordId: body['primaryKey']
629
- });
630
- if (!resp || (!resp.ok && !resp.error)) {
631
- throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
632
- }
633
- if (resp.error) {
634
- return { error: resp.error };
635
- }
567
+ const { error: deleteError } = yield this.adminforth.deleteResourceRecord({ resource, record, adminUser, recordId: body['primaryKey'] });
568
+ if (deleteError) {
569
+ return { error: deleteError };
636
570
  }
637
571
  return {
572
+ ok: true,
638
573
  recordId: body['primaryKey']
639
574
  };
640
575
  })
@@ -642,7 +577,7 @@ export default class AdminForthRestAPI {
642
577
  server.endpoint({
643
578
  method: 'POST',
644
579
  path: '/start_bulk_action',
645
- handler: (_13) => __awaiter(this, [_13], void 0, function* ({ body, adminUser }) {
580
+ handler: (_6) => __awaiter(this, [_6], void 0, function* ({ body, adminUser }) {
646
581
  const { resourceId, actionId, recordIds } = body;
647
582
  const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
648
583
  if (!resource) {
package/index.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  AfterSaveFunction,
18
18
  AdminUser,
19
19
  AdminForthResource,
20
+ IAdminForthDataSourceConnectorBase,
20
21
  } from './types/AdminForthConfig.js';
21
22
  import AdminForthPlugin from './basePlugin.js';
22
23
  import ConfigValidator from './modules/configValidator.js';
@@ -38,6 +39,17 @@ class AdminForth implements IAdminForth {
38
39
  static Utils = {
39
40
  generatePasswordHash: async (password) => {
40
41
  return await AdminForthAuth.generatePasswordHash(password);
42
+ },
43
+
44
+ PASSWORD_VALIDATORS: {
45
+ UP_LOW_NUM_SPECIAL: {
46
+ regExp: '^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[!@#\\$%\\^&\\*\\(\\)\\-_=\\+\\[\\]\\{\\}\\|;:\',\\.<>\\/\\?]).+$',
47
+ message: 'Password must include at least one uppercase letter, one lowercase letter, one number, and one special character'
48
+ },
49
+ UP_LOW_NUM: {
50
+ regExp: '^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).+$',
51
+ message: 'Password must include at least one uppercase letter, one lowercase letter, and one number'
52
+ },
41
53
  }
42
54
  }
43
55
 
@@ -49,7 +61,9 @@ class AdminForth implements IAdminForth {
49
61
  express: ExpressServer;
50
62
  auth: AdminForthAuth;
51
63
  codeInjector: CodeInjector;
52
- connectors;
64
+ connectors: {
65
+ [dataSourceId: string]: IAdminForthDataSourceConnectorBase,
66
+ };
53
67
  connectorClasses: any;
54
68
  runningHotReload: boolean;
55
69
  activatedPlugins: Array<AdminForthPlugin>;
@@ -202,18 +216,7 @@ class AdminForth implements IAdminForth {
202
216
  async createResourceRecord(
203
217
  { resource, record, adminUser }:
204
218
  { resource: AdminForthResource, record: any, adminUser: AdminUser }
205
- ): Promise<{ ok: boolean, error?: string, createdRecord?: any }> {
206
-
207
- for (const column of resource.columns) {
208
- // TODO: assuming specifity for AdminForthResourcePages.create better to move it to api for this button
209
- if (
210
- (column.required as {create?: boolean, edit?: boolean}) ?.create &&
211
- record[column.name] === undefined &&
212
- column.showIn.includes(AdminForthResourcePages.create)
213
- ) {
214
- return { error: `Column '${column.name}' is required`, ok: false };
215
- }
216
- }
219
+ ): Promise<{ error?: string, createdRecord?: any }> {
217
220
 
218
221
  // execute hook if needed
219
222
  for (const hook of listify(resource.hooks?.create?.beforeSave as BeforeSaveFunction[])) {
@@ -223,28 +226,28 @@ class AdminForth implements IAdminForth {
223
226
  }
224
227
 
225
228
  if (resp.error) {
226
- return { error: resp.error, ok: false };
229
+ return { error: resp.error };
227
230
  }
228
231
  }
229
232
 
230
233
  // remove virtual columns from record
231
234
  for (const column of resource.columns.filter((col) => col.virtual)) {
232
- if (record[column.name]) {
233
- delete record[column.name];
234
- }
235
+ if (record[column.name]) {
236
+ delete record[column.name];
237
+ }
235
238
  }
236
239
  const connector = this.connectors[resource.dataSource];
237
- process.env.HEAVY_DEBUG && console.log('🪲🪲🪲🪲 creating record createResourceRecord', record);
238
- const { ok, error, createdRecord } = await connector.createRecord({ resource, record, adminUser });
239
- if (!ok) {
240
- return { ok, error };
240
+ process.env.HEAVY_DEBUG && console.log('🪲🆕 creating record createResourceRecord', record);
241
+ const { error, createdRecord } = await connector.createRecord({ resource, record, adminUser });
242
+ if ( error ) {
243
+ return { error };
241
244
  }
242
245
 
243
246
  const primaryKey = record[resource.columns.find((col) => col.primaryKey).name];
244
247
 
245
248
  // execute hook if needed
246
249
  for (const hook of listify(resource.hooks?.create?.afterSave as AfterSaveFunction[])) {
247
- console.log('Hook afterSave', hook);
250
+ process.env.HEAVY_DEBUG && console.log('🪲 Hook afterSave', hook);
248
251
  const resp = await hook({
249
252
  recordId: primaryKey,
250
253
  resource,
@@ -257,11 +260,112 @@ class AdminForth implements IAdminForth {
257
260
  }
258
261
 
259
262
  if (resp.error) {
260
- return { error: resp.error, ok: false };
263
+ return { error: resp.error };
264
+ }
265
+ }
266
+
267
+ return { error, createdRecord };
268
+ }
269
+
270
+ /**
271
+ * record is partial record with only changed fields
272
+ */
273
+ async updateResourceRecord(
274
+ { resource, recordId, record, oldRecord, adminUser }:
275
+ { resource: AdminForthResource, recordId: any, record: any, oldRecord: any, adminUser: AdminUser }
276
+ ): Promise<{ error?: string }> {
277
+
278
+ // execute hook if needed
279
+ for (const hook of listify(resource.hooks?.edit?.beforeSave as BeforeSaveFunction[])) {
280
+ const resp = await hook({
281
+ recordId,
282
+ resource,
283
+ record,
284
+ oldRecord,
285
+ adminUser
286
+ });
287
+ if (!resp || (!resp.ok && !resp.error)) {
288
+ throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
289
+ }
290
+ if (resp.error) {
291
+ return { error: resp.error };
261
292
  }
262
293
  }
294
+ const newValues = {};
295
+ const connector = this.connectors[resource.dataSource];
296
+
297
+ for (const recordField in record) {
298
+ if (record[recordField] !== oldRecord[recordField]) {
299
+ // leave only changed fields to reduce data transfer/modifications in db
300
+ const column = resource.columns.find((col) => col.name === recordField);
301
+ if (!column || !column.virtual) {
302
+ // exclude virtual columns
303
+ newValues[recordField] = record[recordField];
304
+ }
305
+ }
306
+ }
263
307
 
264
- return { ok, error, createdRecord };
308
+ if (Object.keys(newValues).length > 0) {
309
+ await connector.updateRecord({ resource, recordId, newValues });
310
+ }
311
+
312
+ // execute hook if needed
313
+ for (const hook of listify(resource.hooks?.edit?.afterSave as AfterSaveFunction[])) {
314
+ const resp = await hook({
315
+ resource,
316
+ record,
317
+ adminUser,
318
+ oldRecord,
319
+ recordId,
320
+ });
321
+ if (!resp || (!resp.ok && !resp.error)) {
322
+ throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
323
+ }
324
+
325
+ return { error: resp.error };
326
+ }
327
+ }
328
+
329
+ async deleteResourceRecord(
330
+ { resource, recordId, adminUser, record }:
331
+ { resource: AdminForthResource, recordId: any, adminUser: AdminUser, record: any }
332
+ ): Promise<{ error?: string }> {
333
+ // execute hook if needed
334
+ for (const hook of listify(resource.hooks?.delete?.beforeSave as BeforeSaveFunction[])) {
335
+ const resp = await hook({
336
+ resource,
337
+ record,
338
+ adminUser,
339
+ recordId,
340
+ });
341
+ if (!resp || (!resp.ok && !resp.error)) {
342
+ throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
343
+ }
344
+
345
+ if (resp.error) {
346
+ return { error: resp.error };
347
+ }
348
+ }
349
+
350
+ const connector = this.connectors[resource.dataSource];
351
+ await connector.deleteRecord({ resource, recordId});
352
+
353
+ // execute hook if needed
354
+ for (const hook of listify(resource.hooks?.delete?.afterSave as BeforeSaveFunction[])) {
355
+ const resp = await hook({
356
+ resource,
357
+ record,
358
+ adminUser,
359
+ recordId,
360
+ });
361
+ if (!resp || (!resp.ok && !resp.error)) {
362
+ throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
363
+ }
364
+
365
+ if (resp.error) {
366
+ return { error: resp.error };
367
+ }
368
+ }
265
369
  }
266
370
 
267
371
  resource(resourceId: string): IOperationalResource {
@@ -236,13 +236,13 @@ class CodeInjector implements ICodeInjector {
236
236
  dereference: true, // needed to dereference types
237
237
  });
238
238
  if (process.env.HEAVY_DEBUG) {
239
- console.log('🪲 await fsExtra.copy copy single file', src, dest);
239
+ console.log('🪲⚙️ fsExtra.copy copy single file', src, dest);
240
240
  }
241
241
 
242
242
  }));
243
243
  } else {
244
244
  if (process.env.HEAVY_DEBUG) {
245
- console.log(`🪲 await fsExtra.copy from ${path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'spa')}, -> ${CodeInjector.SPA_TMP_PATH}`);
245
+ console.log(`🪲⚙️ fsExtra.copy from ${path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'spa')}, -> ${CodeInjector.SPA_TMP_PATH}`);
246
246
  }
247
247
 
248
248
  // try to rm SPA_TMP_PATH/src/types directory
@@ -257,7 +257,7 @@ class CodeInjector implements ICodeInjector {
257
257
  filter: (src) => {
258
258
  const filterPasses = !src.includes('/adminforth/spa/node_modules') && !src.includes('/adminforth/spa/dist')
259
259
  if (process.env.HEAVY_DEBUG && !filterPasses) {
260
- console.log('🪲 await fsExtra.copy filtered out', src);
260
+ console.log('🪲⚙️ fsExtra.copy filtered out', src);
261
261
  }
262
262
 
263
263
  return filterPasses
@@ -287,7 +287,7 @@ class CodeInjector implements ICodeInjector {
287
287
  for (const [src, dest] of Object.entries(this.srcFoldersToSync)) {
288
288
  const to = path.join(CodeInjector.SPA_TMP_PATH, 'src', 'custom', dest);
289
289
  if (process.env.HEAVY_DEBUG) {
290
- console.log(`🪲 await fsExtra.copy from ${src}, ${to}`);
290
+ console.log(`🪲⚙️ fsExtra.copy from ${src}, ${to}`);
291
291
  }
292
292
 
293
293
  await fsExtra.copy(src, to, {
@@ -534,7 +534,7 @@ class CodeInjector implements ICodeInjector {
534
534
  await collectDirectories(spaPath);
535
535
 
536
536
  if (process.env.HEAVY_DEBUG) {
537
- console.log('🔎 Watching for changes in:', directories.join(','));
537
+ console.log('🪲🔎 Watch for:', directories.join(','));
538
538
  }
539
539
 
540
540
  const watcher = filewatcher();
@@ -593,12 +593,12 @@ class CodeInjector implements ICodeInjector {
593
593
 
594
594
  const watcher = filewatcher();
595
595
  files.forEach((file) => {
596
- process.env.HEAVY_DEBUG && console.log(`🔎 Watching for changes in file ${file}`);
596
+ process.env.HEAVY_DEBUG && console.log(`🪲🔎 Watch for file ${file}`);
597
597
  watcher.add(file);
598
598
  });
599
599
 
600
600
  if (process.env.HEAVY_DEBUG) {
601
- console.log('🔎 Watching for changes in:', directories.join(','));
601
+ console.log('🪲🔎 Watch for:', directories.join(','));
602
602
  }
603
603
 
604
604
  watcher.on(
@@ -657,7 +657,7 @@ class CodeInjector implements ICodeInjector {
657
657
  await this.runNpmShell({command: 'run build-only', cwd});
658
658
  } else {
659
659
  const command = 'run dev';
660
- console.log(`⚙️ spawn: npm ${command}...`);
660
+ console.log(`🪲⚙️ spawn: npm ${command}...`);
661
661
  const nodeBinary = process.execPath;
662
662
  const npmPath = path.join(path.dirname(nodeBinary), 'npm');
663
663
  const env = {
@@ -87,7 +87,7 @@ export default class OperationalResource implements IOperationalResource {
87
87
  return await this.dataConnector.updateRecord({
88
88
  resource: this.resourceConfig,
89
89
  recordId: primaryKey,
90
- newValues: record
90
+ newValues: record
91
91
  });
92
92
  }
93
93
 
@@ -13,7 +13,8 @@ import {
13
13
  AfterDataSourceResponseFunction,
14
14
  BeforeDataSourceRequestFunction,
15
15
  AfterSaveFunction,
16
- AllowedActionsResolved
16
+ AllowedActionsResolved,
17
+ AdminForthResourcePages
17
18
 
18
19
  } from "../types/AdminForthConfig.js";
19
20
 
@@ -32,7 +33,7 @@ export async function interpretResource(adminUser: AdminUser, resource: AdminFor
32
33
  Object.entries(resource.options?.allowedActions || {}).map(
33
34
  async ([key, value]: [string, AllowedActionValue]) => {
34
35
  if (process.env.HEAVY_DEBUG) {
35
- console.log('🪲checking for allowed call', key, 'value:', value, 'typeof', typeof value);
36
+ console.log(`🪲🚥check allowed ${key}, ${value}`)
36
37
  }
37
38
 
38
39
  // if callable then call
@@ -575,6 +576,16 @@ export default class AdminForthRestAPI {
575
576
 
576
577
  const { record } = body;
577
578
 
579
+ for (const column of resource.columns) {
580
+ if (
581
+ (column.required as {create?: boolean, edit?: boolean})?.create &&
582
+ record[column.name] === undefined &&
583
+ column.showIn.includes(AdminForthResourcePages.create)
584
+ ) {
585
+ return { error: `Column '${column.name}' is required`, ok: false };
586
+ }
587
+ }
588
+
578
589
  const response = await this.adminforth.createResourceRecord({ resource, record, adminUser });
579
590
  if (response.error) {
580
591
  return { error: response.error, ok: false };
@@ -607,66 +618,17 @@ export default class AdminForthRestAPI {
607
618
 
608
619
  const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body, newRecord: record, oldRecord}, ActionCheckSource.EditRequest);
609
620
 
610
- const { allowed, error } = checkAccess(AllowedActionsEnum.edit, allowedActions);
621
+ const { allowed, error: allowedError } = checkAccess(AllowedActionsEnum.edit, allowedActions);
611
622
  if (!allowed) {
612
- return { error };
623
+ return { allowedError };
613
624
  }
614
625
 
615
- // execute hook if needed
616
- for (const hook of listify(resource.hooks?.edit?.beforeSave as BeforeSaveFunction[])) {
617
- const resp = await hook({
618
- recordId,
619
- resource,
620
- record,
621
- adminUser
622
- });
623
- if (!resp || (!resp.ok && !resp.error)) {
624
- throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
625
- }
626
-
627
- if (resp.error) {
628
- return { error: resp.error };
629
- }
630
- }
631
- const newValues = {};
632
-
633
- for (const recordField in record) {
634
- if (record[recordField] !== oldRecord[recordField]) {
635
- const column = resource.columns.find((col) => col.name === recordField);
636
- if (column) {
637
- if (!column.virtual) {
638
- newValues[recordField] = connector.setFieldValue(column, record[recordField]);
639
- }
640
- } else {
641
- newValues[recordField] = record[recordField];
642
- }
643
- }
644
- }
645
-
646
- if (Object.keys(newValues).length > 0) {
647
- await connector.updateRecord({ resource, recordId, newValues});
648
- }
649
-
650
- // execute hook if needed
651
- for (const hook of listify(resource.hooks?.edit?.afterSave as AfterSaveFunction[])) {
652
- const resp = await hook({
653
- resource,
654
- record,
655
- adminUser,
656
- oldRecord,
657
- recordId,
658
- });
659
- if (!resp || (!resp.ok && !resp.error)) {
660
- throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
661
- }
662
-
663
- if (resp.error) {
664
- return { error: resp.error };
665
- }
626
+ const { error } = await this.adminforth.updateResourceRecord({ resource, record, adminUser, oldRecord, recordId });
627
+ if (error) {
628
+ return { error };
666
629
  }
667
-
668
630
  return {
669
- newRecordId: recordId
631
+ ok: true
670
632
  }
671
633
  }
672
634
  });
@@ -693,43 +655,12 @@ export default class AdminForthRestAPI {
693
655
  return { error };
694
656
  }
695
657
 
696
- // execute hook if needed
697
- for (const hook of listify(resource.hooks?.delete?.beforeSave as BeforeSaveFunction[])) {
698
- const resp = await hook({
699
- resource,
700
- record,
701
- adminUser,
702
- recordId: body['primaryKey']
703
- });
704
- if (!resp || (!resp.ok && !resp.error)) {
705
- throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
706
- }
707
-
708
- if (resp.error) {
709
- return { error: resp.error };
710
- }
711
- }
712
-
713
- const connector = this.adminforth.connectors[resource.dataSource];
714
- await connector.deleteRecord({ resource, recordId: body['primaryKey']});
715
-
716
- // execute hook if needed
717
- for (const hook of listify(resource.hooks?.delete?.afterSave as BeforeSaveFunction[])) {
718
- const resp = await hook({
719
- resource,
720
- record,
721
- adminUser,
722
- recordId: body['primaryKey']
723
- });
724
- if (!resp || (!resp.ok && !resp.error)) {
725
- throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
726
- }
727
-
728
- if (resp.error) {
729
- return { error: resp.error };
730
- }
658
+ const { error: deleteError } = await this.adminforth.deleteResourceRecord({ resource, record, adminUser, recordId: body['primaryKey'] });
659
+ if (deleteError) {
660
+ return { error: deleteError };
731
661
  }
732
662
  return {
663
+ ok: true,
733
664
  recordId: body['primaryKey']
734
665
  }
735
666
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.3.27",
3
+ "version": "1.3.29",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",