Compare commits
4 Commits
ef9ae99cb6
...
75ff63a529
| Author | SHA1 | Date | |
|---|---|---|---|
| 75ff63a529 | |||
| b04ee4cb92 | |||
| 4e613554e6 | |||
| d1718becde |
@@ -67,7 +67,7 @@ class AuthenticationBackendMe(AuthenticationBackend):
|
||||
|
||||
class CookieTransportOauth(CookieTransport):
|
||||
async def get_login_response(self, token: str) -> Response:
|
||||
response = RedirectResponse("/login?oauth=success", status_code=status.HTTP_301_MOVED_PERMANENTLY)
|
||||
response = RedirectResponse("/auth/login?oauth=success", status_code=status.HTTP_301_MOVED_PERMANENTLY)
|
||||
return self._set_login_cookie(response, token)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -5,25 +5,29 @@ from pymongo import IndexModel
|
||||
from hub.core import CrudDocument
|
||||
|
||||
class Firm(CrudDocument):
|
||||
name: str = Field()
|
||||
instance: str = Field()
|
||||
firm: str = Field()
|
||||
owner: PydanticObjectId = Field()
|
||||
|
||||
@classmethod
|
||||
def get_by_name(cls, instance, firm):
|
||||
return cls.find_one({"instance": instance, "firm": firm})
|
||||
|
||||
def compute_label(self) -> str:
|
||||
return self.name
|
||||
return f"{self.instance} / {self.firm}"
|
||||
|
||||
class Settings:
|
||||
indexes = [
|
||||
IndexModel(["name", "instance"], unique=True),
|
||||
IndexModel(["instance", "firm"], unique=True),
|
||||
]
|
||||
|
||||
class FirmRead(BaseModel):
|
||||
instance: str = Field()
|
||||
name: str = Field()
|
||||
firm: str = Field()
|
||||
|
||||
class FirmCreate(FirmRead):
|
||||
instance: str = Field(max_length=32, min_length=3, pattern="^[0-9a-z-]+$")
|
||||
name: str = Field(max_length=32, min_length=3, pattern="^[0-9a-z-]+$")
|
||||
firm: str = Field(max_length=32, min_length=3, pattern="^[0-9a-z-]+$")
|
||||
|
||||
class FirmUpdate(BaseModel):
|
||||
owner: PydanticObjectId = Field()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from beanie import PydanticObjectId
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
|
||||
from hub.auth import get_current_user
|
||||
@@ -7,42 +6,41 @@ from hub.firm import Firm, FirmRead, FirmCreate, FirmUpdate
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/", response_model=list[FirmRead], response_description="{} records retrieved".format(Firm.__name__))
|
||||
@router.get("/", response_model=list[FirmRead], response_description="List of firms owned by the current user")
|
||||
async def read_list(user=Depends(get_current_user)) -> list[FirmRead]:
|
||||
return await Firm.find({ "owner": user.id}).to_list()
|
||||
|
||||
@router.post("/", response_description="{} added to the database".format(Firm.__name__))
|
||||
@router.post("/", response_description="Firm added to the database")
|
||||
async def create(item: FirmCreate, user=Depends(get_current_user)) -> FirmRead:
|
||||
firm_dict = {"name": item.name, "instance": item.instance}
|
||||
exists = await Firm.find_one(firm_dict)
|
||||
exists = await Firm.get_by_name(item.instance, item.firm)
|
||||
if exists:
|
||||
raise HTTPException(status_code=400, detail="Firm already exists")
|
||||
|
||||
record = Firm(created_by=user.id, updated_by=user.id, owner=user.id, **item.model_dump())
|
||||
o = await record.create()
|
||||
user.firms.append(firm_dict)
|
||||
user.firms.append({"instance": item.instance, "firm": item.firm})
|
||||
await user.save()
|
||||
return FirmRead(**o.model_dump())
|
||||
|
||||
@router.get("/{id}", response_description="{} record retrieved".format(Firm.__name__))
|
||||
async def read_id(id: PydanticObjectId, user=Depends(get_current_user)) -> FirmRead:
|
||||
item = await Firm.get(id)
|
||||
@router.get("/{instance}/{firm}", response_description="Firm retrieved")
|
||||
async def read_id(instance: str, firm: str, user=Depends(get_current_user)) -> FirmRead:
|
||||
item = await Firm.get_by_name(instance, firm)
|
||||
if not item or not user.belong_to(item) not in user.firms:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
|
||||
return FirmRead(**item.model_dump())
|
||||
|
||||
|
||||
@router.put("/{id}", response_description="{} record updated".format(Firm.__name__))
|
||||
async def update(id: PydanticObjectId, req: FirmUpdate, user=Depends(get_current_user)) -> FirmRead:
|
||||
item = await Firm.get(id)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="{} record not found!".format(Firm.__name__)
|
||||
)
|
||||
@router.put("/{instance}/{firm}", response_description="Firm updated")
|
||||
async def update(instance: str, firm: str, req: FirmUpdate, user=Depends(get_current_user)) -> FirmRead:
|
||||
item = await Firm.get_by_name(instance, firm)
|
||||
if not item or not user.belong_to(item) not in user.firms:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
|
||||
if item.owner != user.id:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="Insufficient credentials to modify {} record".format(Firm.__name__)
|
||||
detail="Insufficient credentials to modify Firm"
|
||||
)
|
||||
|
||||
req = {k: v for k, v in req.model_dump().items() if v is not None}
|
||||
@@ -53,21 +51,19 @@ async def update(id: PydanticObjectId, req: FirmUpdate, user=Depends(get_current
|
||||
await item.update(update_query)
|
||||
return FirmRead(**item.dict())
|
||||
|
||||
@router.delete("/{id}", response_description="{} record deleted from the database".format(Firm.__name__))
|
||||
async def delete(id: PydanticObjectId, user=Depends(get_current_user)) -> dict:
|
||||
item = await Firm.get(id)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="{} record not found!".format(Firm.__name__)
|
||||
)
|
||||
@router.delete("/{instance}/{firm}", response_description="Firm deleted from the database")
|
||||
async def delete(instance: str, firm: str, user=Depends(get_current_user)) -> dict:
|
||||
item = await Firm.get_by_name(instance, firm)
|
||||
if not item or not user.belong_to(item) not in user.firms:
|
||||
raise HTTPException(status_code=404, detail="Firm not found")
|
||||
|
||||
if item.owner != user.id:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="Insufficient credentials delete {} record".format(Firm.__name__)
|
||||
detail="Insufficient credentials delete Firm"
|
||||
)
|
||||
|
||||
await item.delete()
|
||||
return {
|
||||
"message": "{} deleted successfully".format(Firm.__name__)
|
||||
"message": "Firm deleted successfully"
|
||||
}
|
||||
|
||||
@@ -8,5 +8,11 @@ from hub.firm import FirmRead
|
||||
class UserSchema(BaseUser[PydanticObjectId]):
|
||||
firms: list[FirmRead] = Field()
|
||||
|
||||
def belongs_to(self, firm):
|
||||
for f in self.firms:
|
||||
if f.instance == firm.instance and f.firm == firm.firm :
|
||||
return True
|
||||
return False
|
||||
|
||||
class UserUpdateSchema(BaseUserUpdate):
|
||||
pass
|
||||
|
||||
@@ -23,8 +23,8 @@ import { ForgotPassword } from "./components/auth/ForgotPassword";
|
||||
import { UpdatePassword } from "./components/auth/UpdatePassword";
|
||||
|
||||
import { Header } from "./components";
|
||||
import { Hub } from "./pages/hub";
|
||||
import { CreateFirm } from "./pages/hub/CreateFirm";
|
||||
import { HubRoutes } from "./pages/hub";
|
||||
import { FirmRoutes } from "./pages/firm";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
@@ -43,26 +43,42 @@ function App() {
|
||||
syncWithLocation: true,
|
||||
warnWhenUnsavedChanges: true,
|
||||
useNewQueryKeys: true,
|
||||
disableTelemetry: true
|
||||
disableTelemetry: true,
|
||||
reactQuery: {
|
||||
clientConfig: {
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: (failureCount, error) => {
|
||||
// @ts-ignore
|
||||
if (error.status >= 400 && error.status <= 499) {
|
||||
return false
|
||||
}
|
||||
return failureCount < 4
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Header />
|
||||
<Routes>
|
||||
<Route
|
||||
element={(
|
||||
<Authenticated key="authenticated-routes" redirectOnFail="/login" fallback={<CatchAllNavigate to="/login"/>}>
|
||||
<Authenticated key="authenticated-routes" redirectOnFail="/auth/login" fallback={<CatchAllNavigate to="/auth/login"/>}>
|
||||
<Outlet />
|
||||
</Authenticated>
|
||||
)}
|
||||
>
|
||||
<Route path="/hub" element={ <Hub /> } />
|
||||
<Route path="/hub/create-firm" element={ <CreateFirm /> } />
|
||||
<Route path="hub/*" element={<HubRoutes />} />
|
||||
<Route path="firm/*" element={<FirmRoutes />} />
|
||||
</Route>
|
||||
<Route index element={<h1>HOME <Link to={"/login"}>Login</Link></h1>} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/register" element={<Register />} />
|
||||
<Route path="/forgot-password" element={<ForgotPassword />} />
|
||||
<Route path="/update-password" element={<UpdatePassword />} />
|
||||
<Route path="auth/*" element={<><Header /><Outlet /></>}>
|
||||
<Route path="login" element={<Login />} />
|
||||
<Route path="register" element={<Register />} />
|
||||
<Route path="forgot-password" element={<ForgotPassword />} />
|
||||
<Route path="update-password" element={<UpdatePassword />} />
|
||||
</Route>
|
||||
<Route index element={<><Header /><h1>HOME </h1></>} />
|
||||
</Routes>
|
||||
<UnsavedChangesNotifier />
|
||||
<DocumentTitleHandler />
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Button } from "@mui/material";
|
||||
import { useLogout } from "@refinedev/core";
|
||||
|
||||
export const Logout = () => {
|
||||
const { mutate: logout } = useLogout();
|
||||
|
||||
return <button onClick={() => logout()} >Logout</button>;
|
||||
return <Button onClick={() => logout()} >Logout</Button>;
|
||||
};
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import DarkModeOutlined from "@mui/icons-material/DarkModeOutlined";
|
||||
import LightModeOutlined from "@mui/icons-material/LightModeOutlined";
|
||||
import HubIcon from '@mui/icons-material/Hub';
|
||||
import { Button, Menu, MenuItem } from "@mui/material";
|
||||
import AppBar from "@mui/material/AppBar";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import React, { useContext } from "react";
|
||||
import { Link } from "react-router";
|
||||
import { useGetIdentity } from "@refinedev/core";
|
||||
import { HamburgerMenu, RefineThemedLayoutV2HeaderProps } from "@refinedev/mui";
|
||||
import React, { useContext } from "react";
|
||||
import { ColorModeContext } from "../../contexts/color-mode";
|
||||
import { FirmContext } from "../../contexts/FirmContext";
|
||||
import { Logout } from "../auth/Logout";
|
||||
import { IUser } from "../../interfaces";
|
||||
|
||||
@@ -17,34 +21,41 @@ export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({
|
||||
sticky = true,
|
||||
}) => {
|
||||
const { mode, setMode } = useContext(ColorModeContext);
|
||||
const { currentFirm } = useContext(FirmContext);
|
||||
|
||||
const { data: user } = useGetIdentity<IUser>();
|
||||
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const openUserMenu = Boolean(anchorEl);
|
||||
const handleOpenUserMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
}
|
||||
const handleCloseUserMenu = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<AppBar position={sticky ? "sticky" : "relative"}>
|
||||
<Toolbar>
|
||||
<Stack
|
||||
direction="row"
|
||||
width="100%"
|
||||
justifyContent="flex-end"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<HamburgerMenu />
|
||||
{currentFirm && (
|
||||
<Link to={`/firm/${currentFirm.instance}/${currentFirm.firm}`} ><Typography variant="h4" >{currentFirm.instance} / {currentFirm.firm}</Typography></Link>
|
||||
)}
|
||||
{!currentFirm && (
|
||||
<Link to="/" ><Typography variant="h4">Roleplay Contracts</Typography></Link>
|
||||
)}
|
||||
<Link to="/hub"><HubIcon /></Link>
|
||||
<Stack
|
||||
direction="row"
|
||||
width="100%"
|
||||
justifyContent="flex-end"
|
||||
alignItems="center"
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() => {
|
||||
setMode();
|
||||
}}
|
||||
>
|
||||
{mode === "dark" ? <LightModeOutlined /> : <DarkModeOutlined />}
|
||||
</IconButton>
|
||||
|
||||
{(user?.email) && (
|
||||
<Stack
|
||||
direction="row"
|
||||
@@ -52,7 +63,12 @@ export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
{user?.email && (
|
||||
<Button
|
||||
id="user-menu-button"
|
||||
aria-controls={openUserMenu ? 'user-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={openUserMenu ? 'true' : undefined}
|
||||
onClick={handleOpenUserMenu}>
|
||||
<Typography
|
||||
sx={{
|
||||
display: {
|
||||
@@ -63,12 +79,36 @@ export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({
|
||||
variant="subtitle2"
|
||||
>
|
||||
{user?.email}
|
||||
</Typography>
|
||||
)}
|
||||
</Typography>
|
||||
<Avatar src={"user?.avatar"} alt={user?.email} />
|
||||
<Logout />
|
||||
</Button>
|
||||
<Menu
|
||||
id="user-menu"
|
||||
anchorEl={anchorEl}
|
||||
open={openUserMenu}
|
||||
onClose={handleCloseUserMenu}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'user-menu-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleCloseUserMenu}><Logout /></MenuItem>
|
||||
<MenuItem onClick={handleCloseUserMenu}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() => {
|
||||
setMode();
|
||||
}}
|
||||
>
|
||||
{mode === "dark" ? <LightModeOutlined /> : <DarkModeOutlined />}
|
||||
</IconButton>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
{!user && (
|
||||
<Link to="/auth/login"><Button>Login</Button></Link>
|
||||
)}
|
||||
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Toolbar>
|
||||
|
||||
25
gui/rpk-gui/src/contexts/FirmContext.tsx
Normal file
25
gui/rpk-gui/src/contexts/FirmContext.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import React, { createContext, PropsWithChildren } from 'react';
|
||||
import { IFirm } from "../interfaces";
|
||||
import { useParams } from "react-router";
|
||||
|
||||
type FirmContextType = {
|
||||
currentFirm: IFirm,
|
||||
}
|
||||
|
||||
export const FirmContext = createContext<FirmContextType>(
|
||||
{} as FirmContextType
|
||||
);
|
||||
|
||||
|
||||
export const FirmContextProvider: React.FC<PropsWithChildren> = ({ children }: PropsWithChildren) => {
|
||||
const { instance, firm } = useParams<IFirm>()
|
||||
|
||||
if (instance === undefined || firm === undefined) {
|
||||
return "Error"
|
||||
}
|
||||
return (
|
||||
<FirmContext.Provider value={{currentFirm: {instance, firm}}} >
|
||||
{ children }
|
||||
</FirmContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
export type IFirm = {
|
||||
instance: string,
|
||||
name: string
|
||||
firm: string
|
||||
}
|
||||
|
||||
type User = {
|
||||
|
||||
28
gui/rpk-gui/src/pages/firm/index.tsx
Normal file
28
gui/rpk-gui/src/pages/firm/index.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import {Route, Routes} from "react-router";
|
||||
import React, { useContext } from "react";
|
||||
import { FirmContext, FirmContextProvider } from "../../contexts/FirmContext";
|
||||
import { Header } from "../../components";
|
||||
|
||||
export const FirmRoutes = () => {
|
||||
return (
|
||||
<>
|
||||
<Routes>
|
||||
<Route path="/:instance/:firm/*" element={
|
||||
<FirmContextProvider>
|
||||
<Header />
|
||||
<Routes>
|
||||
<Route index element={ <FirmHome /> } />
|
||||
</Routes>
|
||||
</FirmContextProvider>
|
||||
} />
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const FirmHome = () => {
|
||||
const { currentFirm } = useContext(FirmContext);
|
||||
return (
|
||||
<h1>This is la firme {currentFirm.instance} / {currentFirm.firm}</h1>
|
||||
);
|
||||
}
|
||||
@@ -1,38 +1,53 @@
|
||||
import { Button } from "@mui/material";
|
||||
import { Link } from "react-router";
|
||||
import ExitToAppIcon from '@mui/icons-material/ExitToApp';
|
||||
import React from 'react';
|
||||
import {Link, Route, Routes} from "react-router";
|
||||
import { useGetIdentity, useList } from "@refinedev/core";
|
||||
import { IAuthUser, IFirm } from "../../interfaces";
|
||||
import {CreateFirm} from "./CreateFirm";
|
||||
import {Header} from "../../components";
|
||||
|
||||
|
||||
export const Hub = () => {
|
||||
export const HubRoutes = () => {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<Routes>
|
||||
<Route index element={ <HubHome /> } />
|
||||
<Route path="create-firm" element={ <CreateFirm /> } />
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const HubHome = () => {
|
||||
const { data: user } = useGetIdentity<IAuthUser>();
|
||||
const { data: list } = useList<IFirm>({resource: "hub/users/firms/", pagination: { mode: "off" }}, )
|
||||
if (user === undefined || list === undefined) {
|
||||
return <p>Loading</p>
|
||||
return <p>Loading</p>;
|
||||
}
|
||||
console.log("list data: ", list);
|
||||
const ownedFirms = list.data;
|
||||
if (user === undefined || ownedFirms === undefined) {
|
||||
return <p>Loading</p>
|
||||
}
|
||||
console.log("owned firms: ", ownedFirms);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>HUB</h1>
|
||||
<p>List of managed firms</p>
|
||||
<ul>
|
||||
{ownedFirms.map((f: IFirm, index) => (
|
||||
<li key={index}>{f.instance} / {f.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
<p>List of firm you're working at</p>
|
||||
<ul>
|
||||
{user.firms.map((f: IFirm, index) => (
|
||||
<li key={index}>{f.instance} / {f.name}</li>
|
||||
<li key={index}>{f.instance} / {f.firm}</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link to="/hub/create-firm" ><Button>Create a new firm</Button></Link>
|
||||
<p>List of firm you're working at</p>
|
||||
<ul>
|
||||
{user.firms.map((f: IFirm, index) => (
|
||||
<li key={index}>
|
||||
{f.instance} / {f.firm} <Link to={`/firm/${f.instance}/${f.firm}`}><ExitToAppIcon /></Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,12 @@ const LOCAL_STORAGE_USER_KEY = "rpk-gui-current-user";
|
||||
const GOOGLE_SCOPES = { "scopes": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email" };
|
||||
const DISCORD_SCOPES = { "scopes": "identify email" }
|
||||
|
||||
const DEFAULT_LOGIN_REDIRECT = "/hub"
|
||||
|
||||
export const authProvider: AuthProvider = {
|
||||
login: async ({ providerName, email, password }) => {
|
||||
const to_param = findGetParameter("to");
|
||||
const redirect = to_param === null ? DEFAULT_LOGIN_REDIRECT : to_param
|
||||
if (providerName) {
|
||||
let scope = {};
|
||||
if (providerName === "google") {
|
||||
@@ -22,11 +25,14 @@ export const authProvider: AuthProvider = {
|
||||
const response = await fetch(url, { method: "GET", },);
|
||||
const body = await response.json();
|
||||
|
||||
if (to_param) {
|
||||
localStorage.setItem("redirect_after_login", to_param);
|
||||
}
|
||||
|
||||
localStorage.setItem("redirect_after_login", redirect);
|
||||
|
||||
window.location.href = body.authorization_url;
|
||||
return { success: true };
|
||||
return {
|
||||
success: true,
|
||||
redirectTo: ""
|
||||
};
|
||||
} else if (email !== undefined && password !== undefined) {
|
||||
const params = new URLSearchParams({"grant_type": "password", "username": email, "password": password});
|
||||
const response = await fetch(
|
||||
@@ -42,7 +48,10 @@ export const authProvider: AuthProvider = {
|
||||
const user = await response.json();
|
||||
store_user(user);
|
||||
|
||||
return { success: true };
|
||||
return {
|
||||
success: true,
|
||||
redirectTo: redirect,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +61,10 @@ export const authProvider: AuthProvider = {
|
||||
const response = await fetch(`${API_URL}/hub/auth/logout`, { method: "POST" });
|
||||
if (response.status == 204 || response.status == 401) {
|
||||
forget_user();
|
||||
return { success: true };
|
||||
return {
|
||||
success: true,
|
||||
redirectTo: "/",
|
||||
};
|
||||
}
|
||||
return { success: false };
|
||||
},
|
||||
@@ -60,7 +72,7 @@ export const authProvider: AuthProvider = {
|
||||
if (get_user() == null) {
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/login",
|
||||
redirectTo: "/auth/login",
|
||||
logout: true
|
||||
}
|
||||
}
|
||||
@@ -142,7 +154,7 @@ export const authProvider: AuthProvider = {
|
||||
if (error?.status === 401) {
|
||||
forget_user();
|
||||
return {
|
||||
redirectTo: "/login",
|
||||
redirectTo: "/auth/login",
|
||||
logout: true,
|
||||
error: { message: "Authentication required" },
|
||||
} as OnErrorResponse;
|
||||
|
||||
Reference in New Issue
Block a user