adminforth 1.1.22 → 1.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import ExpressServer from './servers/express.js';
23
23
  import { v1 as uuid } from 'uuid';
24
24
  import fs from 'fs';
25
25
  import { ADMINFORTH_VERSION, listify } from './modules/utils.js';
26
- import { AdminForthFilterOperators, AdminForthDataTypes, AdminForthResourcePages, AllowedActionsEnum } from './types/AdminForthConfig.js';
26
+ import { AdminForthFilterOperators, AdminForthDataTypes, AdminForthResourcePages, AllowedActionsEnum, ActionCheckSource } from './types/AdminForthConfig.js';
27
27
  import path from 'path';
28
28
  //get array from enum AdminForthResourcePages
29
29
  class AdminForth {
@@ -633,13 +633,13 @@ class AdminForth {
633
633
  };
634
634
  }),
635
635
  });
636
- function interpretResource(adminUser, resource, meta) {
636
+ function interpretResource(adminUser, resource, meta, source) {
637
637
  return __awaiter(this, void 0, void 0, function* () {
638
638
  var _b;
639
639
  yield Promise.all(Object.entries(((_b = resource.options) === null || _b === void 0 ? void 0 : _b.allowedActions) || {}).map((_c) => __awaiter(this, [_c], void 0, function* ([key, value]) {
640
640
  // if callable then call
641
641
  if (typeof value === 'function') {
642
- resource.options.allowedActions[key] = yield value(adminUser, resource, meta);
642
+ resource.options.allowedActions[key] = yield value({ adminUser, resource, meta, source });
643
643
  }
644
644
  })));
645
645
  });
@@ -667,7 +667,7 @@ class AdminForth {
667
667
  if (!resource) {
668
668
  return { error: `Resource ${resourceId} not found` };
669
669
  }
670
- yield interpretResource(adminUser, resource, {});
670
+ yield interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
671
671
  // exclude "plugins" key
672
672
  return { resource: Object.assign(Object.assign({}, resource), { plugins: undefined }) };
673
673
  }),
@@ -691,7 +691,7 @@ class AdminForth {
691
691
  if (!resource) {
692
692
  return { error: `Resource ${resourceId} not found` };
693
693
  }
694
- yield interpretResource(adminUser, resource, { requestBody: body });
694
+ yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
695
695
  const { allowed, error } = checkAccess(source, resource);
696
696
  console.log('allowed', allowed, error);
697
697
  if (!allowed) {
@@ -891,7 +891,7 @@ class AdminForth {
891
891
  if (!resource) {
892
892
  return { error: `Resource '${body['resourceId']}' not found` };
893
893
  }
894
- yield interpretResource(adminUser, resource, { requestBody: body });
894
+ yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.CreateRequest);
895
895
  const { allowed, error } = checkAccess(AllowedActionsEnum.create, resource);
896
896
  if (!allowed) {
897
897
  return { error };
@@ -963,11 +963,6 @@ class AdminForth {
963
963
  if (!resource) {
964
964
  return { error: `Resource '${body['resourceId']}' not found` };
965
965
  }
966
- yield interpretResource(adminUser, resource, { requestBody: body });
967
- const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
968
- if (!allowed) {
969
- return { error };
970
- }
971
966
  const recordId = body['recordId'];
972
967
  const connector = this.connectors[resource.dataSource];
973
968
  const oldRecord = yield connector.getRecordByPrimaryKey(resource, recordId);
@@ -976,6 +971,11 @@ class AdminForth {
976
971
  return { error: `Record with ${primaryKeyColumn.name} ${recordId} not found` };
977
972
  }
978
973
  const record = body['record'];
974
+ yield interpretResource(adminUser, resource, { requestBody: body, record, oldRecord }, ActionCheckSource.EditRequest);
975
+ const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
976
+ if (!allowed) {
977
+ return { error };
978
+ }
979
979
  // execute hook if needed
980
980
  for (const hook of listify((_6 = (_5 = resource.hooks) === null || _5 === void 0 ? void 0 : _5.edit) === null || _6 === void 0 ? void 0 : _6.beforeSave)) {
981
981
  const resp = yield hook({ resource, record, adminUser });
@@ -1035,7 +1035,7 @@ class AdminForth {
1035
1035
  if (resource.options.allowedActions.delete === false) {
1036
1036
  return { error: `Resource '${resource.resourceId}' does not allow delete action` };
1037
1037
  }
1038
- yield interpretResource(adminUser, resource, { requestBody: body });
1038
+ yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
1039
1039
  const { allowed, error } = checkAccess(AllowedActionsEnum.delete, resource);
1040
1040
  if (!allowed) {
1041
1041
  return { error };
@@ -1,15 +1,5 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { AllowedActionsEnum } from "../../types/AdminForthConfig.js";
11
1
  import AdminForthPlugin from "../base.js";
12
- class AccessControlPlugin extends AdminForthPlugin {
2
+ class AuditLogPlugin extends AdminForthPlugin {
13
3
  constructor(options) {
14
4
  super(options, import.meta.url);
15
5
  this.options = options;
@@ -17,50 +7,7 @@ class AccessControlPlugin extends AdminForthPlugin {
17
7
  modifyResourceConfig(adminforth, resourceConfig) {
18
8
  super.modifyResourceConfig(adminforth, resourceConfig);
19
9
  this.adminforth = adminforth;
20
- if (!resourceConfig.hooks) {
21
- resourceConfig.hooks = {};
22
- }
23
- const checkAccess = (adminUser, action, meta) => __awaiter(this, void 0, void 0, function* () {
24
- const hasAccessOrError = yield this.options.hasAccess(adminUser, action, meta);
25
- if (hasAccessOrError === true) {
26
- return { ok: true };
27
- }
28
- else {
29
- return { ok: false, error: hasAccessOrError || AccessControlPlugin.defaultError };
30
- }
31
- });
32
- const bindHookCheck = (action, hookName) => {
33
- if (!resourceConfig.hooks[action]) {
34
- resourceConfig.hooks[action] = {};
35
- }
36
- if (!resourceConfig.hooks[action][hookName]) {
37
- resourceConfig.hooks[action][hookName] = [];
38
- }
39
- if (hookName === 'beforeDatasourceRequest') {
40
- resourceConfig.hooks[action][hookName].unshift((_a) => __awaiter(this, [_a], void 0, function* ({ adminUser, query }) {
41
- return checkAccess(adminUser, action, { query });
42
- }));
43
- }
44
- else {
45
- resourceConfig.hooks[action][hookName].unshift((_b) => __awaiter(this, [_b], void 0, function* ({ adminUser, record }) {
46
- return checkAccess(adminUser, action, { record });
47
- }));
48
- }
49
- };
50
- // List check
51
- bindHookCheck(AllowedActionsEnum.list, 'beforeDatasourceRequest');
52
- // Show check
53
- bindHookCheck(AllowedActionsEnum.show, 'beforeDatasourceRequest');
54
- // Edit check
55
- bindHookCheck(AllowedActionsEnum.edit, 'beforeDatasourceRequest');
56
- // create check
57
- bindHookCheck(AllowedActionsEnum.create, 'beforeSave');
58
- // edit check
59
- bindHookCheck(AllowedActionsEnum.edit, 'beforeSave');
60
- // delete check
61
- bindHookCheck(AllowedActionsEnum.delete, 'beforeSave');
62
- console.log('resourceConfig', resourceConfig);
63
10
  }
64
11
  }
65
- AccessControlPlugin.defaultError = 'Sorry, you do not have access to this resource.';
66
- export default AccessControlPlugin;
12
+ AuditLogPlugin.defaultError = 'Sorry, you do not have access to this resource.';
13
+ export default AuditLogPlugin;
@@ -12,3 +12,15 @@ export function showErrorTost(message: string, timeout?: number) {
12
12
  window.adminforth.alert({ message, variant: 'danger', timeout: timeout || 'unlimited'});
13
13
  return message;
14
14
  }
15
+
16
+
17
+ const useFrontendApi = () => {
18
+ return {
19
+ showSuccesTost,
20
+ showWarningTost,
21
+ showErrorTost
22
+ }
23
+ }
24
+
25
+
26
+ export default useFrontendApi;
@@ -16,7 +16,7 @@
16
16
  Edit
17
17
  </RouterLink>
18
18
 
19
- <button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="showDeleteModal"
19
+ <button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="deleteRecord"
20
20
  class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
21
21
  >
22
22
  <IconTrashBinSolid class="w-4 h-4" />
@@ -120,6 +120,7 @@ import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbi
120
120
  import { onMounted, ref } from 'vue';
121
121
  import { useRoute,useRouter } from 'vue-router';
122
122
  import {callAdminForthApi} from '@/utils';
123
+ import {showSuccesTost} from '@/composables/useFrontendApi';
123
124
 
124
125
 
125
126
  const item = ref(null);
@@ -154,40 +155,34 @@ onMounted(async () => {
154
155
  loading.value = false;
155
156
  });
156
157
 
157
- function showDeleteModal(row) {
158
- if (!coreStore.config?.deleteConfirmation) {
159
- return deleteRecord(row);
160
- }
161
- modalStore.setModalContent({
162
- content: 'Are you sure you want to delete this item?',
163
- acceptText: 'Delete',
164
- cancelText: 'Cancel',
165
- });
166
- modalStore.setOnAcceptFunction(() => {
167
- return deleteRecord(row)
168
- })
169
- modalStore.togleModal();
170
-
171
-
172
- }
173
-
174
158
  async function deleteRecord(row) {
175
- try{
176
- await callAdminForthApi({
159
+ const data = await window.adminforth.confirm({
160
+ message: 'Are you sure you want to delete this item?',
161
+ yes: 'Delete',
162
+ no: 'Cancel',
163
+ });
164
+ if (data) {
165
+ try {
166
+ const res = await callAdminForthApi({
177
167
  path: '/delete_record',
178
168
  method: 'POST',
179
169
  body: {
180
170
  resourceId: route.params.resourceId,
181
171
  primaryKey: route.params.primaryKey,
182
- recordId: route.params.primaryKey
172
+ }});
173
+ if (!res.error){
174
+ router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
175
+ showSuccesTost('Record deleted successfully')
176
+ } else {
177
+ console.error(res.error)
183
178
  }
184
- });
185
- router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
186
- } catch (error) {
187
- console.log(error);
188
- }
189
179
 
190
- modalStore.resetmodalState()
180
+ } catch (e) {
181
+ console.error(e);
182
+ };
183
+ }
184
+
185
+
191
186
  }
192
187
 
193
188
  </script>
@@ -61,6 +61,15 @@ export var AllowedActionsEnum;
61
61
  AllowedActionsEnum["delete"] = "delete";
62
62
  AllowedActionsEnum["filter"] = "filter";
63
63
  })(AllowedActionsEnum || (AllowedActionsEnum = {}));
64
+ export var ActionCheckSource;
65
+ (function (ActionCheckSource) {
66
+ ActionCheckSource["DisplayButtons"] = "displayButtons";
67
+ ActionCheckSource["ListRequest"] = "listRequest";
68
+ ActionCheckSource["ShowRequest"] = "showRequest";
69
+ ActionCheckSource["EditRequest"] = "editRequest";
70
+ ActionCheckSource["CreateRequest"] = "createRequest";
71
+ ActionCheckSource["DeleteRequest"] = "deleteRequest";
72
+ })(ActionCheckSource || (ActionCheckSource = {}));
64
73
  export var AdminForthDataTypes;
65
74
  (function (AdminForthDataTypes) {
66
75
  AdminForthDataTypes["STRING"] = "string";
package/index.ts CHANGED
@@ -16,11 +16,11 @@ import { AdminForthConfig, AdminForthClass, AdminForthComponentDeclaration, Admi
16
16
  BeforeDataSourceRequestFunction,
17
17
  AfterDataSourceResponseFunction, AllowedActionValue, AdminUser,
18
18
  AdminForthResource,
19
- AllowedActionsEnum
19
+ AllowedActionsEnum,
20
+ ActionCheckSource
20
21
  } from './types/AdminForthConfig.js';
21
22
  import path from 'path';
22
23
  import AdminForthPlugin from './plugins/base.js';
23
- import { tr } from '@faker-js/faker';
24
24
 
25
25
 
26
26
  //get array from enum AdminForthResourcePages
@@ -697,10 +697,6 @@ class AdminForth implements AdminForthClass {
697
697
  }
698
698
  newMenu.push(newMenuItem)
699
699
  }
700
-
701
-
702
-
703
-
704
700
 
705
701
  return {
706
702
  user: userData,
@@ -725,13 +721,13 @@ class AdminForth implements AdminForthClass {
725
721
  },
726
722
  });
727
723
 
728
- async function interpretResource(adminUser: AdminUser, resource: AdminForthResource, meta: any) {
724
+ async function interpretResource(adminUser: AdminUser, resource: AdminForthResource, meta: any, source: ActionCheckSource) {
729
725
  await Promise.all(
730
726
  Object.entries(resource.options?.allowedActions || {}).map(
731
727
  async ([key, value]: [string, AllowedActionValue]) => {
732
728
  // if callable then call
733
729
  if (typeof value === 'function') {
734
- resource.options.allowedActions[key] = await value( adminUser, resource, meta );
730
+ resource.options.allowedActions[key] = await value({ adminUser, resource, meta, source });
735
731
  }
736
732
  })
737
733
  );
@@ -762,7 +758,7 @@ class AdminForth implements AdminForthClass {
762
758
  return { error: `Resource ${resourceId} not found` };
763
759
  }
764
760
 
765
- await interpretResource(adminUser, resource, {});
761
+ await interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
766
762
 
767
763
  // exclude "plugins" key
768
764
  return { resource: { ...resource, plugins: undefined } };
@@ -787,7 +783,7 @@ class AdminForth implements AdminForthClass {
787
783
  return { error: `Resource ${resourceId} not found` };
788
784
  }
789
785
 
790
- await interpretResource(adminUser, resource, { requestBody: body });
786
+ await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
791
787
 
792
788
  const { allowed, error } = checkAccess(source as AllowedActionsEnum, resource);
793
789
  console.log('allowed', allowed, error);
@@ -1012,7 +1008,7 @@ class AdminForth implements AdminForthClass {
1012
1008
  if (!resource) {
1013
1009
  return { error: `Resource '${body['resourceId']}' not found` };
1014
1010
  }
1015
- await interpretResource(adminUser, resource, { requestBody: body });
1011
+ await interpretResource(adminUser, resource, { requestBody: body}, ActionCheckSource.CreateRequest);
1016
1012
 
1017
1013
  const { allowed, error } = checkAccess(AllowedActionsEnum.create, resource);
1018
1014
  if (!allowed) {
@@ -1093,13 +1089,7 @@ class AdminForth implements AdminForthClass {
1093
1089
  if (!resource) {
1094
1090
  return { error: `Resource '${body['resourceId']}' not found` };
1095
1091
  }
1096
- await interpretResource(adminUser, resource, { requestBody: body });
1097
-
1098
- const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
1099
- if (!allowed) {
1100
- return { error };
1101
- }
1102
-
1092
+
1103
1093
  const recordId = body['recordId'];
1104
1094
  const connector = this.connectors[resource.dataSource];
1105
1095
  const oldRecord = await connector.getRecordByPrimaryKey(resource, recordId)
@@ -1109,6 +1099,13 @@ class AdminForth implements AdminForthClass {
1109
1099
  }
1110
1100
  const record = body['record'];
1111
1101
 
1102
+ await interpretResource(adminUser, resource, { requestBody: body, record, oldRecord}, ActionCheckSource.EditRequest);
1103
+
1104
+ const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
1105
+ if (!allowed) {
1106
+ return { error };
1107
+ }
1108
+
1112
1109
  // execute hook if needed
1113
1110
  for (const hook of listify(resource.hooks?.edit?.beforeSave as BeforeSaveFunction[])) {
1114
1111
  const resp = await hook({ resource, record, adminUser });
@@ -1173,7 +1170,7 @@ class AdminForth implements AdminForthClass {
1173
1170
  return { error: `Resource '${resource.resourceId}' does not allow delete action` };
1174
1171
  }
1175
1172
 
1176
- await interpretResource(adminUser, resource, { requestBody: body });
1173
+ await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
1177
1174
 
1178
1175
  const { allowed, error } = checkAccess(AllowedActionsEnum.delete, resource);
1179
1176
  if (!allowed) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,4 @@
1
+
2
+
3
+ export type PluginOptions = {
4
+ }
@@ -12,3 +12,15 @@ export function showErrorTost(message: string, timeout?: number) {
12
12
  window.adminforth.alert({ message, variant: 'danger', timeout: timeout || 'unlimited'});
13
13
  return message;
14
14
  }
15
+
16
+
17
+ const useFrontendApi = () => {
18
+ return {
19
+ showSuccesTost,
20
+ showWarningTost,
21
+ showErrorTost
22
+ }
23
+ }
24
+
25
+
26
+ export default useFrontendApi;
@@ -16,7 +16,7 @@
16
16
  Edit
17
17
  </RouterLink>
18
18
 
19
- <button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="showDeleteModal"
19
+ <button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="deleteRecord"
20
20
  class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
21
21
  >
22
22
  <IconTrashBinSolid class="w-4 h-4" />
@@ -120,6 +120,7 @@ import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbi
120
120
  import { onMounted, ref } from 'vue';
121
121
  import { useRoute,useRouter } from 'vue-router';
122
122
  import {callAdminForthApi} from '@/utils';
123
+ import {showSuccesTost} from '@/composables/useFrontendApi';
123
124
 
124
125
 
125
126
  const item = ref(null);
@@ -154,40 +155,34 @@ onMounted(async () => {
154
155
  loading.value = false;
155
156
  });
156
157
 
157
- function showDeleteModal(row) {
158
- if (!coreStore.config?.deleteConfirmation) {
159
- return deleteRecord(row);
160
- }
161
- modalStore.setModalContent({
162
- content: 'Are you sure you want to delete this item?',
163
- acceptText: 'Delete',
164
- cancelText: 'Cancel',
165
- });
166
- modalStore.setOnAcceptFunction(() => {
167
- return deleteRecord(row)
168
- })
169
- modalStore.togleModal();
170
-
171
-
172
- }
173
-
174
158
  async function deleteRecord(row) {
175
- try{
176
- await callAdminForthApi({
159
+ const data = await window.adminforth.confirm({
160
+ message: 'Are you sure you want to delete this item?',
161
+ yes: 'Delete',
162
+ no: 'Cancel',
163
+ });
164
+ if (data) {
165
+ try {
166
+ const res = await callAdminForthApi({
177
167
  path: '/delete_record',
178
168
  method: 'POST',
179
169
  body: {
180
170
  resourceId: route.params.resourceId,
181
171
  primaryKey: route.params.primaryKey,
182
- recordId: route.params.primaryKey
172
+ }});
173
+ if (!res.error){
174
+ router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
175
+ showSuccesTost('Record deleted successfully')
176
+ } else {
177
+ console.error(res.error)
183
178
  }
184
- });
185
- router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
186
- } catch (error) {
187
- console.log(error);
188
- }
189
179
 
190
- modalStore.resetmodalState()
180
+ } catch (e) {
181
+ console.error(e);
182
+ };
183
+ }
184
+
185
+
191
186
  }
192
187
 
193
188
  </script>
@@ -838,7 +838,29 @@ export enum AllowedActionsEnum {
838
838
  * or function which returns Boolean or string with error message
839
839
  *
840
840
  */
841
- export type AllowedActionValue = boolean | ((adminUser: AdminUser, resource: AdminForthResource, meta: any) => Promise<boolean | string>);
841
+ export type AllowedActionValue = boolean | (({adminUser, resource, meta, source}: {
842
+ adminUser: AdminUser,
843
+ resource: AdminForthResource,
844
+
845
+ /**
846
+ * Meta object which will pass request information just in case
847
+ */
848
+ meta: any,
849
+
850
+ /**
851
+ * Source of the check
852
+ */
853
+ source: ActionCheckSource,
854
+ }) => Promise<boolean | string>);
855
+
856
+ export enum ActionCheckSource {
857
+ DisplayButtons = 'displayButtons',
858
+ ListRequest = 'listRequest',
859
+ ShowRequest = 'showRequest',
860
+ EditRequest = 'editRequest',
861
+ CreateRequest = 'createRequest',
862
+ DeleteRequest = 'deleteRequest',
863
+ }
842
864
 
843
865
  /**
844
866
  * Object which describes allowed actions for user.
@@ -1,7 +0,0 @@
1
-
2
- import { AllowedActionsEnum, AdminUser } from '../../types/AdminForthConfig.js';
3
-
4
-
5
- export type PluginOptions = {
6
-
7
- }
File without changes