diff --git a/api/v2/acl_config.go b/api/v2/acl_config.go index 6bf90478..8e9d7c38 100644 --- a/api/v2/acl_config.go +++ b/api/v2/acl_config.go @@ -7,6 +7,7 @@ var authenticationAllowlistMethods = map[string]bool{ "/memos.api.v2.AuthService/GetAuthStatus": true, "/memos.api.v2.UserService/GetUser": true, "/memos.api.v2.MemoService/ListMemos": true, + "/memos.api.v2.MemoService/GetMemo": true, "/memos.api.v2.MemoService/ListMemoResources": true, "/memos.api.v2.MemoService/ListMemoRelations": true, "/memos.api.v2.MemoService/ListMemoComments": true, diff --git a/web/src/pages/Archived.tsx b/web/src/pages/Archived.tsx index 6f5ff6d2..e795aedc 100644 --- a/web/src/pages/Archived.tsx +++ b/web/src/pages/Archived.tsx @@ -1,4 +1,5 @@ import { Tooltip } from "@mui/joy"; +import { ClientError } from "nice-grpc-web"; import { useEffect, useState } from "react"; import toast from "react-hot-toast"; import { showCommonDialog } from "@/components/Dialog/CommonDialog"; @@ -23,20 +24,18 @@ const Archived = () => { const [archivedMemos, setArchivedMemos] = useState([]); useEffect(() => { - memoServiceClient - .listMemos({ - filter: [`creator == "${user.name}"`, "row_status == 'ARCHIVED'"].join(" && "), - }) - .then(({ memos }) => { + (async () => { + try { + const filters = [`creator == "${user.name}"`, "row_status == 'ARCHIVED'"]; + const { memos } = await memoServiceClient.listMemos({ + filter: filters.join(" && "), + }); setArchivedMemos(memos); - }) - .catch((error) => { - console.error(error); - toast.error(error.response.data.message); - }) - .finally(() => { - loadingState.setFinish(); - }); + } catch (error: unknown) { + toast.error((error as ClientError).details); + } + loadingState.setFinish(); + })(); }, []); const handleDeleteMemoClick = async (memo: Memo) => { @@ -63,9 +62,9 @@ const Archived = () => { ); setArchivedMemos((prev) => prev.filter((m) => m.id !== memo.id)); toast(t("message.restored-successfully")); - } catch (error: any) { + } catch (error: unknown) { console.error(error); - toast.error(error.response.data.message); + toast.error((error as ClientError).details); } }; diff --git a/web/src/pages/MemoDetail.tsx b/web/src/pages/MemoDetail.tsx index 59f23441..c06c294f 100644 --- a/web/src/pages/MemoDetail.tsx +++ b/web/src/pages/MemoDetail.tsx @@ -1,5 +1,6 @@ import { Select, Tooltip, Option, IconButton } from "@mui/joy"; import copy from "copy-to-clipboard"; +import { ClientError } from "nice-grpc-web"; import { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { Link, useParams } from "react-router-dom"; @@ -35,7 +36,7 @@ const MemoDetail = () => { const [creator, setCreator] = useState(); const memoId = Number(params.memoId); const memo = memoStore.getMemoById(memoId); - const allowEdit = memo?.creatorId === currentUser.id; + const allowEdit = memo?.creatorId === currentUser?.id; const [parentMemo, setParentMemo] = useState(undefined); const referenceRelations = memo?.relations.filter((relation) => relation.type === MemoRelation_Type.REFERENCE) || []; const commentRelations = @@ -51,9 +52,9 @@ const MemoDetail = () => { const user = await userStore.getOrFetchUserByUsername(extractUsernameFromName(memo.creator)); setCreator(user); }) - .catch((error) => { - console.error(error); - toast.error(error.response.data.message); + .catch((error: ClientError) => { + toast.error(error.details); + navigateTo("/403"); }); } else { navigateTo("/404"); diff --git a/web/src/pages/PermissionDenied.tsx b/web/src/pages/PermissionDenied.tsx new file mode 100644 index 00000000..78867403 --- /dev/null +++ b/web/src/pages/PermissionDenied.tsx @@ -0,0 +1,15 @@ +import MobileHeader from "@/components/MobileHeader"; + +const PermissionDenied = () => { + return ( +
+ +
+

Permission denied

+

403

+
+
+ ); +}; + +export default PermissionDenied; diff --git a/web/src/router/index.tsx b/web/src/router/index.tsx index 40d03f65..39c23cea 100644 --- a/web/src/router/index.tsx +++ b/web/src/router/index.tsx @@ -18,6 +18,7 @@ const Resources = lazy(() => import("@/pages/Resources")); const Inboxes = lazy(() => import("@/pages/Inboxes")); const Setting = lazy(() => import("@/pages/Setting")); const NotFound = lazy(() => import("@/pages/NotFound")); +const PermissionDenied = lazy(() => import("@/pages/PermissionDenied")); const initialGlobalStateLoader = async () => { try { @@ -110,6 +111,14 @@ const router = createBrowserRouter([ path: "u/:username", element: , }, + { + path: "403", + element: , + }, + { + path: "404", + element: , + }, { path: "*", element: ,