From 7aec3400a7d249b1cfb0837ceb9fd021db3b9616 Mon Sep 17 00:00:00 2001 From: Gaspard Rivoire <36168128+GaspardRivoire@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:22:32 +0200 Subject: [PATCH] archiver un village front et back --- server/controllers/archive.ts | 54 ++++++++++++++- src/api/archive/archive.get.ts | 12 ++++ .../pelicoPresentation.get.ts | 18 ----- .../admin/manage/settings/ArchiveModal.tsx | 47 ------------- .../manage/settings/archive/index.tsx | 67 ++++++++++--------- 5 files changed, 99 insertions(+), 99 deletions(-) create mode 100644 src/api/archive/archive.get.ts delete mode 100644 src/components/admin/manage/settings/ArchiveModal.tsx diff --git a/server/controllers/archive.ts b/server/controllers/archive.ts index 0bdaa1e5f..6e4d32d56 100644 --- a/server/controllers/archive.ts +++ b/server/controllers/archive.ts @@ -1,3 +1,4 @@ +import AWS from 'aws-sdk'; import type { Request, Response, NextFunction } from 'express'; import { UserType } from '../entities/user'; @@ -7,7 +8,7 @@ import { Controller } from './controller'; const archiveController = new Controller('/archives'); // get file -archiveController.get({ path: '/*', userType: UserType.ADMIN }, async (req: Request, res: Response, next: NextFunction) => { +archiveController.get({ path: 'get-file/*', userType: UserType.ADMIN }, async (req: Request, res: Response, next: NextFunction) => { const url = decodeURI(req.url); const key = `archives${url}${url.split('/').length === 2 ? '/index.html' : url.indexOf('.') === -1 ? '.html' : ''}`; try { @@ -17,4 +18,55 @@ archiveController.get({ path: '/*', userType: UserType.ADMIN }, async (req: Requ } }); +/** + * Liste les dossiers dans un préfixe S3 spécifié. + * @param prefix - Le préfixe S3 à partir duquel lister les dossiers. + * @returns Une promesse qui résout avec un tableau de noms de dossiers. + */ +async function listS3Folders(prefix: string): Promise { + // Configurer le client S3 avec les informations d'identification et la région + const s3 = new AWS.S3({ + accessKeyId: process.env.S3_ACCESS_KEY, + secretAccessKey: process.env.S3_SECRET_KEY, + region: 'eu-west-3', + }); + + // Paramètres pour la requête S3 + const params: AWS.S3.ListObjectsV2Request = { + Bucket: process.env.S3_BUCKET_NAME, + Prefix: prefix, + Delimiter: '/', // Utiliser le délimiteur '/' pour obtenir uniquement les dossiers + }; + + try { + // Effectuer la requête pour lister les objets + const data = await s3.listObjectsV2(params).promise(); + + if (!data.CommonPrefixes) { + return []; + } + + // Extraire les noms de dossiers des préfixes communs + // Nettoyer les noms de dossiers (supprimer le préfixe et le délimiteur final) + return data.CommonPrefixes.map((prefixObj) => prefixObj.Prefix) + .filter((prefix): prefix is string => prefix !== undefined) + .map((folder) => folder.slice(prefix.length, -1)); + } catch (error) { + console.error('Error while listing S3 folders:', error); + throw error; + } +} + +archiveController.get({ path: '', userType: UserType.OBSERVATOR }, async (_req: Request, res: Response, next: NextFunction) => { + try { + const prefix = 'archives/'; + const archiveFolders = await listS3Folders(prefix); + res.sendJSON(archiveFolders); + } catch (error) { + console.error('Error while listing archived S3 folders:', error); + next(error); + return; + } +}); + export { archiveController }; diff --git a/src/api/archive/archive.get.ts b/src/api/archive/archive.get.ts new file mode 100644 index 000000000..e781cd039 --- /dev/null +++ b/src/api/archive/archive.get.ts @@ -0,0 +1,12 @@ +import axios from 'axios'; +import { useQuery } from 'react-query'; + +const BASE_URL = '/api/archives'; + +// Récupérer la liste des années déjà archivées +export const useListArchives = () => { + return useQuery(['archives'], async () => { + const { data } = await axios.get(`${BASE_URL}`); + return data; + }); +}; diff --git a/src/api/pelicoPresentation/pelicoPresentation.get.ts b/src/api/pelicoPresentation/pelicoPresentation.get.ts index c117336b0..25b269754 100644 --- a/src/api/pelicoPresentation/pelicoPresentation.get.ts +++ b/src/api/pelicoPresentation/pelicoPresentation.get.ts @@ -18,21 +18,3 @@ export const usePelicoPresentatations = () => { return data; }); }; - -// async function getPelicoPresentation(id: number) { -// const { data } = await axios.get(`${BASE_URL}/${id}`); -// return data; -// } - -// export const useGetPelicoPresentation = (id: number) => { -// return useQuery(['pelico-presentation'], getPelicoPresentation(id)); -// }; - -// async function getPelicoPresentations() { -// const { data } = await axios.get(`${BASE_URL}`); -// return data; -// } - -// export const useGetPelicoPresentations = () => { -// return useQuery(['pelico-presentation'], getPelicoPresentations); -// }; diff --git a/src/components/admin/manage/settings/ArchiveModal.tsx b/src/components/admin/manage/settings/ArchiveModal.tsx deleted file mode 100644 index cdb462251..000000000 --- a/src/components/admin/manage/settings/ArchiveModal.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React, { useState } from 'react'; - -import { TextField, Typography, Box } from '@mui/material'; - -import { Modal } from 'src/components/Modal'; - -interface ArchiveModalProps { - open: boolean; - onClose: () => void; - onConfirm: () => void; -} - -export function ArchiveModal({ open, onClose, onConfirm }: ArchiveModalProps) { - const [confirmText, setConfirmText] = useState(''); - - const handleConfirmTextChange = (event: React.ChangeEvent) => { - setConfirmText(event.target.value); - }; - - const isConfirmDisabled = confirmText !== 'jeconfirmevousloirarchiver'; - - return ( - - - - Archiver 1Village supprimera l'accès de tous les utilisateurs. C'est une action à faire en fin d'année. Merci d'écrire - "jeconfirmevousloirarchiver" dans l'espace ci-dessous pour pouvoir effectuer l'action. - - - - - - - ); -} diff --git a/src/pages/admin/newportal/manage/settings/archive/index.tsx b/src/pages/admin/newportal/manage/settings/archive/index.tsx index 21e8d03bd..f3654d69a 100644 --- a/src/pages/admin/newportal/manage/settings/archive/index.tsx +++ b/src/pages/admin/newportal/manage/settings/archive/index.tsx @@ -1,10 +1,10 @@ import Link from 'next/link'; -import React, { useState } from 'react'; +import { useSnackbar } from 'notistack'; +import React, { useEffect, useState } from 'react'; import { Typography, Box, List, ListItem } from '@mui/material'; -import { ArchiveModal } from 'src/components/admin/manage/settings/ArchiveModal'; -import { RedButton } from 'src/components/buttons/RedButton'; +import { useListArchives } from 'src/api/archive/archive.get'; import { UserContext } from 'src/contexts/userContext'; import BackArrow from 'src/svg/back-arrow.svg'; import { UserType } from 'types/user.type'; @@ -12,25 +12,26 @@ import { UserType } from 'types/user.type'; const Archive = () => { const { user } = React.useContext(UserContext); const hasAccess = user?.type === UserType.SUPER_ADMIN; - const archives = ['1V 2020/21', '1V 2021/22', '1V 2022/23']; - const [isModalOpen, setIsModalOpen] = useState(false); + const [archives, setArchives] = useState([]); + const { enqueueSnackbar } = useSnackbar(); + + const { data: listArchive, isError: listArchiveError, isLoading: listArchiveLoading } = useListArchives(); + + useEffect(() => { + if (listArchive) { + setArchives(listArchive); + } + if (listArchiveError) { + enqueueSnackbar("Une erreur s'est produite lors de la récuperation des archives existantes !", { + variant: 'error', + }); + } + }, [listArchive, listArchiveError, enqueueSnackbar]); if (!hasAccess) { return

Vous n'avez pas accès à cette page, vous devez être super admin.

; } - const handleArchiveClick = () => { - setIsModalOpen(true); - }; - - const handleModalClose = () => { - setIsModalOpen(false); - }; - - const handleArchiveConfirm = () => { - setIsModalOpen(false); - }; - return (
@@ -39,24 +40,24 @@ const Archive = () => {

Archiver

-

Archiver 1Village va fermer l'accès à tous les utilisateurs à la plateforme. Voilà les anciennes archives d'1Village :

+

Voilà la liste des archives existantes. Si tu souhaites effectuer une nouvelle archive d'1Village, adresse toi au pôle tech.

- - {archives.map((archive, index) => ( - - - {archive} - - - ))} - - - - Archiver - - + {listArchiveLoading ? ( +
Chargement...
+ ) : ( + + {archives.map((archive, index) => ( + + + + {archive} + + + + ))} + + )}
- ); };