adminforth 1.1.12 → 1.1.14
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/auth.ts +17 -3
- package/dist/auth.js +32 -18
- package/dist/index.js +107 -63
- package/dist/modules/codeInjector.js +9 -3
- package/dist/modules/utils.js +2 -12
- package/dist/plugins/AccessControl/index.js +66 -0
- package/dist/plugins/AccessControl/types.js +1 -0
- package/dist/plugins/ForeignInlineListPlugin/index.js +1 -1
- package/dist/servers/express.js +2 -2
- package/dist/spa/spa/src/App.vue +7 -3
- package/dist/spa/spa/src/components/Toast.vue +5 -4
- package/dist/spa/spa/src/components/ValueRenderer.vue +1 -1
- package/dist/spa/spa/src/composables/useStores.ts +2 -1
- package/dist/spa/spa/src/router/index.ts +13 -1
- package/dist/spa/spa/src/stores/core.ts +13 -11
- package/dist/spa/spa/src/stores/user.ts +50 -0
- package/dist/spa/spa/src/utils.ts +8 -3
- package/dist/spa/spa/src/views/CreateView.vue +7 -0
- package/dist/spa/spa/src/views/EditView.vue +8 -1
- package/dist/spa/spa/src/views/ListView.vue +10 -1
- package/dist/types/AdminForthConfig.js +9 -0
- package/dist/types/FrontendAPI.js +4 -4
- package/index.ts +103 -51
- package/modules/codeInjector.ts +9 -3
- package/modules/utils.ts +2 -10
- package/package.json +1 -1
- package/plugins/AccessControl/index.ts +83 -0
- package/plugins/AccessControl/types.ts +14 -0
- package/plugins/ForeignInlineListPlugin/custom/InlineList.vue +13 -1
- package/plugins/ForeignInlineListPlugin/index.ts +2 -1
- package/servers/express.ts +2 -2
- package/spa/src/App.vue +7 -3
- package/spa/src/components/Toast.vue +5 -4
- package/spa/src/components/ValueRenderer.vue +1 -1
- package/spa/src/composables/useStores.ts +2 -1
- package/spa/src/router/index.ts +13 -1
- package/spa/src/stores/core.ts +13 -11
- package/spa/src/stores/user.ts +50 -0
- package/spa/src/utils.ts +8 -3
- package/spa/src/views/CreateView.vue +7 -0
- package/spa/src/views/EditView.vue +8 -1
- package/spa/src/views/ListView.vue +10 -1
- package/types/AdminForthConfig.ts +73 -21
- package/types/FrontendAPI.ts +11 -5
package/spa/src/stores/core.ts
CHANGED
|
@@ -8,7 +8,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
8
8
|
const resourceById: Ref<Object> = ref({});
|
|
9
9
|
const menu = ref([]);
|
|
10
10
|
const config = ref({});
|
|
11
|
-
const record = ref({});
|
|
11
|
+
const record: Ref<any | null> = ref({});
|
|
12
12
|
const resource: Ref<AdminForthResource | null> = ref(null);
|
|
13
13
|
|
|
14
14
|
const resourceColumnsWithFilters = computed(() => {
|
|
@@ -67,9 +67,17 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
67
67
|
}
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
if (respData.error) {
|
|
71
|
+
window.adminforth.alert({
|
|
72
|
+
message: respData.error,
|
|
73
|
+
variant: 'danger',
|
|
74
|
+
timeout: 'unlimited'
|
|
75
|
+
});
|
|
76
|
+
record.value = {};
|
|
77
|
+
} else {
|
|
78
|
+
record.value = respData.data[0];
|
|
79
|
+
}
|
|
80
|
+
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
async function fetchResourceFull({ resourceId }: { resourceId: string }) {
|
|
@@ -103,12 +111,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
103
111
|
config.value = {...config.value, ...res};
|
|
104
112
|
}
|
|
105
113
|
|
|
106
|
-
|
|
107
|
-
await callAdminForthApi({
|
|
108
|
-
path: '/logout',
|
|
109
|
-
method: 'POST',
|
|
110
|
-
});
|
|
111
|
-
}
|
|
114
|
+
|
|
112
115
|
|
|
113
116
|
const username = computed(() => {
|
|
114
117
|
const usernameField = config.value.usernameField;
|
|
@@ -134,7 +137,6 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
134
137
|
fetchResourceFull,
|
|
135
138
|
resourceColumnsError,
|
|
136
139
|
resourceOptions,
|
|
137
|
-
logout,
|
|
138
140
|
resource,
|
|
139
141
|
adminUser,
|
|
140
142
|
resourceColumnsWithFilters
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {ref} from 'vue';
|
|
2
|
+
import {defineStore} from 'pinia';
|
|
3
|
+
import { callAdminForthApi } from '@/utils';
|
|
4
|
+
|
|
5
|
+
export const useUserStore = defineStore('user', () => {
|
|
6
|
+
const isAuthorized = ref(false);
|
|
7
|
+
|
|
8
|
+
function authorize() {
|
|
9
|
+
isAuthorized.value = true;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function unauthorize() {
|
|
13
|
+
isAuthorized.value = false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function logout() {
|
|
17
|
+
await callAdminForthApi({
|
|
18
|
+
path: '/logout',
|
|
19
|
+
method: 'POST',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function checkAuth( skipApiCall = false){
|
|
24
|
+
if(isAuthorized.value) return true;
|
|
25
|
+
else {
|
|
26
|
+
if(skipApiCall) return false;
|
|
27
|
+
const resp = await callAdminForthApi({
|
|
28
|
+
path: '/check_auth',
|
|
29
|
+
method: 'POST',
|
|
30
|
+
});
|
|
31
|
+
if (resp.status !== 401) {
|
|
32
|
+
authorize();
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
unauthorize();
|
|
37
|
+
return false;}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
isAuthorized,
|
|
44
|
+
authorize,
|
|
45
|
+
unauthorize,
|
|
46
|
+
checkAuth,
|
|
47
|
+
logout
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
});
|
package/spa/src/utils.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { CoreConfig } from './spa_types/core';
|
|
|
4
4
|
import router from "./router";
|
|
5
5
|
import { useRouter } from 'vue-router';
|
|
6
6
|
import { useCoreStore } from './stores/core';
|
|
7
|
+
import { useUserStore } from './stores/user';
|
|
7
8
|
|
|
8
9
|
export async function callApi({path, method, body=undefined} ) {
|
|
9
10
|
const options = {
|
|
@@ -16,14 +17,18 @@ export async function callApi({path, method, body=undefined} ) {
|
|
|
16
17
|
const fullPath = `${import.meta.env.VITE_ADMINFORTH_PUBLIC_PATH || ''}${path}`;
|
|
17
18
|
const r = await fetch(fullPath, options);
|
|
18
19
|
if (r.status == 401) {
|
|
19
|
-
|
|
20
|
-
router.push({name: 'login'});
|
|
20
|
+
useUserStore().unauthorize();
|
|
21
|
+
router.push({ name: 'login' });
|
|
21
22
|
return null;
|
|
22
23
|
}
|
|
23
24
|
return await r.json();
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export async function callAdminForthApi({ path, method, body=undefined }
|
|
27
|
+
export async function callAdminForthApi({ path, method, body=undefined }: {
|
|
28
|
+
path: string,
|
|
29
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
|
30
|
+
body?: any
|
|
31
|
+
}) {
|
|
27
32
|
try {
|
|
28
33
|
return callApi({path: `/adminapi/v1${path}`, method, body} );
|
|
29
34
|
} catch (e) {
|
|
@@ -137,6 +137,13 @@ async function saveRecord() {
|
|
|
137
137
|
record: record.value,
|
|
138
138
|
},
|
|
139
139
|
});
|
|
140
|
+
if (response.error) {
|
|
141
|
+
window.adminforth.alert({
|
|
142
|
+
message: resp.error,
|
|
143
|
+
variant: 'danger',
|
|
144
|
+
timeout: 'unlimited',
|
|
145
|
+
})
|
|
146
|
+
}
|
|
140
147
|
saving.value = false;
|
|
141
148
|
if (route.query.returnTo) {
|
|
142
149
|
router.push(route.query.returnTo);
|
|
@@ -145,7 +145,7 @@ async function saveRecord() {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
await callAdminForthApi({
|
|
148
|
+
const resp = await callAdminForthApi({
|
|
149
149
|
method: 'POST',
|
|
150
150
|
path: `/update_record`,
|
|
151
151
|
body: {
|
|
@@ -154,6 +154,13 @@ async function saveRecord() {
|
|
|
154
154
|
record: updates,
|
|
155
155
|
},
|
|
156
156
|
});
|
|
157
|
+
if (resp.error) {
|
|
158
|
+
window.adminforth.alert({
|
|
159
|
+
message: resp.error,
|
|
160
|
+
variant: 'danger',
|
|
161
|
+
timeout: 'unlimited',
|
|
162
|
+
})
|
|
163
|
+
}
|
|
157
164
|
saving.value = false;
|
|
158
165
|
router.push({ name: 'resource-show', params: { resourceId: route.params.resourceId, primaryKey: coreStore.record[coreStore.primaryKey] } });
|
|
159
166
|
}
|
|
@@ -183,7 +183,16 @@ async function getList() {
|
|
|
183
183
|
sort: sort.value,
|
|
184
184
|
}
|
|
185
185
|
});
|
|
186
|
-
|
|
186
|
+
if (data.error) {
|
|
187
|
+
window.adminforth.alert({
|
|
188
|
+
message: data.error,
|
|
189
|
+
variant: 'danger',
|
|
190
|
+
timeout: 'unlimited',
|
|
191
|
+
});
|
|
192
|
+
rows.value = [];
|
|
193
|
+
totalRows.value = 0;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
187
196
|
rows.value = data.data?.map(row => {
|
|
188
197
|
row._primaryKeyValue = row[coreStore.resource.columns.find(c => c.primaryKey).name];
|
|
189
198
|
return row;
|
|
@@ -26,12 +26,31 @@ export interface GenericHttpServer {
|
|
|
26
26
|
*/
|
|
27
27
|
endpoint(options: {
|
|
28
28
|
method: string,
|
|
29
|
+
noAuth?: boolean,
|
|
29
30
|
path: string,
|
|
30
|
-
handler:
|
|
31
|
+
handler: (body: any, adminUser: any, query: {[key: string]: string}, headers: {[key: string]: string}, cookies: {[key: string]: string}, response: {
|
|
32
|
+
setHeader: (key: string, value: string) => void,
|
|
33
|
+
setStatus: (code: number, message: string) => void,
|
|
34
|
+
}) => void,
|
|
31
35
|
}): void;
|
|
32
36
|
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
export type AdminUser = {
|
|
40
|
+
/**
|
|
41
|
+
* primaryKey field value of user in table which is defined by {@link AdminForthConfig.auth.resourceId}
|
|
42
|
+
* or null if it is user logged in as {@link AdminForthConfig.rootUser}
|
|
43
|
+
*/
|
|
44
|
+
pk: string | null,
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Username which takend from {@link AdminForthConfig.auth.usernameField} field in user resource {@link AdminForthConfig.auth.resourceId}
|
|
48
|
+
*/
|
|
49
|
+
username: string,
|
|
50
|
+
isRoot: boolean,
|
|
51
|
+
dbUser: any,
|
|
52
|
+
}
|
|
53
|
+
|
|
35
54
|
export interface ExpressHttpServer extends GenericHttpServer {
|
|
36
55
|
|
|
37
56
|
/**
|
|
@@ -67,7 +86,7 @@ export interface AdminForthClass {
|
|
|
67
86
|
|
|
68
87
|
auth: {
|
|
69
88
|
|
|
70
|
-
verify(jwt : string): any
|
|
89
|
+
verify(jwt : string): Promise<any>;
|
|
71
90
|
}
|
|
72
91
|
|
|
73
92
|
/**
|
|
@@ -75,7 +94,6 @@ export interface AdminForthClass {
|
|
|
75
94
|
*/
|
|
76
95
|
runningHotReload: boolean;
|
|
77
96
|
|
|
78
|
-
|
|
79
97
|
/**
|
|
80
98
|
* Connects to databases defined in datasources and fetches described resource columns to find out data types and constraints.
|
|
81
99
|
* You must call this method as soon as possible after AdminForth class is instantiated.
|
|
@@ -182,6 +200,7 @@ export enum AdminForthResourcePages {
|
|
|
182
200
|
edit = 'edit',
|
|
183
201
|
create = 'create',
|
|
184
202
|
filter = 'filter',
|
|
203
|
+
|
|
185
204
|
}
|
|
186
205
|
|
|
187
206
|
|
|
@@ -400,6 +419,32 @@ export type AdminForthResourceColumn = {
|
|
|
400
419
|
masked?: boolean,
|
|
401
420
|
}
|
|
402
421
|
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Modify query to change how data is fetched from database.
|
|
425
|
+
* Return ok: false and error: string to stop execution and show error message to user. Return ok: true to continue execution.
|
|
426
|
+
*/
|
|
427
|
+
export type BeforeDataSourceRequestFunction = (params: {resource: AdminForthResource, adminUser: AdminUser, query: any}) => Promise<{ok: boolean, error?: string}>;
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Modify response to change how data is returned after fetching from database.
|
|
431
|
+
* Return ok: false and error: string to stop execution and show error message to user. Return ok: true to continue execution.
|
|
432
|
+
*/
|
|
433
|
+
export type AfterDataSourceResponseFunction = (params: {resource: AdminForthResource, adminUser: AdminUser, response: any}) => Promise<{ok: boolean, error?: string}>;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Modify record to change how data is saved to database.
|
|
437
|
+
* Return ok: false and error: string to stop execution and show error message to user. Return ok: true to continue execution.
|
|
438
|
+
*/
|
|
439
|
+
export type BeforeSaveFunction = (params:{resource: AdminForthResource, adminUser: AdminUser, record: any}) => Promise<{ok: boolean, error?: string}>;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Modify record to change how data is saved to database.
|
|
443
|
+
* Return ok: false and error: string to stop execution and show error message to user. Return ok: true to continue execution.
|
|
444
|
+
*/
|
|
445
|
+
export type AfterSaveFunction = (params: {resource: AdminForthResource, adminUser: AdminUser, record: any}) => Promise<{ok: boolean, error?: string}>;
|
|
446
|
+
|
|
447
|
+
|
|
403
448
|
/**
|
|
404
449
|
* Resource describes one table or collection in database.
|
|
405
450
|
* AdminForth generates set of pages for 'list', 'show', 'edit', 'create', 'filter' operations for each resource.
|
|
@@ -456,24 +501,24 @@ export type AdminForthResource = {
|
|
|
456
501
|
plugins?: Array<AdminForthPluginType>,
|
|
457
502
|
hooks?: {
|
|
458
503
|
show?: {
|
|
459
|
-
beforeDatasourceRequest?:
|
|
460
|
-
afterDatasourceResponse?:
|
|
504
|
+
beforeDatasourceRequest?: BeforeDataSourceRequestFunction | Array<BeforeDataSourceRequestFunction>,
|
|
505
|
+
afterDatasourceResponse?: AfterDataSourceResponseFunction | Array<AfterDataSourceResponseFunction>,
|
|
461
506
|
},
|
|
462
507
|
list?: {
|
|
463
|
-
beforeDatasourceRequest?:
|
|
464
|
-
afterDatasourceResponse?:
|
|
508
|
+
beforeDatasourceRequest?: BeforeDataSourceRequestFunction | Array<BeforeDataSourceRequestFunction>,
|
|
509
|
+
afterDatasourceResponse?: AfterDataSourceResponseFunction | Array<AfterDataSourceResponseFunction>,
|
|
465
510
|
},
|
|
466
511
|
create?: {
|
|
467
|
-
beforeSave?:
|
|
468
|
-
afterSave?:
|
|
512
|
+
beforeSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
513
|
+
afterSave?: AfterSaveFunction | Array<AfterSaveFunction>,
|
|
469
514
|
},
|
|
470
515
|
edit?: {
|
|
471
|
-
beforeSave?:
|
|
472
|
-
afterSave?:
|
|
516
|
+
beforeSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
517
|
+
afterSave?: AfterSaveFunction | Array<AfterSaveFunction>,
|
|
473
518
|
},
|
|
474
519
|
delete?: {
|
|
475
|
-
beforeSave?:
|
|
476
|
-
afterSave?:
|
|
520
|
+
beforeSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
521
|
+
afterSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
477
522
|
},
|
|
478
523
|
},
|
|
479
524
|
options?: {
|
|
@@ -770,14 +815,21 @@ export type AdminForthConfig = {
|
|
|
770
815
|
deleteConfirmation?: boolean,
|
|
771
816
|
|
|
772
817
|
styles?: Object,
|
|
773
|
-
|
|
818
|
+
}
|
|
774
819
|
|
|
820
|
+
|
|
821
|
+
export enum AllowedActionsEnum {
|
|
822
|
+
show = 'show',
|
|
823
|
+
list = 'list',
|
|
824
|
+
edit = 'edit',
|
|
825
|
+
create = 'create',
|
|
826
|
+
delete = 'delete',
|
|
827
|
+
filter = 'filter',
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
|
|
775
831
|
export type AllowedActions = {
|
|
776
|
-
|
|
777
|
-
edit?: boolean,
|
|
778
|
-
show?: boolean,
|
|
779
|
-
delete?: boolean,
|
|
780
|
-
filter?: boolean,
|
|
832
|
+
[key in AllowedActionsEnum]?: boolean
|
|
781
833
|
}
|
|
782
834
|
|
|
783
835
|
export type ValidationObject = {
|
|
@@ -960,8 +1012,8 @@ export type AdminForthForeignResource = {
|
|
|
960
1012
|
resourceId: string,
|
|
961
1013
|
hooks?: {
|
|
962
1014
|
dropdownList?: {
|
|
963
|
-
beforeDatasourceRequest?:
|
|
964
|
-
afterDatasourceResponse?:
|
|
1015
|
+
beforeDatasourceRequest?: BeforeDataSourceRequestFunction | Array<BeforeDataSourceRequestFunction>,
|
|
1016
|
+
afterDatasourceResponse?: AfterDataSourceResponseFunction | Array<AfterDataSourceResponseFunction>,
|
|
965
1017
|
},
|
|
966
1018
|
},
|
|
967
1019
|
}
|
package/types/FrontendAPI.ts
CHANGED
|
@@ -88,7 +88,13 @@ export type AlertParams = {
|
|
|
88
88
|
/**
|
|
89
89
|
* The variant of the alert
|
|
90
90
|
*/
|
|
91
|
-
variant?: AlertVariant;
|
|
91
|
+
variant?: AlertVariant | keyof typeof AlertVariant;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The timeout of the alert
|
|
95
|
+
*/
|
|
96
|
+
timeout?: number | 'unlimited';
|
|
97
|
+
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
export type FilterParams = {
|
|
@@ -107,10 +113,10 @@ export type FilterParams = {
|
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
export enum AlertVariant {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
danger = 'danger',
|
|
117
|
+
success = 'success',
|
|
118
|
+
warning = 'warning',
|
|
119
|
+
info = 'info'
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
export type Operator = 'in' | 'ilike' | 'gte' | 'lte' ;
|