mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: use new session and auth provider for the frontend
This commit is contained in:
parent
d939dc16eb
commit
6aa849b305
27 changed files with 283 additions and 235 deletions
|
|
@ -1,58 +0,0 @@
|
|||
import { getNewAccessTokenUsingRefreshToken, getUserInfo } from '@services/auth/auth';
|
||||
import { getAPIUrl } from '@services/config/config';
|
||||
import { swrFetcher } from '@services/utils/ts/requests';
|
||||
import React, { useEffect } from 'react'
|
||||
import useSWR from 'swr';
|
||||
|
||||
const AuthContext = React.createContext({})
|
||||
|
||||
type Auth = {
|
||||
access_token: string;
|
||||
isAuthenticated: boolean;
|
||||
user: any;
|
||||
}
|
||||
|
||||
function AuthProvider({ children, orgslug }: { children: React.ReactNode, orgslug: string }) {
|
||||
const [auth, setAuth] = React.useState<Auth>({ access_token: "", isAuthenticated: false, user: {} });
|
||||
|
||||
async function checkRefreshToken() {
|
||||
//deleteCookie("access_token_cookie");
|
||||
let data = await getNewAccessTokenUsingRefreshToken();
|
||||
if (data) {
|
||||
return data.access_token;
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAuth() {
|
||||
try {
|
||||
let access_token = await checkRefreshToken();
|
||||
let userInfo = {};
|
||||
|
||||
if (access_token) {
|
||||
userInfo = await getUserInfo(access_token);
|
||||
setAuth({ access_token: access_token, isAuthenticated: true, user: userInfo });
|
||||
|
||||
} else {
|
||||
setAuth({ access_token: access_token, isAuthenticated: false, user: userInfo });
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
checkAuth();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={auth}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useAuth() {
|
||||
return React.useContext(AuthContext);
|
||||
}
|
||||
|
||||
export default AuthProvider
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
"use client";
|
||||
import React, { useEffect } from "react";
|
||||
import { getNewAccessTokenUsingRefreshToken, getUserInfo } from "../../services/auth/auth";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
|
||||
export const AuthContext: any = React.createContext({});
|
||||
|
||||
const PRIVATE_ROUTES = ["/course/*/edit", "/settings*", "/trail"];
|
||||
const NON_AUTHENTICATED_ROUTES = ["/login", "/register"];
|
||||
|
||||
export interface Auth {
|
||||
access_token: string;
|
||||
isAuthenticated: boolean;
|
||||
userInfo: {};
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
const AuthProvider = ({ children }: any) => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const [auth, setAuth] = React.useState<Auth>({ access_token: "", isAuthenticated: false, userInfo: {}, isLoading: true });
|
||||
|
||||
function deleteCookie(cookieName: string) {
|
||||
document.cookie = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
}
|
||||
|
||||
|
||||
async function checkRefreshToken() {
|
||||
//deleteCookie("access_token_cookie");
|
||||
let data = await getNewAccessTokenUsingRefreshToken();
|
||||
if (data) {
|
||||
return data.access_token;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function checkAuth() {
|
||||
try {
|
||||
let access_token = await checkRefreshToken();
|
||||
let userInfo = {};
|
||||
let isLoading = false;
|
||||
|
||||
if (access_token) {
|
||||
userInfo = await getUserInfo(access_token);
|
||||
setAuth({ access_token, isAuthenticated: true, userInfo, isLoading });
|
||||
|
||||
// Redirect to home if user is trying to access a NON_AUTHENTICATED_ROUTES route
|
||||
|
||||
if (NON_AUTHENTICATED_ROUTES.some((route) => new RegExp(`^${route.replace("*", ".*")}$`).test(pathname))) {
|
||||
router.push("/");
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
setAuth({ access_token, isAuthenticated: false, userInfo, isLoading });
|
||||
|
||||
// Redirect to login if user is trying to access a private route
|
||||
if (PRIVATE_ROUTES.some((route) => new RegExp(`^${route.replace("*", ".*")}$`).test(pathname))) {
|
||||
router.push("/login");
|
||||
}
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
checkAuth();
|
||||
return () => {
|
||||
auth.isLoading = false;
|
||||
};
|
||||
}, [pathname]);
|
||||
|
||||
return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
|
||||
};
|
||||
|
||||
export default AuthProvider;
|
||||
|
|
@ -1,49 +1,73 @@
|
|||
'use client';
|
||||
import React from "react";
|
||||
import { AuthContext } from "./AuthProviderDepreceated";
|
||||
import useSWR, { mutate } from "swr";
|
||||
import { getAPIUrl } from "@services/config/config";
|
||||
import { swrFetcher } from "@services/utils/ts/requests";
|
||||
import { useSession } from "@components/Contexts/SessionContext";
|
||||
import { useOrg } from "@components/Contexts/OrgContext";
|
||||
|
||||
interface AuthenticatedClientElementProps {
|
||||
children: React.ReactNode;
|
||||
checkMethod: 'authentication' | 'roles';
|
||||
orgId?: string;
|
||||
ressourceType?: 'collection' | 'course' | 'activity' | 'user' | 'organization';
|
||||
ressourceType?: 'collections' | 'courses' | 'activities' | 'users' | 'organizations';
|
||||
action?: 'create' | 'update' | 'delete' | 'read';
|
||||
}
|
||||
|
||||
function generateRessourceId(ressourceType: string) {
|
||||
// for every type of ressource, we need to generate a ressource id, example for a collection: col_XXXXX
|
||||
if (ressourceType == 'collection') {
|
||||
return `collection_xxxx`
|
||||
}
|
||||
else if (ressourceType == 'course') {
|
||||
return `course_xxxx`
|
||||
}
|
||||
else if (ressourceType == 'activity') {
|
||||
return `activity_xxxx`
|
||||
}
|
||||
else if (ressourceType == 'user') {
|
||||
return `user_xxxx`
|
||||
}
|
||||
else if (ressourceType == 'organization') {
|
||||
return `org_xxxx`
|
||||
}
|
||||
else if (ressourceType === null) {
|
||||
return `n/a`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const AuthenticatedClientElement = (props: AuthenticatedClientElementProps) => {
|
||||
const auth: any = React.useContext(AuthContext);
|
||||
const { data: authorization_status, error: error } = useSWR(props.checkMethod == 'roles' && props.ressourceType ? `${getAPIUrl()}users/authorize/ressource/${generateRessourceId(props.ressourceType)}/action/${props.action}` : null, swrFetcher);
|
||||
console.log(authorization_status);
|
||||
const [isAllowed, setIsAllowed] = React.useState(false);
|
||||
const session = useSession() as any;
|
||||
const org = useOrg() as any;
|
||||
|
||||
|
||||
if ((props.checkMethod == 'authentication' && auth.isAuthenticated) || (auth.isAuthenticated && props.checkMethod == 'roles' && authorization_status)) {
|
||||
return <>{props.children}</>;
|
||||
function isUserAllowed(roles: any[], action: string, resourceType: string, org_uuid: string): boolean {
|
||||
// Iterate over the user's roles
|
||||
for (const role of roles) {
|
||||
|
||||
// Check if the role is for the right organization
|
||||
if (role.org.org_uuid === org_uuid) {
|
||||
// Check if the user has the role for the resource type
|
||||
if (role.role.rights && role.role.rights[resourceType]) {
|
||||
|
||||
|
||||
// Check if the user is allowed to execute the action
|
||||
const actionKey = `action_${action}`;
|
||||
if (role.role.rights[resourceType][actionKey] === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no role matches the organization, resource type, and action, return false
|
||||
return false;
|
||||
}
|
||||
return <></>;
|
||||
|
||||
function check() {
|
||||
|
||||
if (props.checkMethod === 'authentication') {
|
||||
setIsAllowed(session.isAuthenticated);
|
||||
} else if (props.checkMethod === 'roles') {
|
||||
return setIsAllowed(isUserAllowed(session.roles, props.action!, props.ressourceType!, org.org_uuid));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (session.isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
check();
|
||||
}, [session, org])
|
||||
|
||||
return (
|
||||
<>
|
||||
{isAllowed && props.children}
|
||||
</>
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
'use client';
|
||||
import React from "react";
|
||||
import React, { use, useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import Link from "next/link";
|
||||
import { AuthContext } from "./AuthProviderDepreceated";
|
||||
import Avvvatars from "avvvatars-react";
|
||||
import { GearIcon } from "@radix-ui/react-icons";
|
||||
import { Settings } from "lucide-react";
|
||||
import { useSession } from "@components/Contexts/SessionContext";
|
||||
|
||||
export const HeaderProfileBox = () => {
|
||||
const auth: any = React.useContext(AuthContext);
|
||||
const session = useSession() as any;
|
||||
|
||||
return (
|
||||
<ProfileArea>
|
||||
{!auth.isAuthenticated && (
|
||||
{!session.isAuthenticated && (
|
||||
<UnidentifiedArea className="flex text-sm text-gray-700 font-bold p-1.5 px-2 rounded-lg">
|
||||
<ul className="flex space-x-3 items-center">
|
||||
<li>
|
||||
|
|
@ -28,13 +28,13 @@ export const HeaderProfileBox = () => {
|
|||
</ul>
|
||||
</UnidentifiedArea>
|
||||
)}
|
||||
{auth.isAuthenticated && (
|
||||
{session.isAuthenticated && (
|
||||
<AccountArea className="space-x-0">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="text-xs">{auth.userInfo.username} </div>
|
||||
<div className="text-xs">{session.user.username} </div>
|
||||
<div className="py-4">
|
||||
<div className="shadow-sm rounded-xl">
|
||||
<Avvvatars radius={3} size={30} value={auth.userInfo.user_uuid} style="shape" />
|
||||
<Avvvatars radius={3} size={30} value={session.user.user_uuid} style="shape" />
|
||||
</div>
|
||||
</div>
|
||||
<Link className="text-gray-600" href={"/dash"}><Settings size={14} /></Link>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue