mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-02 21:38:48 +00:00
User roles state (#5685)
* Update for useApiState - Rename to useUserState - Include role information * Adds state method for checking user roles
This commit is contained in:
parent
89faf8e59d
commit
149e5c3696
@ -11,12 +11,12 @@ import { Link } from 'react-router-dom';
|
|||||||
|
|
||||||
import { doClassicLogout } from '../../functions/auth';
|
import { doClassicLogout } from '../../functions/auth';
|
||||||
import { InvenTreeStyle } from '../../globalStyle';
|
import { InvenTreeStyle } from '../../globalStyle';
|
||||||
import { useApiState } from '../../states/ApiState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import { PlaceholderPill } from '../items/Placeholder';
|
import { PlaceholderPill } from '../items/Placeholder';
|
||||||
|
|
||||||
export function MainMenu() {
|
export function MainMenu() {
|
||||||
const { classes, theme } = InvenTreeStyle();
|
const { classes, theme } = InvenTreeStyle();
|
||||||
const [username] = useApiState((state) => [state.user?.name]);
|
const [username] = useUserState((state) => [state.user?.name]);
|
||||||
return (
|
return (
|
||||||
<Menu width={260} position="bottom-end">
|
<Menu width={260} position="bottom-end">
|
||||||
<Menu.Target>
|
<Menu.Target>
|
||||||
|
@ -4,14 +4,10 @@ import { IconCheck } from '@tabler/icons-react';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import {
|
import { ApiPaths, url, useServerApiState } from '../states/ApiState';
|
||||||
ApiPaths,
|
|
||||||
url,
|
|
||||||
useApiState,
|
|
||||||
useServerApiState
|
|
||||||
} from '../states/ApiState';
|
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
import { useSessionState } from '../states/SessionState';
|
import { useSessionState } from '../states/SessionState';
|
||||||
|
import { useUserState } from '../states/UserState';
|
||||||
|
|
||||||
export const doClassicLogin = async (username: string, password: string) => {
|
export const doClassicLogin = async (username: string, password: string) => {
|
||||||
const { host } = useLocalState.getState();
|
const { host } = useLocalState.getState();
|
||||||
@ -62,11 +58,11 @@ export const doSimpleLogin = async (email: string) => {
|
|||||||
|
|
||||||
export const doTokenLogin = (token: string) => {
|
export const doTokenLogin = (token: string) => {
|
||||||
const { setToken } = useSessionState.getState();
|
const { setToken } = useSessionState.getState();
|
||||||
const { fetchApiState } = useApiState.getState();
|
const { fetchUserState } = useUserState.getState();
|
||||||
const { fetchServerApiState } = useServerApiState.getState();
|
const { fetchServerApiState } = useServerApiState.getState();
|
||||||
|
|
||||||
setToken(token);
|
setToken(token);
|
||||||
fetchApiState();
|
fetchUserState();
|
||||||
fetchServerApiState();
|
fetchServerApiState();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
WidgetLayout
|
WidgetLayout
|
||||||
} from '../../components/widgets/WidgetLayout';
|
} from '../../components/widgets/WidgetLayout';
|
||||||
import { LoadingItem } from '../../functions/loading';
|
import { LoadingItem } from '../../functions/loading';
|
||||||
import { useApiState } from '../../states/ApiState';
|
import { useUserState } from '../../states/UserState';
|
||||||
|
|
||||||
const vals: LayoutItemType[] = [
|
const vals: LayoutItemType[] = [
|
||||||
{
|
{
|
||||||
@ -51,7 +51,7 @@ const vals: LayoutItemType[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [username] = useApiState((state) => [state.user?.name]);
|
const [username] = useUserState((state) => [state.user?.name]);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title order={1}>
|
<Title order={1}>
|
||||||
|
@ -4,13 +4,16 @@ import { api } from '../App';
|
|||||||
import { emptyServerAPI } from '../defaults/defaults';
|
import { emptyServerAPI } from '../defaults/defaults';
|
||||||
import { ServerAPIProps, UserProps } from './states';
|
import { ServerAPIProps, UserProps } from './states';
|
||||||
|
|
||||||
interface ApiStateProps {
|
interface UserStateProps {
|
||||||
user: UserProps | undefined;
|
user: UserProps | undefined;
|
||||||
setUser: (newUser: UserProps) => void;
|
setUser: (newUser: UserProps) => void;
|
||||||
fetchApiState: () => void;
|
fetchApiState: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useApiState = create<ApiStateProps>((set, get) => ({
|
/**
|
||||||
|
* Global user information state, using Zustand manager
|
||||||
|
*/
|
||||||
|
export const useApiState = create<UserStateProps>((set, get) => ({
|
||||||
user: undefined,
|
user: undefined,
|
||||||
setUser: (newUser: UserProps) => set({ user: newUser }),
|
setUser: (newUser: UserProps) => set({ user: newUser }),
|
||||||
fetchApiState: async () => {
|
fetchApiState: async () => {
|
||||||
@ -45,6 +48,7 @@ export const useServerApiState = create<ServerApiStateProps>((set, get) => ({
|
|||||||
|
|
||||||
export enum ApiPaths {
|
export enum ApiPaths {
|
||||||
user_me = 'api-user-me',
|
user_me = 'api-user-me',
|
||||||
|
user_roles = 'api-user-roles',
|
||||||
user_token = 'api-user-token',
|
user_token = 'api-user-token',
|
||||||
user_simple_login = 'api-user-simple-login',
|
user_simple_login = 'api-user-simple-login',
|
||||||
user_reset = 'api-user-reset',
|
user_reset = 'api-user-reset',
|
||||||
@ -64,6 +68,8 @@ export function url(path: ApiPaths, pk?: any): string {
|
|||||||
switch (path) {
|
switch (path) {
|
||||||
case ApiPaths.user_me:
|
case ApiPaths.user_me:
|
||||||
return 'user/me/';
|
return 'user/me/';
|
||||||
|
case ApiPaths.user_roles:
|
||||||
|
return 'user/roles/';
|
||||||
case ApiPaths.user_token:
|
case ApiPaths.user_token:
|
||||||
return 'user/token/';
|
return 'user/token/';
|
||||||
case ApiPaths.user_simple_login:
|
case ApiPaths.user_simple_login:
|
||||||
|
59
src/frontend/src/states/UserState.tsx
Normal file
59
src/frontend/src/states/UserState.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
import { api } from '../App';
|
||||||
|
import { ApiPaths, url } from './ApiState';
|
||||||
|
import { UserProps } from './states';
|
||||||
|
|
||||||
|
interface UserStateProps {
|
||||||
|
user: UserProps | undefined;
|
||||||
|
setUser: (newUser: UserProps) => void;
|
||||||
|
fetchUserState: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global user information state, using Zustand manager
|
||||||
|
*/
|
||||||
|
export const useUserState = create<UserStateProps>((set, get) => ({
|
||||||
|
user: undefined,
|
||||||
|
setUser: (newUser: UserProps) => set({ user: newUser }),
|
||||||
|
fetchUserState: async () => {
|
||||||
|
// Fetch user data
|
||||||
|
await api
|
||||||
|
.get(url(ApiPaths.user_me))
|
||||||
|
.then((response) => {
|
||||||
|
const user: UserProps = {
|
||||||
|
name: `${response.data.first_name} ${response.data.last_name}`,
|
||||||
|
email: response.data.email,
|
||||||
|
username: response.data.username
|
||||||
|
};
|
||||||
|
set({ user: user });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching user data:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch role data
|
||||||
|
await api
|
||||||
|
.get(url(ApiPaths.user_roles))
|
||||||
|
.then((response) => {
|
||||||
|
const user: UserProps = get().user as UserProps;
|
||||||
|
user.roles = response.data.roles;
|
||||||
|
user.is_staff = response.data.is_staff ?? false;
|
||||||
|
user.is_superuser = response.data.is_superuser ?? false;
|
||||||
|
set({ user: user });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching user roles:', error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
checkUserRole: (role: string, permission: string) => {
|
||||||
|
// Check if the user has the specified permission for the specified role
|
||||||
|
const user: UserProps = get().user as UserProps;
|
||||||
|
|
||||||
|
if (user.is_superuser) return true;
|
||||||
|
if (user.roles === undefined) return false;
|
||||||
|
if (user.roles[role] === undefined) return false;
|
||||||
|
|
||||||
|
return user.roles[role].includes(permission);
|
||||||
|
}
|
||||||
|
}));
|
@ -7,12 +7,17 @@ export interface HostList {
|
|||||||
[key: string]: Host;
|
[key: string]: Host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type interface fully defining the current user
|
||||||
export interface UserProps {
|
export interface UserProps {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
is_staff?: boolean;
|
||||||
|
is_superuser?: boolean;
|
||||||
|
roles?: Record<string, string[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type interface fully defining the current server
|
||||||
export interface ServerAPIProps {
|
export interface ServerAPIProps {
|
||||||
server: null | string;
|
server: null | string;
|
||||||
version: null | string;
|
version: null | string;
|
||||||
|
@ -7,13 +7,13 @@ import { BaseContext } from '../contexts/BaseContext';
|
|||||||
import { defaultHostList } from '../defaults/defaultHostList';
|
import { defaultHostList } from '../defaults/defaultHostList';
|
||||||
import { url_base } from '../main';
|
import { url_base } from '../main';
|
||||||
import { routes } from '../router';
|
import { routes } from '../router';
|
||||||
import { useApiState } from '../states/ApiState';
|
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
import { useSessionState } from '../states/SessionState';
|
import { useSessionState } from '../states/SessionState';
|
||||||
|
import { useUserState } from '../states/UserState';
|
||||||
|
|
||||||
export default function DesktopAppView() {
|
export default function DesktopAppView() {
|
||||||
const [hostList] = useLocalState((state) => [state.hostList]);
|
const [hostList] = useLocalState((state) => [state.hostList]);
|
||||||
const [fetchApiState] = useApiState((state) => [state.fetchApiState]);
|
const [fetchUserState] = useUserState((state) => [state.fetchUserState]);
|
||||||
|
|
||||||
// Local state initialization
|
// Local state initialization
|
||||||
if (Object.keys(hostList).length === 0) {
|
if (Object.keys(hostList).length === 0) {
|
||||||
@ -29,7 +29,7 @@ export default function DesktopAppView() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token && !fetchedServerSession) {
|
if (token && !fetchedServerSession) {
|
||||||
setFetchedServerSession(true);
|
setFetchedServerSession(true);
|
||||||
fetchApiState();
|
fetchUserState();
|
||||||
}
|
}
|
||||||
}, [token, fetchedServerSession]);
|
}, [token, fetchedServerSession]);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user