diff --git a/policies/visualizer_dashboard.yaml b/policies/visualizer_dashboard.yaml new file mode 100644 index 0000000000..877827ebfe --- /dev/null +++ b/policies/visualizer_dashboard.yaml @@ -0,0 +1,9 @@ +apiVersion: api.cerbos.dev/v1 +resourcePolicy: + version: "default" + resource: "visualizer:dashboard" + rules: + - actions: ["read"] + effect: EFFECT_ALLOW + roles: + - role1 diff --git a/web/src/services/api/cerbosApi.ts b/web/src/services/api/cerbosApi.ts new file mode 100644 index 0000000000..95b16260b6 --- /dev/null +++ b/web/src/services/api/cerbosApi.ts @@ -0,0 +1,60 @@ +import { useState, useCallback } from "react"; + +import { useAuth } from "@reearth/services/auth"; + +export default () => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const { getAccessToken } = useAuth(); + + const checkPermission = useCallback( + async (resource: string, action: string) => { + setLoading(true); + setError(null); + + try { + const accessToken = await getAccessToken(); + + const response = await fetch("http://localhost:8090/api/graphql", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + body: JSON.stringify({ + query: ` + query CheckPermission($input: CheckPermissionInput!) { + checkPermission(input: $input) { + allowed + } + } + `, + variables: { + input: { + service: "visualizer", + resource, + action, + }, + }, + }), + }); + + const result = await response.json(); + setData(result.data); + } catch (err) { + setError(err as Error); + } finally { + setLoading(false); + } + }, + [getAccessToken], + ); + + return { + checkPermission, + data, + loading, + error, + }; +}; diff --git a/web/src/services/api/index.ts b/web/src/services/api/index.ts index c91c808634..e56b8c9c95 100644 --- a/web/src/services/api/index.ts +++ b/web/src/services/api/index.ts @@ -11,3 +11,4 @@ export { default as useStorytellingFetcher } from "./storytellingApi"; export { default as useLayerStylesFetcher } from "./layerStyleApi"; export { default as useFeatureCollectionFetcher } from "./featureCollectionApi"; export { default as useInfoboxFetcher } from "./infoboxApi"; +export { default as useCerbosFetcher } from "./cerbosApi"; diff --git a/web/src/services/theme/provider.tsx b/web/src/services/theme/provider.tsx index 3078687e72..a6fc1f0f0f 100644 --- a/web/src/services/theme/provider.tsx +++ b/web/src/services/theme/provider.tsx @@ -7,7 +7,7 @@ import { useAuth } from "@reearth/services/auth"; import { Theme } from "@reearth/services/gql"; import { useCurrentTheme } from "@reearth/services/state"; -import { useMeFetcher } from "../api"; +import { useMeFetcher, useCerbosFetcher } from "../api"; import GlobalStyle from "./reearthTheme/common/globalStyles"; import darkTheme from "./reearthTheme/darkTheme"; @@ -19,6 +19,7 @@ const Provider: React.FC<{ children?: ReactNode }> = ({ children }) => { const { useMeQuery } = useMeFetcher(); const { me } = useMeQuery({ skip: !isAuthenticated }); const themeType = me?.theme; + console.log(me); // TODO: switch theme by the system settings const actualThemeType = themeType === ("light" as Theme) ? "light" : "dark"; @@ -37,6 +38,26 @@ const Provider: React.FC<{ children?: ReactNode }> = ({ children }) => { ...darkTheme, }; + const { checkPermission, data, loading, error } = useCerbosFetcher(); + + useEffect(() => { + checkPermission("dashboard", "read"); + }, [checkPermission]); + + if (loading) { + return
Loading...
; + } + + if (error) { + return
Error: {error.message}
; + } + + console.log(data?.checkPermission?.allowed); + + if (!data?.checkPermission?.allowed) { + return
権限がありません。
; + } + return (