update api users and groups and users 4

This commit is contained in:
Alma 2025-04-09 20:39:21 +02:00
parent 22bab9e845
commit 6a5155e855
2 changed files with 122 additions and 70 deletions

81
app/api/roles/route.ts Normal file
View File

@ -0,0 +1,81 @@
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import { NextResponse } from "next/server";
async function getAdminToken() {
try {
const tokenResponse = await fetch(
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.KEYCLOAK_CLIENT_ID!,
client_secret: process.env.KEYCLOAK_CLIENT_SECRET!,
}),
}
);
const data = await tokenResponse.json();
if (!tokenResponse.ok || !data.access_token) {
console.error('Token Error:', data);
return null;
}
return data.access_token;
} catch (error) {
console.error('Token Error:', error);
return null;
}
}
export async function GET() {
const session = await getServerSession(authOptions);
if (!session) {
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
}
try {
const token = await getAdminToken();
if (!token) {
return NextResponse.json({ error: "Erreur d'authentification" }, { status: 401 });
}
const response = await fetch(
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/roles`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
if (!response.ok) {
const errorData = await response.json();
console.error("Failed to fetch roles:", errorData);
return NextResponse.json({ error: "Erreur lors de la récupération des rôles" }, { status: response.status });
}
const roles = await response.json();
// Filter out system roles
const filteredRoles = roles.filter((role: any) =>
!role.name.startsWith('default-roles-') &&
role.name !== 'offline_access' &&
role.name !== 'uma_authorization'
);
return NextResponse.json(filteredRoles);
} catch (error) {
console.error("Error fetching roles:", error);
return NextResponse.json(
{ error: "Une erreur est survenue" },
{ status: 500 }
);
}
}

View File

@ -48,22 +48,25 @@ interface User {
roles: string[];
}
interface Role {
id: string;
name: string;
description: string;
composite: boolean;
clientRole: boolean;
containerId: string;
}
interface UsersTableProps {
userRole?: string[];
}
// Constants for role names
const ROLES = {
ADMIN: "Admin",
TEACHER: "Teacher",
STUDENT: "Students"
} as const;
const ITEMS_PER_PAGE = 10;
export function UsersTable({ userRole = [] }: UsersTableProps) {
const { data: session, status } = useSession();
const [users, setUsers] = useState<User[]>([]);
const [roles, setRoles] = useState<Role[]>([]);
const [loading, setLoading] = useState(true);
const [currentPage, setCurrentPage] = useState(1);
const [searchTerm, setSearchTerm] = useState("");
@ -81,15 +84,32 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
useEffect(() => {
fetchUsers();
fetchRoles();
}, []);
const fetchRoles = async () => {
try {
const response = await fetch("/api/roles");
if (!response.ok) {
throw new Error("Failed to fetch roles");
}
const data = await response.json();
setRoles(data);
} catch (error) {
console.error("Error fetching roles:", error);
toast({
title: "Erreur",
description: "Erreur lors de la récupération des rôles",
variant: "destructive",
});
}
};
const fetchUsers = async () => {
try {
setLoading(true);
const response = await fetch("/api/users");
const data = await response.json();
console.log("Fetched users:", data);
console.log("Current user role:", session?.user?.role); // Debug log
setUsers(data);
} catch (error) {
console.error("Error fetching users:", error);
@ -103,46 +123,6 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
}
};
const filterUsers = (users: User[]) => {
console.log("Filtering users with role:", userRole); // Debug log
if (!Array.isArray(users)) return [];
// If no role specified or user is admin, show all users
if (!userRole?.length || userRole.includes(ROLES.ADMIN)) {
console.log("Showing all users - admin or no role");
return users;
}
// If user is teacher, show teachers and students
if (userRole.includes(ROLES.TEACHER)) {
console.log("Filtering for teacher view");
return users.filter(user =>
user.roles?.includes(ROLES.TEACHER) || user.roles?.includes(ROLES.STUDENT)
);
}
// If user is student, show only students
if (userRole.includes(ROLES.STUDENT)) {
console.log("Filtering for student view");
return users.filter(user => user.roles?.includes(ROLES.STUDENT));
}
// Default: show all users
console.log("Default case: showing all users");
return users;
};
const canDelete = (targetUserRole: string[]) => {
if (!userRole?.length) return false;
if (userRole.includes(ROLES.ADMIN)) return true;
if (userRole.includes(ROLES.TEACHER)) {
return targetUserRole.includes(ROLES.STUDENT);
}
return false;
};
const handleAddUser = async (e: React.FormEvent) => {
e.preventDefault();
try {
@ -320,9 +300,8 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
};
const filteredUsers = useMemo(() => {
let filtered = filterUsers(users);
let filtered = users;
// Apply search filter
if (searchTerm) {
filtered = filtered.filter(user =>
user.username.toLowerCase().includes(searchTerm.toLowerCase()) ||
@ -333,26 +312,14 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
}
return filtered;
}, [users, searchTerm, userRole]);
}, [users, searchTerm]);
// Calculate pagination
const totalPages = Math.ceil(filteredUsers.length / ITEMS_PER_PAGE);
const paginatedUsers = filteredUsers.slice(
(currentPage - 1) * ITEMS_PER_PAGE,
currentPage * ITEMS_PER_PAGE
);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
// First, let's debug the roles
console.log("Current session:", {
role: session?.user?.role,
isAdmin: session?.user?.role?.includes("Admin"),
isTeacher: session?.user?.role?.includes("Teacher")
});
if (!session) return null;
if (loading) return <div className="text-center p-4">Loading...</div>;
@ -430,9 +397,11 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
<SelectValue placeholder="Sélectionner un rôle" />
</SelectTrigger>
<SelectContent>
<SelectItem value={ROLES.ADMIN}>Admin</SelectItem>
<SelectItem value={ROLES.TEACHER}>Enseignant</SelectItem>
<SelectItem value={ROLES.STUDENT}>Étudiant</SelectItem>
{roles.map((role) => (
<SelectItem key={role.id} value={role.name}>
{role.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
@ -542,9 +511,11 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
<SelectValue placeholder="Sélectionner un rôle" />
</SelectTrigger>
<SelectContent>
<SelectItem value={ROLES.ADMIN}>Admin</SelectItem>
<SelectItem value={ROLES.TEACHER}>Enseignant</SelectItem>
<SelectItem value={ROLES.STUDENT}>Étudiant</SelectItem>
{roles.map((role) => (
<SelectItem key={role.id} value={role.name}>
{role.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>