update api users and groups and users 4
This commit is contained in:
parent
22bab9e845
commit
6a5155e855
81
app/api/roles/route.ts
Normal file
81
app/api/roles/route.ts
Normal 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 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -48,22 +48,25 @@ interface User {
|
|||||||
roles: string[];
|
roles: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Role {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
composite: boolean;
|
||||||
|
clientRole: boolean;
|
||||||
|
containerId: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface UsersTableProps {
|
interface UsersTableProps {
|
||||||
userRole?: string[];
|
userRole?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constants for role names
|
|
||||||
const ROLES = {
|
|
||||||
ADMIN: "Admin",
|
|
||||||
TEACHER: "Teacher",
|
|
||||||
STUDENT: "Students"
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 10;
|
const ITEMS_PER_PAGE = 10;
|
||||||
|
|
||||||
export function UsersTable({ userRole = [] }: UsersTableProps) {
|
export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
const [users, setUsers] = useState<User[]>([]);
|
||||||
|
const [roles, setRoles] = useState<Role[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
@ -81,15 +84,32 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUsers();
|
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 () => {
|
const fetchUsers = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await fetch("/api/users");
|
const response = await fetch("/api/users");
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log("Fetched users:", data);
|
|
||||||
console.log("Current user role:", session?.user?.role); // Debug log
|
|
||||||
setUsers(data);
|
setUsers(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching users:", 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) => {
|
const handleAddUser = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
try {
|
try {
|
||||||
@ -320,9 +300,8 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const filteredUsers = useMemo(() => {
|
const filteredUsers = useMemo(() => {
|
||||||
let filtered = filterUsers(users);
|
let filtered = users;
|
||||||
|
|
||||||
// Apply search filter
|
|
||||||
if (searchTerm) {
|
if (searchTerm) {
|
||||||
filtered = filtered.filter(user =>
|
filtered = filtered.filter(user =>
|
||||||
user.username.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
user.username.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
@ -333,26 +312,14 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return filtered;
|
return filtered;
|
||||||
}, [users, searchTerm, userRole]);
|
}, [users, searchTerm]);
|
||||||
|
|
||||||
// Calculate pagination
|
|
||||||
const totalPages = Math.ceil(filteredUsers.length / ITEMS_PER_PAGE);
|
const totalPages = Math.ceil(filteredUsers.length / ITEMS_PER_PAGE);
|
||||||
const paginatedUsers = filteredUsers.slice(
|
const paginatedUsers = filteredUsers.slice(
|
||||||
(currentPage - 1) * ITEMS_PER_PAGE,
|
(currentPage - 1) * ITEMS_PER_PAGE,
|
||||||
currentPage * 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 (!session) return null;
|
||||||
if (loading) return <div className="text-center p-4">Loading...</div>;
|
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" />
|
<SelectValue placeholder="Sélectionner un rôle" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value={ROLES.ADMIN}>Admin</SelectItem>
|
{roles.map((role) => (
|
||||||
<SelectItem value={ROLES.TEACHER}>Enseignant</SelectItem>
|
<SelectItem key={role.id} value={role.name}>
|
||||||
<SelectItem value={ROLES.STUDENT}>Étudiant</SelectItem>
|
{role.name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
@ -542,9 +511,11 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
|||||||
<SelectValue placeholder="Sélectionner un rôle" />
|
<SelectValue placeholder="Sélectionner un rôle" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value={ROLES.ADMIN}>Admin</SelectItem>
|
{roles.map((role) => (
|
||||||
<SelectItem value={ROLES.TEACHER}>Enseignant</SelectItem>
|
<SelectItem key={role.id} value={role.name}>
|
||||||
<SelectItem value={ROLES.STUDENT}>Étudiant</SelectItem>
|
{role.name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user