Skip to content

Commit 75d8376

Browse files
committed
feat: consolidate config fetching and handle unauthorized access with updated backend get_config logic
AdminForth/1877/login-page-improvements
1 parent 7655663 commit 75d8376

3 files changed

Lines changed: 49 additions & 30 deletions

File tree

adminforth/spa/src/App.vue

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ import AcceptModal from './components/AcceptModal.vue';
197197
import Sidebar from './components/Sidebar.vue';
198198
import { useRoute, useRouter } from 'vue-router';
199199
import { createHead } from 'unhead'
200-
import { getCustomComponent } from '@/utils';
200+
import { getCustomComponent, handleNotAuthorized } from '@/utils';
201201
import Toast from './components/Toast.vue';
202202
import {useToastStore} from '@/stores/toast';
203203
import { initFrontedAPI } from '@/adminforth';
@@ -271,6 +271,7 @@ async function initRouter() {
271271
routerIsReady.value = true;
272272
}
273273
274+
// used by Sidebar to reload menu, initial load is done by loadConfig below
274275
async function loadMenu() {
275276
await initRouter();
276277
if (route.meta.sidebarAndHeader !== 'none') {
@@ -280,6 +281,18 @@ async function loadMenu() {
280281
loginRedirectCheckIsReady.value = true;
281282
}
282283
284+
async function loadConfig() {
285+
const resp = await coreStore.fetchConfig({ redirectToLoginIfNotLoggedIn: false });
286+
publicConfigLoaded.value = true;
287+
288+
await initRouter();
289+
if (resp && !resp.loggedIn && route.meta.sidebarAndHeader !== 'none') {
290+
// for custom layouts we don't force login, they are allowed to be rendered for anonymous user
291+
await handleNotAuthorized();
292+
}
293+
loginRedirectCheckIsReady.value = true;
294+
}
295+
283296
function humanizeSnake(str: string): string {
284297
if (!str) {
285298
return '';
@@ -341,16 +354,9 @@ watch(dropdownUserButton, async (dropdownUserButton) => {
341354
}
342355
})
343356
344-
async function loadPublicConfig() {
345-
await coreStore.getPublicConfig();
346-
publicConfigLoaded.value = true;
347-
}
348-
349-
350357
// initialize components based on data attribute selectors
351358
onMounted(async () => {
352-
await loadPublicConfig(); // run this in async mode
353-
await loadMenu(); // and this
359+
await loadConfig();
354360
// before init flowbite we have to wait router initialized because it affects dom(our v-ifs) and fetch menu
355361
await initRouter();
356362
document.documentElement.setAttribute('data-theme', theme.value);

adminforth/spa/src/stores/core.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { ref, computed, onMounted, onUnmounted } from 'vue'
22
import { defineStore } from 'pinia'
3-
import { callAdminForthApi } from '@/utils';
3+
import { callAdminForthApi, handleNotAuthorized } from '@/utils';
44
import websocket from '@/websocket';
55
import { useAdminforth } from '@/adminforth';
66

7-
import type { AdminForthResourceCommon, AdminForthResourceColumnCommon, GetBaseConfigResponse, ResourceVeryShort, AdminUser, UserData, AdminForthConfigMenuItem, AdminForthConfigForFrontend, AdminForthResourceFrontend } from '@/types/Common';
7+
import type { AdminForthResourceCommon, AdminForthResourceColumnCommon, GetConfigResponse, ResourceVeryShort, AdminUser, UserData, AdminForthConfigMenuItem, AdminForthConfigForFrontend, AdminForthResourceFrontend } from '@/types/Common';
88
import type { Ref } from 'vue'
99

1010

@@ -75,25 +75,42 @@ export const useCoreStore = defineStore('core', () => {
7575
window.localStorage.setItem('af__theme', theme.value);
7676
}
7777

78-
async function fetchMenuAndResource() {
79-
const resp: GetBaseConfigResponse = await callAdminForthApi({
80-
path: '/get_base_config',
78+
79+
async function fetchConfig(
80+
{ redirectToLoginIfNotLoggedIn = true }: { redirectToLoginIfNotLoggedIn?: boolean } = {}
81+
): Promise<GetConfigResponse | null> {
82+
const resp: GetConfigResponse | null = await callAdminForthApi({
83+
path: '/get_config',
8184
method: 'GET',
8285
});
8386

8487
if(!resp){
85-
return
88+
return null
89+
}
90+
91+
config.value = { ...config.value, ...resp.config } as AdminForthConfigForFrontend;
92+
93+
if (!resp.loggedIn) {
94+
if (redirectToLoginIfNotLoggedIn) {
95+
await handleNotAuthorized();
96+
}
97+
return resp;
8698
}
99+
87100
menu.value = resp.menu;
88101
resourceById.value = resp.resources.reduce((acc: Record<string, ResourceVeryShort>, resource: ResourceVeryShort) => {
89102
acc[resource.resourceId] = resource;
90103
return acc;
91104
}, {});
92-
config.value = resp.config;
93105
adminUser.value = resp.adminUser;
94106
userData.value = resp.user;
95107
console.log('🌍 AdminForth v', resp.version);
96108
subscribeToMenuRefresh();
109+
return resp;
110+
}
111+
112+
async function fetchMenuAndResource() {
113+
await fetchConfig();
97114
}
98115

99116
async function refreshMenu() {
@@ -234,14 +251,6 @@ export const useCoreStore = defineStore('core', () => {
234251
isResourceFetching.value = false;
235252
}
236253

237-
async function getPublicConfig() {
238-
const res = await callAdminForthApi({
239-
path: '/get_public_config',
240-
method: 'GET',
241-
});
242-
config.value = {...config.value, ...res};
243-
}
244-
245254
async function getLoginFormConfig() {
246255
const res = await callAdminForthApi({
247256
path: '/get_login_form_config',
@@ -279,8 +288,8 @@ export const useCoreStore = defineStore('core', () => {
279288
username,
280289
userFullname,
281290
userAvatarUrl,
282-
getPublicConfig,
283-
fetchMenuAndResource,
291+
fetchConfig,
292+
fetchMenuAndResource,
284293
refreshMenu,
285294
getLoginFormConfig,
286295
fetchRecord,

adminforth/spa/src/utils/utils.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ async function tryAutologin(autologin: string): Promise<boolean> {
103103
return !!coreStore.adminUser;
104104
}
105105

106+
export async function handleNotAuthorized() {
107+
useUserStore().unauthorize();
108+
useCoreStore().resetAdminUser();
109+
await redirectToLogin();
110+
}
111+
106112
export async function redirectToLogin() {
107113
const currentPath = router.currentRoute.value.path;
108114
const homeRoute = router.getRoutes().find(route => route.name === 'home');
@@ -151,11 +157,9 @@ export async function callApi({path, method, body, headers, silentError = false,
151157
try {
152158
const r = await fetch(fullPath, options);
153159
if (r.status == 401 && !path.includes('/login')) {
154-
useUserStore().unauthorize();
155-
useCoreStore().resetAdminUser();
156-
await redirectToLogin();
160+
await handleNotAuthorized();
157161
return null;
158-
}
162+
}
159163
return await r.json();
160164
} catch(e) {
161165
if (e instanceof DOMException && e.name === 'AbortError') {

0 commit comments

Comments
 (0)