diff --git a/apps/api/src/db/users.py b/apps/api/src/db/users.py
index 79ee9788..95f263f2 100644
--- a/apps/api/src/db/users.py
+++ b/apps/api/src/db/users.py
@@ -1,6 +1,10 @@
from typing import Optional
+from pydantic import BaseModel
from sqlmodel import Field, SQLModel
+from src.db.roles import RoleRead
+from src.db.organizations import OrganizationRead
+
class UserBase(SQLModel):
username: str
@@ -33,14 +37,27 @@ class UserRead(UserBase):
id: int
user_uuid: str
+
class PublicUser(UserRead):
pass
+
+class UserRoleWithOrg(BaseModel):
+ role: RoleRead
+ org: OrganizationRead
+
+
+class UserSession(BaseModel):
+ user: UserRead
+ roles: list[UserRoleWithOrg]
+
+
class AnonymousUser(SQLModel):
id: int = 0
user_uuid: str = "user_anonymous"
username: str = "anonymous"
+
class User(UserBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
password: str = ""
diff --git a/apps/api/src/routers/users.py b/apps/api/src/routers/users.py
index 71ec2741..808f77b5 100644
--- a/apps/api/src/routers/users.py
+++ b/apps/api/src/routers/users.py
@@ -9,6 +9,7 @@ from src.db.users import (
User,
UserCreate,
UserRead,
+ UserSession,
UserUpdate,
UserUpdatePassword,
)
@@ -17,6 +18,7 @@ from src.services.users.users import (
create_user,
create_user_without_org,
delete_user_by_id,
+ get_user_session,
read_user_by_id,
read_user_by_uuid,
update_user,
@@ -35,6 +37,18 @@ async def api_get_current_user(current_user: User = Depends(get_current_user)):
return current_user.dict()
+@router.get("/session")
+async def api_get_current_user_session(
+ request: Request,
+ db_session: Session = Depends(get_db_session),
+ current_user: PublicUser = Depends(get_current_user),
+) -> UserSession:
+ """
+ Get current user
+ """
+ return await get_user_session(request, db_session, current_user)
+
+
@router.get("/authorize/ressource/{ressource_uuid}/action/{action}")
async def api_get_authorization_status(
request: Request,
diff --git a/apps/api/src/security/rbac/rbac.py b/apps/api/src/security/rbac/rbac.py
index 34098744..6aec4117 100644
--- a/apps/api/src/security/rbac/rbac.py
+++ b/apps/api/src/security/rbac/rbac.py
@@ -23,7 +23,7 @@ async def authorization_verify_if_element_is_public(
if element_nature == "courses":
print("looking for course")
statement = select(Course).where(
- Course.public == True, Course.course_uuid == element_uuid
+ Course.public is True, Course.course_uuid == element_uuid
)
course = db_session.exec(statement).first()
if course:
@@ -33,7 +33,7 @@ async def authorization_verify_if_element_is_public(
if element_nature == "collections":
statement = select(Collection).where(
- Collection.public == True, Collection.collection_uuid == element_uuid
+ Collection.public is True, Collection.collection_uuid == element_uuid
)
collection = db_session.exec(statement).first()
diff --git a/apps/api/src/services/courses/courses.py b/apps/api/src/services/courses/courses.py
index df69ce75..72d78d01 100644
--- a/apps/api/src/services/courses/courses.py
+++ b/apps/api/src/services/courses/courses.py
@@ -327,7 +327,7 @@ async def get_courses_orgslug(
statement_public = (
select(Course)
.join(Organization)
- .where(Organization.slug == org_slug, Course.public == True)
+ .where(Organization.slug == org_slug, Course.public is True)
)
statement_all = (
select(Course).join(Organization).where(Organization.slug == org_slug)
diff --git a/apps/api/src/services/users/users.py b/apps/api/src/services/users/users.py
index 4a9c5ee6..cc6fbca5 100644
--- a/apps/api/src/services/users/users.py
+++ b/apps/api/src/services/users/users.py
@@ -3,17 +3,20 @@ from typing import Literal
from uuid import uuid4
from fastapi import HTTPException, Request, status
from sqlmodel import Session, select
+from src.db.roles import Role, RoleRead
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship,
authorization_verify_if_user_is_anon,
)
-from src.db.organizations import Organization
+from src.db.organizations import Organization, OrganizationRead
from src.db.users import (
AnonymousUser,
PublicUser,
User,
UserCreate,
UserRead,
+ UserRoleWithOrg,
+ UserSession,
UserUpdate,
UserUpdatePassword,
)
@@ -279,6 +282,57 @@ async def read_user_by_uuid(
return user
+async def get_user_session(
+ request: Request,
+ db_session: Session,
+ current_user: PublicUser | AnonymousUser,
+) -> UserSession:
+ # Get user
+ statement = select(User).where(User.user_uuid == current_user.user_uuid)
+ user = db_session.exec(statement).first()
+
+ if not user:
+ raise HTTPException(
+ status_code=400,
+ detail="User does not exist",
+ )
+
+ user = UserRead.from_orm(user)
+
+ # Get roles and orgs
+ statement = (
+ select(UserOrganization)
+ .where(UserOrganization.user_id == user.id)
+ .join(Organization)
+ )
+ user_organizations = db_session.exec(statement).all()
+
+ roles = []
+
+ for user_organization in user_organizations:
+ role_statement = select(Role).where(Role.id == user_organization.role_id)
+ role = db_session.exec(role_statement).first()
+
+ org_statement = select(Organization).where(
+ Organization.id == user_organization.org_id
+ )
+ org = db_session.exec(org_statement).first()
+
+ roles.append(
+ UserRoleWithOrg(
+ role=RoleRead.from_orm(role),
+ org=OrganizationRead.from_orm(org),
+ )
+ )
+
+ user_session = UserSession(
+ user=user,
+ roles=roles,
+ )
+
+ return user_session
+
+
async def authorize_user_action(
request: Request,
db_session: Session,
diff --git a/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx
index 55948525..06483373 100644
--- a/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx
+++ b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx
@@ -1,5 +1,4 @@
import { default as React, } from "react";
-import AuthProvider from "@components/Security/AuthProviderDepreceated";
import EditorWrapper from "@components/Objects/Editor/EditorWrapper";
import { getCourseMetadataWithAuthHeader } from "@services/courses/courses";
import { cookies } from "next/headers";
@@ -7,6 +6,7 @@ import { Metadata } from "next";
import { getActivityWithAuthHeader } from "@services/courses/activities";
import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from "@services/auth/auth";
import { getOrganizationContextInfo, getOrganizationContextInfoWithId } from "@services/organizations/orgs";
+import SessionProvider from "@components/Contexts/SessionContext";
type MetadataProps = {
params: { orgslug: string, courseid: string, activityid: string };
@@ -35,13 +35,13 @@ const EditActivity = async (params: any) => {
const courseInfo = await getCourseMetadataWithAuthHeader(courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
const activity = await getActivityWithAuthHeader(activityuuid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null)
const org = await getOrganizationContextInfoWithId(courseInfo.org_id, { revalidate: 1800, tags: ['organizations'] });
- console.log('courseInfo', courseInfo )
+ console.log('courseInfo', courseInfo)
return (
);
}
diff --git a/apps/web/app/organizations/page.tsx b/apps/web/app/organizations/page.tsx
index 009c0b19..00120e03 100644
--- a/apps/web/app/organizations/page.tsx
+++ b/apps/web/app/organizations/page.tsx
@@ -5,7 +5,6 @@ import { deleteOrganizationFromBackend } from "@services/organizations/orgs";
import useSWR, { mutate } from "swr";
import { swrFetcher } from "@services/utils/ts/requests";
import { getAPIUrl, getUriWithOrg } from "@services/config/config";
-import AuthProvider from "@components/Security/AuthProviderDepreceated";
const Organizations = () => {
const { data: organizations, error } = useSWR(`${getAPIUrl()}orgs/user/page/1/limit/10`, swrFetcher)
@@ -17,7 +16,6 @@ const Organizations = () => {
return (
<>
-
Your Organizations{" "}
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx
index ee4890b7..7a65ca2c 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx
@@ -57,7 +57,7 @@ const CollectionsPage = async (params: any) => {
@@ -85,7 +85,7 @@ const CollectionsPage = async (params: any) => {
Create a collection to group courses together
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx
index 5c1348ba..0cab8203 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx
@@ -34,7 +34,7 @@ function Courses(props: CourseProps) {
-
+
{children}
-
+
>
);
}
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx
index aaed6f07..999456ec 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx
@@ -69,7 +69,7 @@ const OrgHomePage = async (params: any) => {
@@ -110,7 +110,7 @@ const OrgHomePage = async (params: any) => {
diff --git a/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx b/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx
index 541368fa..9a290f15 100644
--- a/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx
@@ -37,7 +37,7 @@ function CoursesHome(params: CourseProps) {
Courses
-
+
-
+
>
)
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/user/settings/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/user/settings/[subpage]/page.tsx
index 56de4bcf..575b235f 100644
--- a/apps/web/app/orgs/[orgslug]/dash/user/settings/[subpage]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/user/settings/[subpage]/page.tsx
@@ -7,7 +7,7 @@ import Link from 'next/link';
import { getUriWithOrg } from '@services/config/config';
import { Info, Lock } from 'lucide-react';
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs';
-import { useAuth } from '@components/Security/AuthContext';
+import { useSession } from '@components/Contexts/SessionContext';
export type SettingsParams = {
subpage: string
@@ -15,17 +15,17 @@ export type SettingsParams = {
}
function SettingsPage({ params }: { params: SettingsParams }) {
- const auth = useAuth() as any;
+ const session = useSession() as any;
useEffect(() => {
}
- , [auth])
+ , [session])
return (
-
+
Account Settings
diff --git a/apps/web/app/orgs/[orgslug]/layout.tsx b/apps/web/app/orgs/[orgslug]/layout.tsx
index ce0f624f..e9b5b4a9 100644
--- a/apps/web/app/orgs/[orgslug]/layout.tsx
+++ b/apps/web/app/orgs/[orgslug]/layout.tsx
@@ -1,20 +1,17 @@
'use client';
import { OrgProvider } from "@components/Contexts/OrgContext";
-import AuthProvider from "@components/Security/AuthContext";
-import { getAPIUrl } from "@services/config/config";
-import { swrFetcher } from "@services/utils/ts/requests";
+import SessionProvider from "@components/Contexts/SessionContext";
import "@styles/globals.css";
-import useSWR from "swr";
export default function RootLayout({ children, params }: { children: React.ReactNode, params: any }) {
return (
-
-
+
+
{children}
-
-
+
+
);
}
diff --git a/apps/web/components/Contexts/SessionContext.tsx b/apps/web/components/Contexts/SessionContext.tsx
new file mode 100644
index 00000000..7094b94e
--- /dev/null
+++ b/apps/web/components/Contexts/SessionContext.tsx
@@ -0,0 +1,65 @@
+'use client';
+import { getNewAccessTokenUsingRefreshToken, getUserSession } from '@services/auth/auth';
+import { usePathname, useRouter, useSearchParams } from 'next/navigation'
+import React, { useContext, createContext, useEffect } from 'react'
+import { useOrg } from './OrgContext';
+
+export const SessionContext = createContext({}) as any;
+
+const PATHS_THAT_REQUIRE_AUTH = ['/dash'];
+
+type Session = {
+ access_token: string;
+ user: any;
+ roles: any;
+ isLoading: boolean;
+ isAuthenticated: boolean;
+}
+
+function SessionProvider({ children }: { children: React.ReactNode }) {
+ const [session, setSession] = React.useState
({ access_token: "", user: {}, roles: {}, isLoading: true, isAuthenticated: false });
+ const org = useOrg() as any;
+ const pathname = usePathname()
+ const router = useRouter()
+
+
+ async function getNewAccessTokenUsingRefreshTokenUI() {
+ let data = await getNewAccessTokenUsingRefreshToken();
+ return data.access_token;
+ }
+
+ async function checkSession() {
+ // Get new access token using refresh token
+ const access_token = await getNewAccessTokenUsingRefreshTokenUI();
+
+ if (access_token) {
+ // Get user session info
+ const user_session = await getUserSession(access_token);
+
+ // Set session
+ setSession({ access_token: access_token, user: user_session.user, roles: user_session.roles, isLoading: false, isAuthenticated: true });
+ }
+ }
+
+
+
+ useEffect(() => {
+ // Check session
+ checkSession();
+
+
+
+ }, [])
+
+ return (
+
+ {children}
+
+ )
+}
+
+export function useSession() {
+ return useContext(SessionContext);
+}
+
+export default SessionProvider
\ No newline at end of file
diff --git a/apps/web/components/Dashboard/UI/LeftMenu.tsx b/apps/web/components/Dashboard/UI/LeftMenu.tsx
index 1a4d2ca4..06e50fa6 100644
--- a/apps/web/components/Dashboard/UI/LeftMenu.tsx
+++ b/apps/web/components/Dashboard/UI/LeftMenu.tsx
@@ -1,6 +1,6 @@
'use client';
import { useOrg } from '@components/Contexts/OrgContext';
-import { useAuth } from '@components/Security/AuthContext';
+import { useSession } from '@components/Contexts/SessionContext';
import ToolTip from '@components/StyledElements/Tooltip/Tooltip'
import LearnHouseDashboardLogo from '@public/dashLogo.png';
import Avvvatars from 'avvvatars-react';
@@ -11,11 +11,11 @@ import React, { use, useEffect } from 'react'
function LeftMenu() {
const org = useOrg() as any;
- const auth = useAuth() as any;
+ const session = useSession() as any;
const [loading, setLoading] = React.useState(true);
function waitForEverythingToLoad() {
- if (org && auth) {
+ if (org && session) {
return true;
}
return false;
@@ -59,15 +59,15 @@ function LeftMenu() {
-
+
-
+
diff --git a/apps/web/components/Dashboard/User/UserEditGeneral/UserEditGeneral.tsx b/apps/web/components/Dashboard/User/UserEditGeneral/UserEditGeneral.tsx
index edb12d11..165e34d7 100644
--- a/apps/web/components/Dashboard/User/UserEditGeneral/UserEditGeneral.tsx
+++ b/apps/web/components/Dashboard/User/UserEditGeneral/UserEditGeneral.tsx
@@ -1,33 +1,33 @@
-import { useAuth } from '@components/Security/AuthContext';
import { updateProfile } from '@services/settings/profile';
import React, { useEffect } from 'react'
import { Formik, Form, Field, ErrorMessage } from 'formik';
+import { useSession } from '@components/Contexts/SessionContext';
function UserEditGeneral() {
- const auth = useAuth() as any;
+ const session = useSession() as any;
useEffect(() => {
}
- , [auth, auth.user])
+ , [session, session.user])
return (
- {auth.user && (
+ {session.user && (
{
setTimeout(() => {
setSubmitting(false);
- updateProfile(values,auth.user.id)
+ updateProfile(values,session.user.id)
}, 400);
}}
>
diff --git a/apps/web/components/Dashboard/User/UserEditPassword/UserEditPassword.tsx b/apps/web/components/Dashboard/User/UserEditPassword/UserEditPassword.tsx
index f11a962b..996aa53c 100644
--- a/apps/web/components/Dashboard/User/UserEditPassword/UserEditPassword.tsx
+++ b/apps/web/components/Dashboard/User/UserEditPassword/UserEditPassword.tsx
@@ -1,19 +1,19 @@
-import { useAuth } from '@components/Security/AuthContext';
+import { useSession } from '@components/Contexts/SessionContext';
import { updatePassword } from '@services/settings/password';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import React, { useEffect } from 'react'
function UserEditPassword() {
- const auth = useAuth() as any;
+ const session = useSession() as any;
const updatePasswordUI = async (values: any) => {
- let user_id = auth.userInfo.user_object.user_id;
+ let user_id = session.user.user_id;
await updatePassword(user_id, values)
}
useEffect(() => {
}
- , [auth])
+ , [session])
return (
diff --git a/apps/web/components/Objects/Editor/Editor.tsx b/apps/web/components/Objects/Editor/Editor.tsx
index 4db1cc14..5d9028dd 100644
--- a/apps/web/components/Objects/Editor/Editor.tsx
+++ b/apps/web/components/Objects/Editor/Editor.tsx
@@ -2,7 +2,6 @@
import React from "react";
import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
-import { AuthContext } from "../../Security/AuthProviderDepreceated";
import learnhouseIcon from "public/learnhouse_icon.png";
import { ToolbarButtons } from "./Toolbar/ToolbarButtons";
import { motion } from "framer-motion";
@@ -38,6 +37,7 @@ import python from 'highlight.js/lib/languages/python'
import java from 'highlight.js/lib/languages/java'
import { CourseProvider } from "@components/Contexts/CourseContext";
import { OrgProvider } from "@components/Contexts/OrgContext";
+import { useSession } from "@components/Contexts/SessionContext";
interface Editor {
@@ -51,7 +51,7 @@ interface Editor {
}
function Editor(props: Editor) {
- const auth: any = React.useContext(AuthContext);
+ const session = useSession() as any;
// remove course_ from course_uuid
const course_uuid = props.course.course_uuid.substring(7);
@@ -164,8 +164,8 @@ function Editor(props: Editor) {
- {!auth.isAuthenticated && Loading}
- {auth.isAuthenticated && }
+ {!session.isAuthenticated && Loading}
+ {session.isAuthenticated && }
diff --git a/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx b/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx
index 242d935b..e669654f 100644
--- a/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx
+++ b/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx
@@ -58,7 +58,7 @@ const CollectionAdminEditsArea = (props: any) => {
return (
diff --git a/apps/web/components/Security/AuthContext.tsx b/apps/web/components/Security/AuthContext.tsx
deleted file mode 100644
index a1742832..00000000
--- a/apps/web/components/Security/AuthContext.tsx
+++ /dev/null
@@ -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
({ 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 (
-
- {children}
-
- )
-}
-
-export function useAuth() {
- return React.useContext(AuthContext);
-}
-
-export default AuthProvider
\ No newline at end of file
diff --git a/apps/web/components/Security/AuthProviderDepreceated.tsx b/apps/web/components/Security/AuthProviderDepreceated.tsx
deleted file mode 100644
index a2beecfa..00000000
--- a/apps/web/components/Security/AuthProviderDepreceated.tsx
+++ /dev/null
@@ -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({ 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 {children};
-};
-
-export default AuthProvider;
diff --git a/apps/web/components/Security/AuthenticatedClientElement.tsx b/apps/web/components/Security/AuthenticatedClientElement.tsx
index 693aafec..a02ead11 100644
--- a/apps/web/components/Security/AuthenticatedClientElement.tsx
+++ b/apps/web/components/Security/AuthenticatedClientElement.tsx
@@ -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}
+ >
+ )
}
diff --git a/apps/web/components/Security/HeaderProfileBox.tsx b/apps/web/components/Security/HeaderProfileBox.tsx
index 2e4dc7b6..5d1e5464 100644
--- a/apps/web/components/Security/HeaderProfileBox.tsx
+++ b/apps/web/components/Security/HeaderProfileBox.tsx
@@ -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 (
- {!auth.isAuthenticated && (
+ {!session.isAuthenticated && (
-
@@ -28,13 +28,13 @@ export const HeaderProfileBox = () => {
)}
- {auth.isAuthenticated && (
+ {session.isAuthenticated && (
-
{auth.userInfo.username}
+
{session.user.username}
diff --git a/apps/web/services/auth/auth.ts b/apps/web/services/auth/auth.ts
index 9821f2fd..e01e3951 100644
--- a/apps/web/services/auth/auth.ts
+++ b/apps/web/services/auth/auth.ts
@@ -45,6 +45,22 @@ export async function getUserInfo(token: string): Promise
{
.catch((error) => console.log("error", error));
}
+export async function getUserSession(token: string): Promise {
+ const origin = window.location.origin;
+ const HeadersConfig = new Headers({ Authorization: `Bearer ${token}`, Origin: origin });
+
+ const requestOptions: any = {
+ method: "GET",
+ headers: HeadersConfig,
+ redirect: "follow",
+ credentials: "include",
+ };
+
+ return fetch(`${getAPIUrl()}users/session`, requestOptions)
+ .then((result) => result.json())
+ .catch((error) => console.log("error", error));
+}
+
export async function getNewAccessTokenUsingRefreshToken(): Promise {
const requestOptions: any = {
method: "POST",