From b4838562d0f357975301c32e004f55ecef873e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 11 Mar 2026 11:41:29 +0100 Subject: [PATCH 1/5] Redirect to user profile page on 403 status code --- Cargo.lock | 4 ++-- web/src/shared/api/api-client.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f52b7a1907..fc5217cc04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7949,9 +7949,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe" +checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" dependencies = [ "zune-core", ] diff --git a/web/src/shared/api/api-client.ts b/web/src/shared/api/api-client.ts index b7d3fe21bd..fe83141bb0 100644 --- a/web/src/shared/api/api-client.ts +++ b/web/src/shared/api/api-client.ts @@ -1,5 +1,7 @@ import axios from 'axios'; import qs from 'qs'; +import { router } from '../../app/router'; +import { useAuth } from '../hooks/useAuth'; export const client = axios.create({ baseURL: '/api/v1', @@ -11,3 +13,27 @@ export const client = axios.create({ }), }, }); + +client.interceptors.response.use( + (response) => response, + async (error) => { + if (axios.isAxiosError(error) && error.response?.status === 403) { + const username = useAuth.getState().user?.username; + + if (username) { + const currentPath = router.state.location.pathname; + const profilePath = `/user/${username}`; + + if (currentPath !== profilePath) { + await router.navigate({ + to: '/user/$username', + params: { username }, + replace: true, + }); + } + } + } + + return Promise.reject(error); + }, +); From d1d3b230ca694272762b33c2d5286bbe9f492c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 11 Mar 2026 11:54:26 +0100 Subject: [PATCH 2/5] Better fix? --- web/src/routes/_authorized/_default.tsx | 24 +++++++++++++++++++++++- web/src/shared/api/api-client.ts | 23 +---------------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/web/src/routes/_authorized/_default.tsx b/web/src/routes/_authorized/_default.tsx index 6fe0e92133..d1b3ab38ff 100644 --- a/web/src/routes/_authorized/_default.tsx +++ b/web/src/routes/_authorized/_default.tsx @@ -1,7 +1,29 @@ -import { createFileRoute, Outlet } from '@tanstack/react-router'; +import { createFileRoute, Outlet, redirect } from '@tanstack/react-router'; import { Navigation } from '../../shared/components/Navigation/Navigation'; +import { getSessionInfoQueryOptions, getUserMeQueryOptions } from '../../shared/query'; export const Route = createFileRoute('/_authorized/_default')({ + beforeLoad: async ({ context, location }) => { + const sessionInfo = ( + await context.queryClient.ensureQueryData(getSessionInfoQueryOptions) + ).data; + + if (sessionInfo.is_admin) { + return; + } + + const me = (await context.queryClient.ensureQueryData(getUserMeQueryOptions)).data; + + if (location.pathname !== `/user/${me.username}`) { + throw redirect({ + to: '/user/$username', + params: { + username: me.username, + }, + replace: true, + }); + } + }, component: RouteComponent, }); diff --git a/web/src/shared/api/api-client.ts b/web/src/shared/api/api-client.ts index fe83141bb0..c8b1d22406 100644 --- a/web/src/shared/api/api-client.ts +++ b/web/src/shared/api/api-client.ts @@ -1,7 +1,5 @@ import axios from 'axios'; import qs from 'qs'; -import { router } from '../../app/router'; -import { useAuth } from '../hooks/useAuth'; export const client = axios.create({ baseURL: '/api/v1', @@ -16,24 +14,5 @@ export const client = axios.create({ client.interceptors.response.use( (response) => response, - async (error) => { - if (axios.isAxiosError(error) && error.response?.status === 403) { - const username = useAuth.getState().user?.username; - - if (username) { - const currentPath = router.state.location.pathname; - const profilePath = `/user/${username}`; - - if (currentPath !== profilePath) { - await router.navigate({ - to: '/user/$username', - params: { username }, - replace: true, - }); - } - } - } - - return Promise.reject(error); - }, + (error) => Promise.reject(error), ); From 205cb0b9eacd0138a19c9e6e18925b14325030b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 11 Mar 2026 12:01:01 +0100 Subject: [PATCH 3/5] Change to fetchQuery --- web/src/routes/_authorized/_default.tsx | 2 +- web/src/shared/api/api-client.ts | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/web/src/routes/_authorized/_default.tsx b/web/src/routes/_authorized/_default.tsx index d1b3ab38ff..808ef91c1f 100644 --- a/web/src/routes/_authorized/_default.tsx +++ b/web/src/routes/_authorized/_default.tsx @@ -12,7 +12,7 @@ export const Route = createFileRoute('/_authorized/_default')({ return; } - const me = (await context.queryClient.ensureQueryData(getUserMeQueryOptions)).data; + const me = (await context.queryClient.fetchQuery(getUserMeQueryOptions)).data; if (location.pathname !== `/user/${me.username}`) { throw redirect({ diff --git a/web/src/shared/api/api-client.ts b/web/src/shared/api/api-client.ts index c8b1d22406..b7d3fe21bd 100644 --- a/web/src/shared/api/api-client.ts +++ b/web/src/shared/api/api-client.ts @@ -11,8 +11,3 @@ export const client = axios.create({ }), }, }); - -client.interceptors.response.use( - (response) => response, - (error) => Promise.reject(error), -); From f6550380195a4daca5ec3b6d473c4d12ed188a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 11 Mar 2026 12:20:12 +0100 Subject: [PATCH 4/5] Change to fetchQuery --- web/src/routes/_authorized/_default.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/src/routes/_authorized/_default.tsx b/web/src/routes/_authorized/_default.tsx index 808ef91c1f..9a0e6f8e38 100644 --- a/web/src/routes/_authorized/_default.tsx +++ b/web/src/routes/_authorized/_default.tsx @@ -4,9 +4,8 @@ import { getSessionInfoQueryOptions, getUserMeQueryOptions } from '../../shared/ export const Route = createFileRoute('/_authorized/_default')({ beforeLoad: async ({ context, location }) => { - const sessionInfo = ( - await context.queryClient.ensureQueryData(getSessionInfoQueryOptions) - ).data; + const sessionInfo = (await context.queryClient.fetchQuery(getSessionInfoQueryOptions)) + .data; if (sessionInfo.is_admin) { return; From aaac205bf2f0340a7355e93cf7f1bbda6844d71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 11 Mar 2026 12:30:35 +0100 Subject: [PATCH 5/5] Move to _authorized.tsx --- web/src/routes/_authorized.tsx | 18 +++++++++++++++++- web/src/routes/_authorized/_default.tsx | 23 +---------------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/web/src/routes/_authorized.tsx b/web/src/routes/_authorized.tsx index 5414bcfa4b..3cb8ae7321 100644 --- a/web/src/routes/_authorized.tsx +++ b/web/src/routes/_authorized.tsx @@ -8,7 +8,7 @@ import { UpgradeEnterpriseModal } from '../shared/components/modals/license/Upgr import { SelectionModal } from '../shared/components/modals/SelectionModal/SelectionModal'; import { AppInfoProvider } from '../shared/providers/AppInfoProvider'; import { AppUserProvider } from '../shared/providers/AppUserProvider'; -import { getSessionInfoQueryOptions } from '../shared/query'; +import { getSessionInfoQueryOptions, getUserMeQueryOptions } from '../shared/query'; export const Route = createFileRoute('/_authorized')({ component: RouteComponent, @@ -27,6 +27,22 @@ export const Route = createFileRoute('/_authorized')({ throw redirect({ to: '/migration', replace: true }); } } + + if (sessionInfo.is_admin) { + return; + } + + const me = (await context.queryClient.fetchQuery(getUserMeQueryOptions)).data; + + if (location.pathname !== `/user/${me.username}`) { + throw redirect({ + to: '/user/$username', + params: { + username: me.username, + }, + replace: true, + }); + } }, }); diff --git a/web/src/routes/_authorized/_default.tsx b/web/src/routes/_authorized/_default.tsx index 9a0e6f8e38..6fe0e92133 100644 --- a/web/src/routes/_authorized/_default.tsx +++ b/web/src/routes/_authorized/_default.tsx @@ -1,28 +1,7 @@ -import { createFileRoute, Outlet, redirect } from '@tanstack/react-router'; +import { createFileRoute, Outlet } from '@tanstack/react-router'; import { Navigation } from '../../shared/components/Navigation/Navigation'; -import { getSessionInfoQueryOptions, getUserMeQueryOptions } from '../../shared/query'; export const Route = createFileRoute('/_authorized/_default')({ - beforeLoad: async ({ context, location }) => { - const sessionInfo = (await context.queryClient.fetchQuery(getSessionInfoQueryOptions)) - .data; - - if (sessionInfo.is_admin) { - return; - } - - const me = (await context.queryClient.fetchQuery(getUserMeQueryOptions)).data; - - if (location.pathname !== `/user/${me.username}`) { - throw redirect({ - to: '/user/$username', - params: { - username: me.username, - }, - replace: true, - }); - } - }, component: RouteComponent, });