mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: implement comprehensive RBAC checks for courses, chapters, collections, and activities, enhancing user rights management and security documentation
This commit is contained in:
parent
887046203e
commit
3ce019abec
22 changed files with 1788 additions and 598 deletions
|
|
@ -3,40 +3,193 @@ import { useLHSession } from '@components/Contexts/LHSessionContext';
|
|||
import { useEffect, useState, useMemo } from 'react';
|
||||
|
||||
interface Role {
|
||||
org: { id: number };
|
||||
role: { id: number; role_uuid: string };
|
||||
org: { id: number; org_uuid: string };
|
||||
role: {
|
||||
id: number;
|
||||
role_uuid: string;
|
||||
rights?: {
|
||||
[key: string]: {
|
||||
[key: string]: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function useAdminStatus() {
|
||||
interface Rights {
|
||||
courses: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_read_own: boolean;
|
||||
action_update: boolean;
|
||||
action_update_own: boolean;
|
||||
action_delete: boolean;
|
||||
action_delete_own: boolean;
|
||||
};
|
||||
users: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_update: boolean;
|
||||
action_delete: boolean;
|
||||
};
|
||||
usergroups: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_update: boolean;
|
||||
action_delete: boolean;
|
||||
};
|
||||
collections: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_update: boolean;
|
||||
action_delete: boolean;
|
||||
};
|
||||
organizations: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_update: boolean;
|
||||
action_delete: boolean;
|
||||
};
|
||||
coursechapters: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_update: boolean;
|
||||
action_delete: boolean;
|
||||
};
|
||||
activities: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_update: boolean;
|
||||
action_delete: boolean;
|
||||
};
|
||||
roles: {
|
||||
action_create: boolean;
|
||||
action_read: boolean;
|
||||
action_update: boolean;
|
||||
action_delete: boolean;
|
||||
};
|
||||
dashboard: {
|
||||
action_access: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface UseAdminStatusReturn {
|
||||
isAdmin: boolean | null;
|
||||
loading: boolean;
|
||||
userRoles: Role[];
|
||||
rights: Rights | null;
|
||||
}
|
||||
|
||||
function useAdminStatus(): UseAdminStatusReturn {
|
||||
const session = useLHSession() as any;
|
||||
const org = useOrg() as any;
|
||||
const [isAdmin, setIsAdmin] = useState<boolean | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [rights, setRights] = useState<Rights | null>(null);
|
||||
|
||||
const userRoles = useMemo(() => session?.data?.roles || [], [session?.data?.roles]);
|
||||
|
||||
useEffect(() => {
|
||||
if (session.status === 'authenticated' && org?.id) {
|
||||
const isAdminVar = userRoles.some((role: Role) => {
|
||||
return (
|
||||
role.org.id === org.id &&
|
||||
(
|
||||
role.role.id === 1 ||
|
||||
role.role.id === 2 ||
|
||||
role.role.role_uuid === 'role_global_admin' ||
|
||||
role.role.role_uuid === 'role_global_maintainer'
|
||||
)
|
||||
);
|
||||
});
|
||||
// Extract rights from the backend session data
|
||||
const extractRightsFromRoles = (): Rights | null => {
|
||||
if (!userRoles || userRoles.length === 0) return null;
|
||||
|
||||
// Find roles for the current organization
|
||||
const orgRoles = userRoles.filter((role: Role) => role.org.id === org.id);
|
||||
if (orgRoles.length === 0) return null;
|
||||
|
||||
// Merge rights from all roles for this organization
|
||||
const mergedRights: Rights = {
|
||||
courses: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_read_own: false,
|
||||
action_update: false,
|
||||
action_update_own: false,
|
||||
action_delete: false,
|
||||
action_delete_own: false
|
||||
},
|
||||
users: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_update: false,
|
||||
action_delete: false
|
||||
},
|
||||
usergroups: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_update: false,
|
||||
action_delete: false
|
||||
},
|
||||
collections: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_update: false,
|
||||
action_delete: false
|
||||
},
|
||||
organizations: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_update: false,
|
||||
action_delete: false
|
||||
},
|
||||
coursechapters: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_update: false,
|
||||
action_delete: false
|
||||
},
|
||||
activities: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_update: false,
|
||||
action_delete: false
|
||||
},
|
||||
roles: {
|
||||
action_create: false,
|
||||
action_read: false,
|
||||
action_update: false,
|
||||
action_delete: false
|
||||
},
|
||||
dashboard: {
|
||||
action_access: false
|
||||
}
|
||||
};
|
||||
|
||||
// Merge rights from all roles
|
||||
orgRoles.forEach((role: Role) => {
|
||||
if (role.role.rights) {
|
||||
Object.keys(role.role.rights).forEach((resourceType) => {
|
||||
if (mergedRights[resourceType as keyof Rights]) {
|
||||
Object.keys(role.role.rights![resourceType]).forEach((action) => {
|
||||
if (role.role.rights![resourceType][action] === true) {
|
||||
(mergedRights[resourceType as keyof Rights] as any)[action] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return mergedRights;
|
||||
};
|
||||
|
||||
const extractedRights = extractRightsFromRoles();
|
||||
setRights(extractedRights);
|
||||
|
||||
// User is admin only if they have dashboard access
|
||||
const isAdminVar = extractedRights?.dashboard?.action_access === true;
|
||||
setIsAdmin(isAdminVar);
|
||||
setLoading(false); // Set loading to false once the status is determined
|
||||
|
||||
setLoading(false);
|
||||
} else {
|
||||
setIsAdmin(false);
|
||||
setLoading(false); // Set loading to false if not authenticated or org not found
|
||||
setRights(null);
|
||||
setLoading(false);
|
||||
}
|
||||
}, [session.status, userRoles, org.id]);
|
||||
|
||||
return { isAdmin, loading };
|
||||
return { isAdmin, loading, userRoles, rights };
|
||||
}
|
||||
|
||||
export default useAdminStatus;
|
||||
|
|
|
|||
64
apps/web/components/Hooks/useCourseRights.tsx
Normal file
64
apps/web/components/Hooks/useCourseRights.tsx
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
'use client'
|
||||
import { getAPIUrl } from '@services/config/config'
|
||||
import { swrFetcher } from '@services/utils/ts/requests'
|
||||
import useSWR from 'swr'
|
||||
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
||||
|
||||
export interface CourseRights {
|
||||
course_uuid: string
|
||||
user_id: number
|
||||
is_anonymous: boolean
|
||||
permissions: {
|
||||
read: boolean
|
||||
create: boolean
|
||||
update: boolean
|
||||
delete: boolean
|
||||
create_content: boolean
|
||||
update_content: boolean
|
||||
delete_content: boolean
|
||||
manage_contributors: boolean
|
||||
manage_access: boolean
|
||||
grade_assignments: boolean
|
||||
mark_activities_done: boolean
|
||||
create_certifications: boolean
|
||||
}
|
||||
ownership: {
|
||||
is_owner: boolean
|
||||
is_creator: boolean
|
||||
is_maintainer: boolean
|
||||
is_contributor: boolean
|
||||
authorship_status: string
|
||||
}
|
||||
roles: {
|
||||
is_admin: boolean
|
||||
is_maintainer_role: boolean
|
||||
is_instructor: boolean
|
||||
is_user: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export function useCourseRights(courseuuid: string) {
|
||||
const session = useLHSession() as any
|
||||
const access_token = session?.data?.tokens?.access_token
|
||||
|
||||
const { data: rights, error, isLoading } = useSWR<CourseRights>(
|
||||
courseuuid ? `${getAPIUrl()}courses/${courseuuid}/rights` : null,
|
||||
(url) => swrFetcher(url, access_token)
|
||||
)
|
||||
|
||||
return {
|
||||
rights,
|
||||
error,
|
||||
isLoading,
|
||||
hasPermission: (permission: keyof CourseRights['permissions']) => {
|
||||
return rights?.permissions?.[permission] ?? false
|
||||
},
|
||||
hasRole: (role: keyof CourseRights['roles']) => {
|
||||
return rights?.roles?.[role] ?? false
|
||||
},
|
||||
isOwner: rights?.ownership?.is_owner ?? false,
|
||||
isCreator: rights?.ownership?.is_creator ?? false,
|
||||
isMaintainer: rights?.ownership?.is_maintainer ?? false,
|
||||
isContributor: rights?.ownership?.is_contributor ?? false
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue