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
|
@@ -24,7 +24,7 @@ export default class ForeignInlineListPlugin extends AdminForthPlugin {
|
|
|
24
24
|
return { error: `Resource ${this.options.foreignResourceId} not found` };
|
|
25
25
|
}
|
|
26
26
|
// exclude "plugins" key
|
|
27
|
-
const resourceCopy = Object.assign(Object.assign({}, resource), { plugins: undefined });
|
|
27
|
+
const resourceCopy = JSON.parse(JSON.stringify(Object.assign(Object.assign({}, resource), { plugins: undefined })));
|
|
28
28
|
if (this.options.modifyTableResourceConfig) {
|
|
29
29
|
this.options.modifyTableResourceConfig(resourceCopy);
|
|
30
30
|
}
|
package/dist/servers/express.js
CHANGED
|
@@ -149,7 +149,7 @@ class ExpressServer {
|
|
|
149
149
|
res.status(401).send('Unauthorized by AdminForth');
|
|
150
150
|
return;
|
|
151
151
|
}
|
|
152
|
-
const adminforthUser = this.adminforth.auth.verify(jwt);
|
|
152
|
+
const adminforthUser = yield this.adminforth.auth.verify(jwt);
|
|
153
153
|
if (!adminforthUser) {
|
|
154
154
|
res.status(401).send('Unauthorized by AdminForth');
|
|
155
155
|
}
|
|
@@ -191,7 +191,7 @@ class ExpressServer {
|
|
|
191
191
|
this.message = message;
|
|
192
192
|
}
|
|
193
193
|
};
|
|
194
|
-
const input = { body, query, headers, cookies, response, _raw_express_req: req, _raw_express_res: res };
|
|
194
|
+
const input = { body, query, headers, cookies, adminUser, response, _raw_express_req: req, _raw_express_res: res };
|
|
195
195
|
let output;
|
|
196
196
|
try {
|
|
197
197
|
output = yield handler(input);
|
package/dist/spa/spa/src/App.vue
CHANGED
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
aria-label="Sidebar"
|
|
65
65
|
>
|
|
66
66
|
<div class="h-full px-3 pb-4 overflow-y-auto bg-nav-menu-bg dark:bg-gray-800 border-r">
|
|
67
|
-
|
|
68
67
|
<div class="flex ms-2 md:me-24 m-4 ">
|
|
69
68
|
<img :src="loadFile(coreStore.config?.brandLogo || '@/assets/logo.svg')" :alt="`${ coreStore.config?.brandName } Logo`" class="h-8 me-3" />
|
|
70
69
|
<span class="self-center text-header-text-size font-semibold sm:text-header-text-size whitespace-nowrap dark:text-header-text text-header-logo-color">
|
|
@@ -168,6 +167,7 @@ import { RouterLink, RouterView } from 'vue-router';
|
|
|
168
167
|
import { initFlowbite } from 'flowbite'
|
|
169
168
|
import './index.scss'
|
|
170
169
|
import { useCoreStore } from '@/stores/core';
|
|
170
|
+
import { useUserStore } from '@/stores/user';
|
|
171
171
|
import {useModalStore} from '@/stores/modal';
|
|
172
172
|
import { IconMoonSolid, IconSunSolid } from '@iconify-prerendered/vue-flowbite';
|
|
173
173
|
import AcceptModal from './components/AcceptModal.vue';
|
|
@@ -184,6 +184,7 @@ import { FrontendAPI } from '@/composables/useStores'
|
|
|
184
184
|
const coreStore = useCoreStore();
|
|
185
185
|
const modalStore = useModalStore();
|
|
186
186
|
const toastStore = useToastStore();
|
|
187
|
+
const userStore = useUserStore();
|
|
187
188
|
const frontendApi = new FrontendAPI();
|
|
188
189
|
frontendApi.init();
|
|
189
190
|
const splitAtLast = (str: string, separator: string) => {
|
|
@@ -221,8 +222,9 @@ if (opened.value.includes(label)) {
|
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
async function logout() {
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
userStore.unauthorize();
|
|
226
|
+
await userStore.logout();
|
|
227
|
+
router.push({ name: 'login' })
|
|
226
228
|
}
|
|
227
229
|
|
|
228
230
|
|
|
@@ -244,6 +246,8 @@ async function loadMenu() {
|
|
|
244
246
|
});
|
|
245
247
|
}
|
|
246
248
|
|
|
249
|
+
|
|
250
|
+
|
|
247
251
|
watch(route, () => {
|
|
248
252
|
title.value = `${coreStore.config?.title || coreStore.config?.brandName || 'Adminforth'} | ${ Object.values(route.params)[0] || route.meta.title || ' '}`;
|
|
249
253
|
useHead({
|
|
@@ -46,16 +46,17 @@ const props = defineProps<{
|
|
|
46
46
|
toast:{message: string;
|
|
47
47
|
variant: string;
|
|
48
48
|
id: string;
|
|
49
|
-
|
|
49
|
+
timeout?: number|'unlimited';}
|
|
50
50
|
}>();
|
|
51
51
|
function closeToast() {
|
|
52
52
|
emit('close');
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
onMounted(() => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
if (props.toast.timeout === 'unlimited') return;
|
|
57
|
+
else {
|
|
58
|
+
setTimeout(() => {emit('close');}, props.toast.timeout || 10000 );
|
|
59
|
+
}
|
|
59
60
|
});
|
|
60
61
|
|
|
61
62
|
</script>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
2
2
|
import ResourceParent from '@/views/ResourceParent.vue'
|
|
3
|
+
import { useUserStore } from '@/stores/user'
|
|
3
4
|
/* IMPORTANT:ADMINFORTH ROUTES IMPORTS */
|
|
4
5
|
|
|
5
6
|
const router = createRouter({
|
|
@@ -9,7 +10,15 @@ const router = createRouter({
|
|
|
9
10
|
path: '/login',
|
|
10
11
|
name: 'login',
|
|
11
12
|
component: () => import('@/views/LoginView.vue'),
|
|
12
|
-
meta: { title: 'login' }
|
|
13
|
+
meta: { title: 'login' },
|
|
14
|
+
beforeEnter: async (to, from, next) => {
|
|
15
|
+
const userStore = useUserStore()
|
|
16
|
+
if (await userStore.checkAuth(true)) {
|
|
17
|
+
next({ name: 'home' })
|
|
18
|
+
} else {
|
|
19
|
+
next()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
13
22
|
},
|
|
14
23
|
{
|
|
15
24
|
path: '/resource/:resourceId',
|
|
@@ -49,4 +58,7 @@ const router = createRouter({
|
|
|
49
58
|
})
|
|
50
59
|
|
|
51
60
|
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
52
64
|
export default router
|
|
@@ -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
|
+
});
|
|
@@ -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;
|
|
@@ -52,6 +52,15 @@ export var AdminForthResourcePages;
|
|
|
52
52
|
AdminForthResourcePages["create"] = "create";
|
|
53
53
|
AdminForthResourcePages["filter"] = "filter";
|
|
54
54
|
})(AdminForthResourcePages || (AdminForthResourcePages = {}));
|
|
55
|
+
export var AllowedActionsEnum;
|
|
56
|
+
(function (AllowedActionsEnum) {
|
|
57
|
+
AllowedActionsEnum["show"] = "show";
|
|
58
|
+
AllowedActionsEnum["list"] = "list";
|
|
59
|
+
AllowedActionsEnum["edit"] = "edit";
|
|
60
|
+
AllowedActionsEnum["create"] = "create";
|
|
61
|
+
AllowedActionsEnum["delete"] = "delete";
|
|
62
|
+
AllowedActionsEnum["filter"] = "filter";
|
|
63
|
+
})(AllowedActionsEnum || (AllowedActionsEnum = {}));
|
|
55
64
|
export var AdminForthDataTypes;
|
|
56
65
|
(function (AdminForthDataTypes) {
|
|
57
66
|
AdminForthDataTypes["STRING"] = "string";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export var AlertVariant;
|
|
2
2
|
(function (AlertVariant) {
|
|
3
|
-
AlertVariant["
|
|
4
|
-
AlertVariant["
|
|
5
|
-
AlertVariant["
|
|
6
|
-
AlertVariant["
|
|
3
|
+
AlertVariant["danger"] = "danger";
|
|
4
|
+
AlertVariant["success"] = "success";
|
|
5
|
+
AlertVariant["warning"] = "warning";
|
|
6
|
+
AlertVariant["info"] = "info";
|
|
7
7
|
})(AlertVariant || (AlertVariant = {}));
|