mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
FIX frontend admin
This commit is contained in:
parent
985764a064
commit
f006dfd195
12 changed files with 407 additions and 26 deletions
|
|
@ -26,10 +26,15 @@ import Footer from './components/Footer/Footer';
|
||||||
import ApiService from './services/ApiService';
|
import ApiService from './services/ApiService';
|
||||||
import OAuthCallback from './pages/AuthManager/callback/AuthCallback';
|
import OAuthCallback from './pages/AuthManager/callback/AuthCallback';
|
||||||
|
|
||||||
|
import Users from './pages/Admin/Users';
|
||||||
|
import Images from './pages/Admin/Images';
|
||||||
|
import Stats from './pages/Admin/Stats';
|
||||||
|
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn());
|
const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn());
|
||||||
const [isTeacherAuthenticated, setIsTeacherAuthenticated] = useState(ApiService.isLoggedInTeacher());
|
const [isTeacherAuthenticated, setIsTeacherAuthenticated] = useState(ApiService.isLoggedInTeacher());
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
//const [isAdmin, setIsAdmin] = useState(false);
|
||||||
const [isRoomRequireAuthentication, setRoomsRequireAuth] = useState(null);
|
const [isRoomRequireAuthentication, setRoomsRequireAuth] = useState(null);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
|
@ -100,6 +105,11 @@ const App: React.FC = () => {
|
||||||
|
|
||||||
{/* Pages authentification sélection */}
|
{/* Pages authentification sélection */}
|
||||||
<Route path="/auth/callback" element={<OAuthCallback />} />
|
<Route path="/auth/callback" element={<OAuthCallback />} />
|
||||||
|
|
||||||
|
<Route path="/admin/stats" element={<Stats />} />
|
||||||
|
<Route path="/admin/images" element={<Images />} />
|
||||||
|
<Route path="/admin/users" element={<Users />} />
|
||||||
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
17
client/src/Types/ImageType.tsx
Normal file
17
client/src/Types/ImageType.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
export interface ImageType {
|
||||||
|
id: string;
|
||||||
|
file_content: string;
|
||||||
|
file_name: string;
|
||||||
|
mime_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImagesResponse {
|
||||||
|
images: ImageType[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImagesParams {
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
uid?: string;
|
||||||
|
}
|
||||||
|
|
@ -9,3 +9,11 @@ export interface QuizType {
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
updated_at: Date;
|
updated_at: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface QuizTypeShort {
|
||||||
|
_id: string;
|
||||||
|
userId: string;
|
||||||
|
title: string;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
}
|
||||||
11
client/src/Types/UserType.tsx
Normal file
11
client/src/Types/UserType.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
export interface UserType {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
created_at: string;
|
||||||
|
roles: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UsersResponse {
|
||||||
|
users: UserType[];
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import ListItemText from '@mui/material/ListItemText';
|
||||||
import BarChartIcon from '@mui/icons-material/BarChart';
|
import BarChartIcon from '@mui/icons-material/BarChart';
|
||||||
import ImageIcon from '@mui/icons-material/Image';
|
import ImageIcon from '@mui/icons-material/Image';
|
||||||
import PeopleIcon from '@mui/icons-material/People';
|
import PeopleIcon from '@mui/icons-material/People';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
drawerBg: 'rgba(82, 113, 255, 0.85)',
|
drawerBg: 'rgba(82, 113, 255, 0.85)',
|
||||||
|
|
@ -21,23 +22,29 @@ const styles = {
|
||||||
|
|
||||||
export default function AdminDrawer() {
|
export default function AdminDrawer() {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const toggleDrawer = (isOpen: boolean) => () => {
|
const toggleDrawer = (isOpen: boolean) => () => {
|
||||||
setOpen(isOpen);
|
setOpen(isOpen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleNavigation = (path: string) => {
|
||||||
|
navigate(path);
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ text: 'Stats', icon: <BarChartIcon /> },
|
{ text: 'Stats', icon: <BarChartIcon />, path: '/admin/stats' },
|
||||||
{ text: 'Images', icon: <ImageIcon /> },
|
{ text: 'Images', icon: <ImageIcon />, path: '/admin/images' },
|
||||||
{ text: 'Users', icon: <PeopleIcon /> },
|
{ text: 'Users', icon: <PeopleIcon />, path: '/admin/users' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const list = (
|
const list = (
|
||||||
<Box sx={{ width: 250, backgroundColor: styles.drawerBg, height: styles.height, color: styles.drawerTxtColor }} role="presentation" onClick={toggleDrawer(false)}>
|
<Box sx={{ width: 250, backgroundColor: styles.drawerBg, height: styles.height, color: styles.drawerTxtColor }} role="presentation" onClick={toggleDrawer(false)}>
|
||||||
<List>
|
<List>
|
||||||
{menuItems.map(({ text, icon }) => (
|
{menuItems.map(({ text, icon, path }) => (
|
||||||
<ListItem key={text} disablePadding>
|
<ListItem key={text} disablePadding>
|
||||||
<ListItemButton>
|
<ListItemButton onClick={() => handleNavigation(path)}>
|
||||||
<ListItemIcon sx={{ color: styles.drawerTxtColor }}>{icon}</ListItemIcon>
|
<ListItemIcon sx={{ color: styles.drawerTxtColor }}>{icon}</ListItemIcon>
|
||||||
<ListItemText primary={text} />
|
<ListItemText primary={text} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
|
|
|
||||||
114
client/src/pages/Admin/Images.tsx
Normal file
114
client/src/pages/Admin/Images.tsx
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableRow,
|
||||||
|
TableHead,
|
||||||
|
IconButton,
|
||||||
|
Paper,
|
||||||
|
Box,
|
||||||
|
CircularProgress,
|
||||||
|
Button,
|
||||||
|
Typography
|
||||||
|
} from "@mui/material";
|
||||||
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
|
import { ImageType } from "../../Types/ImageType";
|
||||||
|
import ApiService from '../../services/ApiService';
|
||||||
|
|
||||||
|
const Images: React.FC = () => {
|
||||||
|
const [images, setImages] = useState<ImageType[]>([]);
|
||||||
|
const [totalImg, setTotalImg] = useState(0);
|
||||||
|
const [imgPage, setImgPage] = useState(1);
|
||||||
|
const [imgLimit] = useState(10);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const fetchImages = async (page: number, limit: number) => {
|
||||||
|
setLoading(true);
|
||||||
|
const data = await ApiService.getImages(page, limit);
|
||||||
|
setImages(data.images);
|
||||||
|
setTotalImg(data.total);
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchImages(imgPage, imgLimit);
|
||||||
|
}, [imgPage]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleDelete = async (id: string) => {
|
||||||
|
setLoading(true);
|
||||||
|
const isDeleted = await ApiService.deleteImage(id);
|
||||||
|
setLoading(false);
|
||||||
|
if (isDeleted) {
|
||||||
|
setImages(images.filter(image => image.id !== id));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNextPage = () => {
|
||||||
|
if ((imgPage * imgLimit) < totalImg) {
|
||||||
|
setImgPage(prev => prev + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePrevPage = () => {
|
||||||
|
if (imgPage > 1) {
|
||||||
|
setImgPage(prev => prev - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box p={3}>
|
||||||
|
{loading ? (
|
||||||
|
<Box display="flex" justifyContent="center" alignItems="center" height={200}>
|
||||||
|
<CircularProgress />
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell></TableCell>
|
||||||
|
<TableCell>Nom</TableCell>
|
||||||
|
<TableCell>Image ID</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{images.map((obj: ImageType) => (
|
||||||
|
<TableRow key={obj.id}>
|
||||||
|
<TableCell>
|
||||||
|
<img
|
||||||
|
src={`data:${obj.mime_type};base64,${obj.file_content}`}
|
||||||
|
alt={`Image ${obj.file_name}`}
|
||||||
|
style={{ width: 350, height: "auto", borderRadius: 8 }}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{obj.file_name}</TableCell>
|
||||||
|
<TableCell style={{ minWidth: 150 }}>
|
||||||
|
{obj.id}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<IconButton onClick={() => handleDelete(obj.id)} color="error">
|
||||||
|
<DeleteIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
)}
|
||||||
|
<Box display="flex" justifyContent="center" mt={2}>
|
||||||
|
<Button onClick={handlePrevPage} disabled={imgPage === 1} color="primary">
|
||||||
|
Précédent
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleNextPage} disabled={(imgPage * imgLimit) >= totalImg} color="primary">
|
||||||
|
Suivant
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Images;
|
||||||
57
client/src/pages/Admin/Stats.tsx
Normal file
57
client/src/pages/Admin/Stats.tsx
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton } from "@mui/material";
|
||||||
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
|
import ApiService from '../../services/ApiService';
|
||||||
|
import { QuizTypeShort } from "../../Types/QuizType";
|
||||||
|
|
||||||
|
const Users: React.FC = () => {
|
||||||
|
const [quizzes, setQuizzes] = useState<QuizTypeShort[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchUsers = async () => {
|
||||||
|
try {
|
||||||
|
const data = await ApiService.getQuizzes();
|
||||||
|
setQuizzes(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching quizzes:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchUsers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDelete = (id: string) => {
|
||||||
|
setQuizzes(quizzes.filter(quiz => quiz._id !== id));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableContainer component={Paper} className="p-4">
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Enseignant</TableCell>
|
||||||
|
<TableCell>Titre</TableCell>
|
||||||
|
<TableCell>Crée</TableCell>
|
||||||
|
<TableCell>Modifié</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{quizzes.map((quiz) => (
|
||||||
|
<TableRow key={quiz._id}>
|
||||||
|
<TableCell>{quiz.userId}</TableCell>
|
||||||
|
<TableCell>{quiz.title}</TableCell>
|
||||||
|
<TableCell>{new Date(quiz.created_at).toLocaleDateString()}</TableCell>
|
||||||
|
<TableCell>{new Date(quiz.updated_at).toLocaleDateString()}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<IconButton onClick={() => handleDelete(quiz._id)} color="error">
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Users;
|
||||||
57
client/src/pages/Admin/Users.tsx
Normal file
57
client/src/pages/Admin/Users.tsx
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton } from "@mui/material";
|
||||||
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
|
import ApiService from '../../services/ApiService';
|
||||||
|
import { UserType } from "../../Types/UserType";
|
||||||
|
|
||||||
|
const Users: React.FC = () => {
|
||||||
|
const [users, setUsers] = useState<UserType[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchUsers = async () => {
|
||||||
|
try {
|
||||||
|
const data = await ApiService.getUsers();
|
||||||
|
setUsers(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching users:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchUsers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDelete = (email: string) => {
|
||||||
|
setUsers(users.filter(user => user.email !== email));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableContainer component={Paper} className="p-4">
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Nom</TableCell>
|
||||||
|
<TableCell>Courriel</TableCell>
|
||||||
|
<TableCell>Crée</TableCell>
|
||||||
|
<TableCell>Roles</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{users.map((user) => (
|
||||||
|
<TableRow key={user.email}>
|
||||||
|
<TableCell>{user.name}</TableCell>
|
||||||
|
<TableCell>{user.email}</TableCell>
|
||||||
|
<TableCell>{new Date(user.created_at).toLocaleDateString()}</TableCell>
|
||||||
|
<TableCell>{user.roles?.join(", ")}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<IconButton onClick={() => handleDelete(user.email)} color="error">
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Users;
|
||||||
|
|
@ -3,8 +3,10 @@ import { jwtDecode } from 'jwt-decode';
|
||||||
import { ENV_VARIABLES } from '../constants';
|
import { ENV_VARIABLES } from '../constants';
|
||||||
|
|
||||||
import { FolderType } from 'src/Types/FolderType';
|
import { FolderType } from 'src/Types/FolderType';
|
||||||
import { QuizType } from 'src/Types/QuizType';
|
import { QuizType, QuizTypeShort } from 'src/Types/QuizType';
|
||||||
import { RoomType } from 'src/Types/RoomType';
|
import { RoomType } from 'src/Types/RoomType';
|
||||||
|
import { UserType } from 'src/Types/UserType';
|
||||||
|
import { ImagesResponse, ImagesParams } from 'src/Types/ImageType';
|
||||||
|
|
||||||
type ApiResponse = boolean | string;
|
type ApiResponse = boolean | string;
|
||||||
|
|
||||||
|
|
@ -1009,6 +1011,7 @@ public async login(email: string, password: string): Promise<any> {
|
||||||
return `Une erreur inattendue s'est produite.`;
|
return `Une erreur inattendue s'est produite.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getRoomTitle(roomId: string): Promise<string | string> {
|
public async getRoomTitle(roomId: string): Promise<string | string> {
|
||||||
try {
|
try {
|
||||||
if (!roomId) {
|
if (!roomId) {
|
||||||
|
|
@ -1167,8 +1170,120 @@ public async login(email: string, password: string): Promise<any> {
|
||||||
return `ERROR : Une erreur inattendue s'est produite.`
|
return `ERROR : Une erreur inattendue s'est produite.`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// NOTE : Get Image pas necessaire
|
|
||||||
|
|
||||||
|
public async getUsers(): Promise<UserType[]> {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const url: string = this.constructRequestUrl(`/admin/getUsers`);
|
||||||
|
const headers = this.constructRequestHeaders();
|
||||||
|
const result: AxiosResponse = await axios.get(url, { headers });
|
||||||
|
|
||||||
|
if (result.status !== 200) {
|
||||||
|
throw new Error(`L'obtention des titres des salles a échoué. Status: ${result.status}`);
|
||||||
|
}
|
||||||
|
console.log(result.data);
|
||||||
|
|
||||||
|
return result.data.users;
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error details: ", error);
|
||||||
|
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
const err = error as AxiosError;
|
||||||
|
const data = err.response?.data as { error: string } | undefined;
|
||||||
|
const msg = data?.error || 'Erreur serveur inconnue lors de la requête.';
|
||||||
|
throw new Error(`L'enregistrement a échoué. Status: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`ERROR : Une erreur inattendue s'est produite.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getImages(page: number, limit: number): Promise<ImagesResponse> {
|
||||||
|
try {
|
||||||
|
const url: string = this.constructRequestUrl(`/admin/getImages`);
|
||||||
|
const headers = this.constructRequestHeaders();
|
||||||
|
let params : ImagesParams = { page: page, limit: limit };
|
||||||
|
|
||||||
|
const result: AxiosResponse = await axios.get(url, { params: params, headers: headers });
|
||||||
|
|
||||||
|
if (result.status !== 200) {
|
||||||
|
throw new Error(`L'affichage des images a échoué. Status: ${result.status}`);
|
||||||
|
}
|
||||||
|
console.log(result.data);
|
||||||
|
const images = result.data.data;
|
||||||
|
|
||||||
|
return images;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error details: ", error);
|
||||||
|
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
const err = error as AxiosError;
|
||||||
|
const data = err.response?.data as { error: string } | undefined;
|
||||||
|
const msg = data?.error || 'Erreur serveur inconnue lors de la requête.';
|
||||||
|
throw new Error(`L'enregistrement a échoué. Status: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`ERROR : Une erreur inattendue s'est produite.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteImage(imgId: string): Promise<ApiResponse> {
|
||||||
|
try {
|
||||||
|
const url: string = this.constructRequestUrl(`/admin/deleteImage`);
|
||||||
|
const headers = this.constructRequestHeaders();
|
||||||
|
let params = { imgId: imgId };
|
||||||
|
|
||||||
|
const result: AxiosResponse = await axios.delete(url, { params: params, headers: headers });
|
||||||
|
|
||||||
|
if (result.status !== 200) {
|
||||||
|
throw new Error(`La suppression de l'image a échoué. Status: ${result.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleted = result.data.deleted;
|
||||||
|
return deleted;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error details: ", error);
|
||||||
|
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
const err = error as AxiosError;
|
||||||
|
const data = err.response?.data as { error: string } | undefined;
|
||||||
|
const msg = data?.error || 'Erreur serveur inconnue lors de la requête.';
|
||||||
|
throw new Error(`L'enregistrement a échoué. Status: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`ERROR : Une erreur inattendue s'est produite.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getQuizzes(): Promise<QuizTypeShort[]> {
|
||||||
|
try {
|
||||||
|
const url: string = this.constructRequestUrl(`/admin/getQuizzes`);
|
||||||
|
const headers = this.constructRequestHeaders();
|
||||||
|
const result: AxiosResponse = await axios.get(url, { headers });
|
||||||
|
|
||||||
|
if (result.status !== 200) {
|
||||||
|
throw new Error(`L'affichage des images a échoué. Status: ${result.status}`);
|
||||||
|
}
|
||||||
|
const quiz = result.data.quizzes;
|
||||||
|
|
||||||
|
return quiz;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error details: ", error);
|
||||||
|
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
const err = error as AxiosError;
|
||||||
|
const data = err.response?.data as { error: string } | undefined;
|
||||||
|
const msg = data?.error || 'Erreur serveur inconnue lors de la requête.';
|
||||||
|
throw new Error(`L'enregistrement a échoué. Status: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`ERROR : Une erreur inattendue s'est produite.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiService = new ApiService();
|
const apiService = new ApiService();
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class AdminController {
|
||||||
|
|
||||||
const imgs = await this.model.getImages(page, limit);
|
const imgs = await this.model.getImages(page, limit);
|
||||||
|
|
||||||
return res.status(200).json({ imgs });
|
return res.status(200).json({ data: imgs });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(error);
|
return next(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,27 +38,13 @@ class Admin {
|
||||||
const conn = this.db.getConnection();
|
const conn = this.db.getConnection();
|
||||||
|
|
||||||
const quizColl = conn.collection('files');
|
const quizColl = conn.collection('files');
|
||||||
|
const projection = { content: 0, folderName: 0, folderId: 0 };
|
||||||
const result = await quizColl.find({}).toArray();
|
const result = await quizColl.find({}, projection).toArray();
|
||||||
|
|
||||||
if (!result) return null;
|
if (!result) return null;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteQuiz(id) {
|
|
||||||
let deleted = false;
|
|
||||||
await this.db.connect()
|
|
||||||
const conn = this.db.getConnection();
|
|
||||||
|
|
||||||
const quizColl = conn.collection('files');
|
|
||||||
|
|
||||||
const result = await quizColl.deleteOne({ _id: ObjectId.createFromHexString(id) });
|
|
||||||
|
|
||||||
if (result) deleted = true;
|
|
||||||
|
|
||||||
return deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getImages(page, limit) {
|
async getImages(page, limit) {
|
||||||
await this.db.connect()
|
await this.db.connect()
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ router.get("/getUsers", asyncHandler(admin.getUsers));
|
||||||
router.get("/getQuizzes", asyncHandler(admin.getQuizzes));
|
router.get("/getQuizzes", asyncHandler(admin.getQuizzes));
|
||||||
router.get("/getImages", asyncHandler(admin.getImages));
|
router.get("/getImages", asyncHandler(admin.getImages));
|
||||||
router.delete("/deleteUser", asyncHandler(admin.deleteUser));
|
router.delete("/deleteUser", asyncHandler(admin.deleteUser));
|
||||||
router.delete("/deleteQuiz", asyncHandler(admin.deleteQuiz));
|
|
||||||
router.delete("/deleteImage", jwt.authenticate, asyncHandler(admin.deleteImage));
|
router.delete("/deleteImage", jwt.authenticate, asyncHandler(admin.deleteImage));
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue