From 687a7e8d3fa4258fc8b63b4ed1a5d6902e6c5850 Mon Sep 17 00:00:00 2001 From: Jessie Ragot <jessie.ragot@hotmail.com> Date: Thu, 6 Mar 2025 16:45:55 +0100 Subject: [PATCH] Change of MedicalFile to secure routes and ensure that authenticated patients can only see their medical records and doctors can see all MedicalFiles. --- ....java => DoctorMedicalFileController.java} | 44 +++++------ .../PatientMedicalFileController.java | 73 +++++++++++++++++++ .../repositories/MedicalFileRepository.java | 3 + .../services/MedicalFileService.java | 4 + .../resources/templates/appointments.html | 1 - .../resources/templates/doctor-dashboard.html | 3 +- ...l-files.html => medical-files-doctor.html} | 7 +- .../templates/medical-files-patient.html | 55 ++++++++++++++ .../templates/patient-dashboard.html | 6 +- ...ile.html => view-medical-file-doctor.html} | 11 +-- 10 files changed, 167 insertions(+), 40 deletions(-) rename src/main/java/com/projet/projetIndu/controllers/{MedicalFileController.java => DoctorMedicalFileController.java} (80%) create mode 100644 src/main/java/com/projet/projetIndu/controllers/PatientMedicalFileController.java rename src/main/resources/templates/{medical-files.html => medical-files-doctor.html} (82%) create mode 100644 src/main/resources/templates/medical-files-patient.html rename src/main/resources/templates/{view-medical-file.html => view-medical-file-doctor.html} (84%) diff --git a/src/main/java/com/projet/projetIndu/controllers/MedicalFileController.java b/src/main/java/com/projet/projetIndu/controllers/DoctorMedicalFileController.java similarity index 80% rename from src/main/java/com/projet/projetIndu/controllers/MedicalFileController.java rename to src/main/java/com/projet/projetIndu/controllers/DoctorMedicalFileController.java index c8bad47..6adfe0d 100644 --- a/src/main/java/com/projet/projetIndu/controllers/MedicalFileController.java +++ b/src/main/java/com/projet/projetIndu/controllers/DoctorMedicalFileController.java @@ -13,17 +13,16 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes; import java.io.IOException; import java.time.LocalDate; -import java.util.List; import java.util.Optional; @Controller -@RequestMapping("/medical-files") -public class MedicalFileController { +@RequestMapping("/doctors/medical-files-doctor") +public class DoctorMedicalFileController { private final MedicalFileService medicalFileService; private final MedicalDocumentRepository medicalDocumentRepository; - public MedicalFileController(MedicalFileService medicalFileService, MedicalDocumentRepository medicalDocumentRepository) { + public DoctorMedicalFileController(MedicalFileService medicalFileService, MedicalDocumentRepository medicalDocumentRepository) { this.medicalFileService = medicalFileService; this.medicalDocumentRepository = medicalDocumentRepository; } @@ -31,29 +30,27 @@ public class MedicalFileController { // Afficher tous les dossiers médicaux @GetMapping public String listMedicalFiles(Model model) { - List<MedicalFile> medicalFiles = medicalFileService.getAllMedicalFiles(); - System.out.println("Dossiers médicaux récupérés : " + medicalFiles.size()); - model.addAttribute("medicalFiles", medicalFiles); - return "medical-files"; + model.addAttribute("medicalFiles", medicalFileService.getAllMedicalFiles()); + return "medical-files-doctor"; } - // Afficher un dossier médical spécifique @GetMapping("/{id}") public String viewMedicalFile(@PathVariable Long id, Model model) { - return medicalFileService.getMedicalFileById(id) - .map(medicalFile -> { - model.addAttribute("medicalFile", medicalFile); - return "view-medical-file"; - }) - .orElse("error"); + MedicalFile medicalFile = medicalFileService.getMedicalFileById(id).orElse(null); + if (medicalFile != null) { + model.addAttribute("medicalFile", medicalFile); + return "view-medical-file-doctor"; + } + model.addAttribute("errorMessage", "Dossier introuvable."); + return "error"; } // Créer un dossier médical @PostMapping("/create") public String createMedicalFile(@ModelAttribute MedicalFile medicalFile) { medicalFileService.saveMedicalFiles(medicalFile); - return "redirect:/medical-files"; + return "redirect:/doctors/medical-files-doctor"; } // Mettre à jour l'historique médical @@ -63,10 +60,9 @@ public class MedicalFileController { @RequestParam String notes, @RequestParam LocalDate consultationDate) { medicalFileService.updateMedicalFileHistory(id, antecedent, notes, consultationDate); - return "redirect:/medical-files/" + id; + return "redirect:/doctors/medical-files-doctor/" + id; } - // Ajouter un document à un dossier médical @PostMapping("/{id}/documents") public String uploadMedicalFileDocument(@PathVariable Long id, @RequestParam("document") MultipartFile document, RedirectAttributes redirectAttributes) { @@ -75,12 +71,11 @@ public class MedicalFileController { } catch (IOException e) { e.printStackTrace(); redirectAttributes.addFlashAttribute("errorMessage", "Erreur lors de l'upload du document."); - return "redirect:/medical-files/" + id; + return "redirect:/doctors/medical-files-doctor/" + id; } - return "redirect:/medical-files/" + id; + return "redirect:/doctors/medical-files-doctor/" + id; } - // Télécharger un document médical @GetMapping("/{id}/documents/{docId}") @ResponseBody @@ -100,7 +95,6 @@ public class MedicalFileController { } } - // Supprimer un document médical @DeleteMapping("/{id}/documents/{docId}") public String deleteDocument(@PathVariable Long id, @PathVariable Long docId, RedirectAttributes redirectAttributes) { @@ -113,10 +107,9 @@ public class MedicalFileController { redirectAttributes.addFlashAttribute("errorMessage", "Document introuvable."); } - return "redirect:/medical-files/" + id; + return "redirect:/doctors/medical-files-doctor/" + id; } - // Supprimer un dossier médical @DeleteMapping("/{id}") public String deleteMedicalFile(@PathVariable Long id, RedirectAttributes redirectAttributes) { @@ -126,7 +119,6 @@ public class MedicalFileController { } catch (Exception e) { redirectAttributes.addFlashAttribute("errorMessage", "Erreur lors de la suppression du dossier médical."); } - return "redirect:/medical-files"; + return "redirect:/doctors/medical-files-doctor"; } - } diff --git a/src/main/java/com/projet/projetIndu/controllers/PatientMedicalFileController.java b/src/main/java/com/projet/projetIndu/controllers/PatientMedicalFileController.java new file mode 100644 index 0000000..f47af20 --- /dev/null +++ b/src/main/java/com/projet/projetIndu/controllers/PatientMedicalFileController.java @@ -0,0 +1,73 @@ +package com.projet.projetIndu.controllers; + +import com.projet.projetIndu.entities.MedicalDocument; +import com.projet.projetIndu.entities.MedicalFile; +import com.projet.projetIndu.entities.Patient; +import com.projet.projetIndu.services.MedicalFileService; +import com.projet.projetIndu.services.PatientService; +import org.springframework.http.*; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@RequestMapping("/patients/medical-files-patient") +public class PatientMedicalFileController { + + private final MedicalFileService medicalFileService; + private final PatientService patientService; + + public PatientMedicalFileController(MedicalFileService medicalFileService, PatientService patientService) { + this.medicalFileService = medicalFileService; + this.patientService = patientService; + } + + // Afficher le dossier médical du patient connecté + @GetMapping + public String viewMedicalFile(Model model) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String currentUsername = authentication.getName(); // Récupérer l'email du patient authentifié + + // Récupérer le patient correspondant à cet email + Patient patient = patientService.getPatientByEmail(currentUsername).orElse(null); + + if (patient != null) { + // Récupérer le dossier médical pour ce patient (un seul dossier par patient) + MedicalFile medicalFile = medicalFileService.getMedicalFileByPatientId(patient.getId()).orElse(null); + + if (medicalFile != null) { + model.addAttribute("medicalFile", medicalFile); + return "medical-files-patient"; // Afficher le dossier médical + } + } + + model.addAttribute("errorMessage", "Dossier médical introuvable."); + return "error"; // Vue d'erreur si aucun dossier n'est trouvé + } + + + // Télécharger un document médical + @GetMapping("/{id}/documents/{docId}") + @ResponseBody + public ResponseEntity<byte[]> getMedicalFileDocument(@PathVariable Long id, @PathVariable Long docId) { + try { + MedicalDocument document = medicalFileService.getMedicalFileDocument(id, docId); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + headers.setContentDisposition(ContentDisposition.attachment() + .filename(document.getFileName()) + .build()); + + return new ResponseEntity<>(document.getFileData(), headers, HttpStatus.OK); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); + } + } +} + diff --git a/src/main/java/com/projet/projetIndu/repositories/MedicalFileRepository.java b/src/main/java/com/projet/projetIndu/repositories/MedicalFileRepository.java index 54f79cc..4841839 100644 --- a/src/main/java/com/projet/projetIndu/repositories/MedicalFileRepository.java +++ b/src/main/java/com/projet/projetIndu/repositories/MedicalFileRepository.java @@ -3,6 +3,9 @@ package com.projet.projetIndu.repositories; import com.projet.projetIndu.entities.MedicalFile; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface MedicalFileRepository extends JpaRepository<MedicalFile, Long> { + Optional<MedicalFile> findByPatientId(Long patientId); } diff --git a/src/main/java/com/projet/projetIndu/services/MedicalFileService.java b/src/main/java/com/projet/projetIndu/services/MedicalFileService.java index a789dea..89d02c2 100644 --- a/src/main/java/com/projet/projetIndu/services/MedicalFileService.java +++ b/src/main/java/com/projet/projetIndu/services/MedicalFileService.java @@ -110,6 +110,10 @@ public class MedicalFileService { .orElseThrow(() -> new RuntimeException("Document introuvable.")); } + public Optional<MedicalFile> getMedicalFileByPatientId(Long patientId) { + return medicalFileRepository.findByPatientId(patientId); + } + } diff --git a/src/main/resources/templates/appointments.html b/src/main/resources/templates/appointments.html index f529e14..cafccf1 100644 --- a/src/main/resources/templates/appointments.html +++ b/src/main/resources/templates/appointments.html @@ -39,7 +39,6 @@ </table> <a href="/doctors/appointments/create" class="btn btn-primary mt-3">Créer un nouveau rendez-vous</a> - <a href="/doctors/dashboard" class="btn btn-secondary mt-3">Retour au tableau de bord</a> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> diff --git a/src/main/resources/templates/doctor-dashboard.html b/src/main/resources/templates/doctor-dashboard.html index 6927532..b31bed1 100644 --- a/src/main/resources/templates/doctor-dashboard.html +++ b/src/main/resources/templates/doctor-dashboard.html @@ -31,7 +31,8 @@ <p class="mt-2 text-gray-600">Consulter et gérer la liste de vos patients.</p> </a> - <a href="/medical-files" class="p-6 bg-white shadow-md rounded-lg hover:shadow-lg transition"> + <a href="/doctors/medical-files-doctor" + class="p-6 bg-white shadow-md rounded-lg hover:shadow-lg transition"> <h3 class="text-xl font-semibold text-gray-800">Dossiers Médicaux</h3> <p class="mt-2 text-gray-600">Accéder aux dossiers médicaux de vos patients.</p> </a> diff --git a/src/main/resources/templates/medical-files.html b/src/main/resources/templates/medical-files-doctor.html similarity index 82% rename from src/main/resources/templates/medical-files.html rename to src/main/resources/templates/medical-files-doctor.html index 368bb30..e660738 100644 --- a/src/main/resources/templates/medical-files.html +++ b/src/main/resources/templates/medical-files-doctor.html @@ -4,8 +4,7 @@ <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Liste des dossiers médicaux</title> - <link rel="stylesheet" - href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"> </head> <body class="bg-light"> @@ -39,13 +38,13 @@ </td> <td> - <a th:href="@{/medical-files/{id}(id=${file.id})}" class="btn btn-info">Consulter</a> + <a th:href="@{/doctors/medical-files-doctor/{id}(id=${file.id})}" class="btn btn-info">Consulter</a> </td> </tr> </tbody> </table> - <a href="/" class="btn btn-primary mt-3">Retour à l'accueil</a> + <a href="/doctors/dashboard" class="btn btn-primary mt-3">Retour à l'accueil</a> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> diff --git a/src/main/resources/templates/medical-files-patient.html b/src/main/resources/templates/medical-files-patient.html new file mode 100644 index 0000000..77e6507 --- /dev/null +++ b/src/main/resources/templates/medical-files-patient.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Mon Dossier Médical</title> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"> +</head> +<body class="bg-light"> + +<div class="container mt-5"> + <h1 class="text-center mb-4">Mon Dossier Médical</h1> + + <div th:if="${medicalFile}"> + <h5 class="card-title">Dossier médical de : + <span th:text="${medicalFile.patient != null ? medicalFile.patient.firstName : 'Inconnu'}"></span> + <span th:text="${medicalFile.patient != null ? medicalFile.patient.lastName : ''}"></span> + </h5> + + <!-- Historique médical --> + <div class="mt-3"> + <h5>Historique médical :</h5> + <ul class="list-group"> + <li th:each="history : ${medicalFile.healthHistoricalList}" class="list-group-item"> + <strong>Antécédent:</strong> <span th:text="${history.antecedent}"></span><br> + <strong>Notes:</strong> <span th:text="${history.notes}"></span><br> + <strong>Date de consultation:</strong> <span th:text="${history.consultationDate}"></span> + </li> + </ul> + </div> + + <!-- Liste des documents avec lien de téléchargement --> + <div class="mt-3"> + <h5>Documents disponibles :</h5> + <ul class="list-group"> + <li th:each="doc : ${medicalFile.documentList}" + class="list-group-item d-flex justify-content-between align-items-center"> + <span th:text="${doc.fileName}"></span> + <div> + <a th:href="@{/patients/medical-files-patient/{id}/documents/{docId}(id=${medicalFile.id}, docId=${doc.id})}" + class="btn btn-sm btn-warning"> + Télécharger + </a> + </div> + </li> + </ul> + </div> + </div> + + <a href="/patients/dashboard" class="btn btn-primary mt-3">Retour à l'accueil</a> +</div> + +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> +</body> +</html> diff --git a/src/main/resources/templates/patient-dashboard.html b/src/main/resources/templates/patient-dashboard.html index ebb9bf3..78819ac 100644 --- a/src/main/resources/templates/patient-dashboard.html +++ b/src/main/resources/templates/patient-dashboard.html @@ -24,9 +24,9 @@ <p class="mt-2 text-gray-600">Voir les informations de votre médecin.</p> </a> - <a href="/medical-files" class="p-6 bg-white shadow-md rounded-lg hover:shadow-lg transition"> - <h3 class="text-xl font-semibold text-gray-800">Mes Dossiers Médicaux</h3> - <p class="mt-2 text-gray-600">Consulter vos dossiers médicaux.</p> + <a href="/patients/medical-files-patient" class="p-6 bg-white shadow-md rounded-lg hover:shadow-lg transition"> + <h3 class="text-xl font-semibold text-gray-800">Mon Dossier Médical</h3> + <p class="mt-2 text-gray-600">Consulter votre dossier médical.</p> </a> <a href="/patients/appointments" class="p-6 bg-white shadow-md rounded-lg hover:shadow-lg transition"> diff --git a/src/main/resources/templates/view-medical-file.html b/src/main/resources/templates/view-medical-file-doctor.html similarity index 84% rename from src/main/resources/templates/view-medical-file.html rename to src/main/resources/templates/view-medical-file-doctor.html index b336c37..b53f4c0 100644 --- a/src/main/resources/templates/view-medical-file.html +++ b/src/main/resources/templates/view-medical-file-doctor.html @@ -31,7 +31,8 @@ </div> <!-- Formulaire de téléchargement du document --> - <form method="post" th:action="@{/medical-files/{id}/documents(id=${medicalFile.id})}" enctype="multipart/form-data" + <form method="post" th:action="@{/doctors/medical-files-doctor/{id}/documents(id=${medicalFile.id})}" + enctype="multipart/form-data" class="mt-3"> <label for="file" class="form-label">Importer un document :</label> <input type="file" name="document" id="file" class="form-control mb-2"/> @@ -46,11 +47,11 @@ class="list-group-item d-flex justify-content-between align-items-center"> <span th:text="${doc.fileName}"></span> <div> - <a th:href="@{/medical-files/{id}/documents/{docId}(id=${medicalFile.id}, docId=${doc.id})}" + <a th:href="@{/doctors/medical-files-doctor/{id}/documents/{docId}(id=${medicalFile.id}, docId=${doc.id})}" class="btn btn-sm btn-warning"> Télécharger </a> - <form th:action="@{/medical-files/{id}/documents/{docId}(id=${medicalFile.id}, docId=${doc.id})}" + <form th:action="@{/doctors/medical-files-doctor/{id}/documents/{docId}(id=${medicalFile.id}, docId=${doc.id})}" method="post" class="d-inline"> <input type="hidden" name="_method" value="delete"/> <button type="submit" class="btn btn-sm btn-danger" @@ -63,9 +64,9 @@ </ul> </div> - <a href="/medical-files" class="btn btn-primary mt-3">Retour à la liste</a> + <a href="/doctors/medical-files-doctor" class="btn btn-primary mt-3">Retour à la liste</a> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> </body> -</html> \ No newline at end of file +</html> -- GitLab