Skip to content
Snippets Groups Projects
Commit f20066b1 authored by Jessie Ragot's avatar Jessie Ragot
Browse files

Authentification functional, session management optimal for doctor, upload of...

Authentification functional, session management optimal for doctor, upload of documents in MedicalFile to be handed in
parent 70de54d6
Branches
No related tags found
1 merge request!19[feature]models-change+authentification+registration
Showing
with 157 additions and 182 deletions
......@@ -52,14 +52,19 @@ public class DatabaseSeeder implements CommandLineRunner {
MedicalFile file2 = new MedicalFile(patient2, "Pollen", "Bisoprolol");
medicalFileRepository.saveAll(List.of(file1, file2));
patient1.setMedicalFile(file1);
patient2.setMedicalFile(file2);
patientRepository.saveAll(List.of(patient1, patient2));
addDefaultDocument(file1, "documents/exemple1.pdf", "Rapport Médical.pdf");
addDefaultDocument(file2, "documents/exemple2.pdf", "Résultat Analyse.pdf");
medicalFileRepository.saveAll(List.of(file1, file2));
HealthHistorical history1 = new HealthHistorical("Asthme", "Consultation pour suivi annuel", LocalDate.parse("2023-10-10"), file1);
HealthHistorical history2 = new HealthHistorical("Hypertension", "Consultation pour traitement du cœur", LocalDate.parse("2023-09-15"), file2);
file1.getHealthHistoricalList().add(history1);
file2.getHealthHistoricalList().add(history2);
patient1.setMedicalFile(file1);
patient2.setMedicalFile(file2);
patientRepository.saveAll(List.of(patient1, patient2));
Appointment appointment1 = new Appointment(patient1, doctor1, LocalDateTime.now().plusDays(2), AppointmentStatus.CONFIRMED, "Consultation de suivi");
Appointment appointment2 = new Appointment(patient2, doctor2, LocalDateTime.now().plusDays(7), AppointmentStatus.PENDING, "Bilan annuel");
appointmentRepository.saveAll(List.of(appointment1, appointment2));
......
......@@ -4,13 +4,11 @@ import com.projet.projetIndu.entities.Doctor;
import com.projet.projetIndu.services.DoctorService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/doctors")
@Controller
public class DoctorController {
private final DoctorService doctorService;
......@@ -20,7 +18,7 @@ public class DoctorController {
this.doctorService = doctorService;
}
@GetMapping("/doctors")
@GetMapping
public String doctors(Model model) {
List<Doctor> doctors = doctorService.getAllDoctors();
model.addAttribute("doctors", doctors);
......@@ -28,27 +26,27 @@ public class DoctorController {
}
// Formulaire pour ajouter un médecin
@GetMapping("/create-doctor")
@GetMapping("/create")
public String showCreateForm(Model model) {
model.addAttribute("doctor", new Doctor());
return "create-doctor";
}
// POST pour enregistrer un médecin
@PostMapping("/doctors")
@PostMapping
public String createDoctor(@ModelAttribute Doctor doctor) {
doctorService.saveDoctor(doctor);
return "redirect:/doctors";
}
@GetMapping("doctors/search")
@GetMapping("/search")
public String searchDoctor(@RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName, Model model) {
List<Doctor> doctors = doctorService.getDoctorByName(firstName, lastName);
model.addAttribute("doctors", doctors);
return "doctors";
}
@GetMapping("/doctors/dashboard")
@GetMapping("/dashboard")
public String showDoctorDashboard(Model model) {
return "doctor-dashboard";
}
......
......@@ -32,10 +32,12 @@ public class MedicalFileController {
@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";
}
// Afficher un dossier médical spécifique
@GetMapping("/{id}")
public String viewMedicalFile(@PathVariable Long id, Model model) {
......@@ -67,37 +69,38 @@ public class MedicalFileController {
// Ajouter un document à un dossier médical
@PostMapping("/{id}/documents")
public String uploadMedicalFileDocument(@PathVariable Long id, @RequestParam("document") MultipartFile document) {
public String uploadMedicalFileDocument(@PathVariable Long id, @RequestParam("document") MultipartFile document, RedirectAttributes redirectAttributes) {
try {
medicalFileService.uploadMedicalFileDocument(id, document);
} catch (IOException e) {
e.printStackTrace();
return "error";
redirectAttributes.addFlashAttribute("errorMessage", "Erreur lors de l'upload du document.");
return "redirect:/medical-files/" + id;
}
return "redirect:/medical-files/" + id;
}
// Télécharger un document médical
@GetMapping("/{id}/documents/{docId}")
@ResponseBody
public ResponseEntity<byte[]> getMedicalFileDocument(@PathVariable Long id, @PathVariable Long docId) {
Optional<MedicalDocument> document = medicalDocumentRepository.findById(docId);
if (document.isPresent()) {
byte[] documentData = document.get().getFileData();
try {
MedicalDocument document = medicalFileService.getMedicalFileDocument(id, docId);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDisposition(ContentDisposition.attachment()
.filename(document.get().getFileName())
.filename(document.getFileName())
.build());
return new ResponseEntity<>(documentData, headers, HttpStatus.OK);
return new ResponseEntity<>(document.getFileData(), headers, HttpStatus.OK);
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
// Supprimer un document médical
@DeleteMapping("/{id}/documents/{docId}")
public String deleteDocument(@PathVariable Long id, @PathVariable Long docId, RedirectAttributes redirectAttributes) {
......@@ -113,10 +116,17 @@ public class MedicalFileController {
return "redirect:/medical-files/" + id;
}
// Supprimer un dossier médical
@DeleteMapping("/{id}")
public String deleteMedicalFile(@PathVariable Long id) {
public String deleteMedicalFile(@PathVariable Long id, RedirectAttributes redirectAttributes) {
try {
medicalFileService.deleteMedicalFileById(id);
redirectAttributes.addFlashAttribute("successMessage", "Dossier médical supprimé avec succès.");
} catch (Exception e) {
redirectAttributes.addFlashAttribute("errorMessage", "Erreur lors de la suppression du dossier médical.");
}
return "redirect:/medical-files";
}
}
......@@ -6,7 +6,6 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Entity
@Data
......@@ -25,4 +24,11 @@ public class HealthHistorical {
@JoinColumn(name = "medical_file_id", nullable = false)
private MedicalFile medicalFile;
public HealthHistorical(String antecedent, String notes, LocalDate consultationDate, MedicalFile medicalFile) {
this.antecedent = antecedent;
this.notes = notes;
this.consultationDate = consultationDate;
this.medicalFile = medicalFile;
}
}
\ No newline at end of file
......@@ -36,7 +36,7 @@ public class CustomUserDetailsService implements UserDetailsService {
return org.springframework.security.core.userdetails.User.builder()
.username(user.getEmail())
.password(user.getPassword())
.authorities("ROLE_" + user.getRole())
.authorities(String.valueOf(user.getRole()))
.build();
}
......
......@@ -7,6 +7,7 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
......@@ -25,11 +26,12 @@ public class SecurityConfig {
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login", "/register", "/css/**", "/js/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/doctors/**").hasRole("DOCTOR")
.requestMatchers("/patients/**").hasRole("PATIENT")
.anyRequest().permitAll()
.requestMatchers("/admin/**").hasAuthority("ADMIN")
.requestMatchers("/doctors/**").hasAuthority("DOCTOR")
.requestMatchers("/patients/**").hasAuthority("PATIENT")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.usernameParameter("email")
......@@ -41,14 +43,13 @@ public class SecurityConfig {
String role = authentication.getAuthorities().iterator().next().getAuthority();
switch (role) {
case "ROLE_ADMIN" -> response.sendRedirect("/admin/dashboard");
case "ROLE_DOCTOR" -> response.sendRedirect("/doctors/dashboard");
case "ROLE_PATIENT" -> response.sendRedirect("/patients/dashboard");
case "ADMIN" -> response.sendRedirect("/admin/dashboard");
case "DOCTOR" -> response.sendRedirect("/doctors/dashboard");
case "PATIENT" -> response.sendRedirect("/patients/dashboard");
default -> response.sendRedirect("/");
}
})
.failureHandler((request, response, exception) -> {
response.sendRedirect("/login?error=true");
})
......@@ -83,5 +84,10 @@ public class SecurityConfig {
return new ProviderManager(provider);
}
@Bean
public GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("");
}
}
\ No newline at end of file
......@@ -10,7 +10,6 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
......@@ -49,20 +48,26 @@ public class MedicalFileService {
healthHistorical.setAntecedent(antecedent);
healthHistorical.setNotes(notes);
healthHistorical.setConsultationDate(consultationDate);
healthHistorical.setMedicalFile(medicalFile);
medicalFile.getHealthHistoricalList().add(healthHistorical);
medicalFileRepository.save(medicalFile);
} else {
throw new RuntimeException("Dossier médical introuvable.");
}
}
public void uploadMedicalFileDocument(Long medicalFileId, MultipartFile file) throws IOException {
MedicalFile medicalFile = medicalFileRepository.findById(medicalFileId)
.orElseThrow(() -> new RuntimeException("Dossier médical introuvable"));
if (file.getSize() > 10 * 1024 * 1024) {
throw new RuntimeException("Le fichier est trop volumineux.");
}
MedicalDocument document = new MedicalDocument();
document.setFileName(file.getOriginalFilename());
document.setFileType(file.getContentType());
......@@ -74,93 +79,39 @@ public class MedicalFileService {
}
public void deleteHealthHistorical(Long medicalFileId, Long healthHistoricalId) {
Optional<MedicalFile> optionalMedicalFile = medicalFileRepository.findById(medicalFileId);
if (optionalMedicalFile.isPresent()) {
MedicalFile medicalFile = optionalMedicalFile.get();
}
HealthHistorical healthHistorical = medicalFile.getHealthHistoricalList().stream()
.filter(h -> h.getId().equals(healthHistoricalId))
.findFirst()
.orElseThrow(() -> new RuntimeException("Antécédent médical introuvable."));
medicalFile.getHealthHistoricalList().remove(healthHistorical);
medicalFileRepository.save(medicalFile);
} else {
throw new RuntimeException("Dossier médical introuvable.");
}
}
public MedicalDocument getMedicalFileDocument(Long medicalFileId, Long documentId) {
Optional<MedicalFile> medicalFileOpt = medicalFileRepository.findById(medicalFileId);
if (medicalFileOpt.isEmpty()) {
throw new RuntimeException("Dossier médical introuvable.");
}
MedicalFile medicalFile = medicalFileOpt.get();
return medicalFile.getDocumentList().stream()
.filter(doc -> doc.getId().equals(documentId))
.findFirst()
.orElseThrow(() -> new RuntimeException("Document introuvable."));
}
/// / Pour le dur
//
// @PostConstruct
// public void init() { // Charger les données une seule fois
// Patient patient1 = new Patient(1L, "Pierre", "Martinez", "10/05/1980", "0654789652", "jean.dupont@email.com", "1 rue de Paris", "Pollen", "Aspirine");
// Doctor doctor1 = new Doctor(1L, "Jean", "Dupont", "Cardiologue", "jean.dupont@example.com");
//
// medicalFilesList.add(new MedicalFile(1L, patient1, doctor1, "Aucun antécédent majeur."));
// }
//
// public List<MedicalFile> getAllMedicalFiles() {
// return medicalFilesList;
// }
// public Optional<MedicalFile> getMedicalFileById(Long id) {
// return medicalFilesList.stream().filter(mf -> mf.getId().equals(id)).findFirst();
// }
// public void updateMedicalFile(Long id, String history) {
// medicalFilesList.stream()
// .filter(mf -> mf.getId().equals(id))
// .findFirst()
// .ifPresent(mf -> mf.setHistory(history)); // Mise à jour de l'historique
// }
/// Pour le codage en dur (à retirer ensuite avec la BDD)
// public List<MedicalFile> getAllMedicalFiles() {
// // Récupérer les patients et médecins en dur
// Patient patient1 = new Patient(1L, "Pierre", "Martinez", "10/05/1980", "0654789652", "jean.dupont@email.com", "1 rue de Paris", "Pollen", "Aspirine");
// Patient patient2 = new Patient(2L, "Marine", "Boz", "19/10/2001", "066666666", "marine.boz@email.com", "10 rue de Marseille", "Péniciline", "Bisoce");
// Patient patient3 = new Patient(3L, "Laurie", "Marie", "23/11/1994", "0778456985", "marie.durand@email.com", "2 avenue des Lilas", "Arachides", "Paracétamol");
//
// Doctor doctor1 = new Doctor(1L, "Jean", "Dupont", "Cardiologue", "jean.dupont@example.com");
// Doctor doctor2 = new Doctor(2L, "Marie", "Curie", "Radiologue", "marie.curie@example.com");
// Doctor doctor3 = new Doctor(3L, "Paul", "Durand", "Généraliste", "paul.durand@example.com");
//
// return Arrays.asList(
// new MedicalFile(1L, patient1, doctor1, "Aucun antécédent majeur."),
// new MedicalFile(2L, patient2, doctor2, "Allergie à la pénicilline."),
// new MedicalFile(3L, patient3, doctor3, "Diabète de type 2.")
// );
// }
// /// En dur
// public void updateMedicalFileDocument(Long id, byte[] document) {
// medicalFilesList.stream()
// .filter(mf -> mf.getId().equals(id))
// .findFirst()
// .ifPresent(mf -> mf.setDocuments(document)); // Mise à jour du document
// }
// // DUR
// public void saveMedicalFile(MedicalFile medicalFile) {
// medicalFileRepository.save(medicalFile); // Persiste en base
// }
// ///En dur
// public Optional<MedicalFile> getMedicalFileById(Long id) {
// List<MedicalFile> medicalFilesList = getAllMedicalFiles(); // Récupère les données en dur
// return medicalFilesList.stream()
// .filter(medicalFile -> medicalFile.getId().equals(id))
// .findFirst();
// }
//
// //En dur (remplace saveMedicalFiles pour l'instant)
// public void updateMedicalFile(Long id, String history, String documents) {
// List<MedicalFile> medicalFilesList = getAllMedicalFiles();
//
// for (MedicalFile file : medicalFilesList) {
// if (file.getId().equals(id)) {
// file.setHistory(history);
// file.setDocuments(documents.getBytes());
// break;
// }
// }
// }
// }
}
......
......@@ -10,11 +10,8 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import static com.projet.projetIndu.entities.Role.*;
@Service
......@@ -57,8 +54,9 @@ public class UserService implements UserDetailsService {
String encodedPassword = passwordEncoder.encode(userDTO.getPassword());
User user;
Role role;
try {
Role role = Role.valueOf(String.valueOf(userDTO.getRole())); // Conversion du String en Role Enum
role = Role.valueOf(String.valueOf(userDTO.getRole()));
switch (role) {
case DOCTOR -> {
......@@ -87,13 +85,13 @@ public class UserService implements UserDetailsService {
user.setPhoneNumber(userDTO.getPhoneNumber());
user.setEmail(userDTO.getEmail());
user.setPassword(encodedPassword);
user.setRole(role);
return userRepository.save(user);
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email)
......
spring.application.name=projetIndu
spring.datasource.url=jdbc:mysql://localhost:3306/projet
spring.datasource.username=root
spring.datasource.password=jessie
......@@ -7,13 +6,10 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=false
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB
spring.mvc.hiddenmethod.filter.enabled=true
spring.banner.location=banner.txt
......@@ -17,17 +17,27 @@
<tr>
<th>ID</th>
<th>Patient</th>
<th>Médecin</th>
<th>Historique</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="file : ${medicalFile}">
<!-- Afficher chaque dossier médical -->
<tr th:each="file : ${medicalFiles}">
<td th:text="${file.id}"></td>
<td th:text="${file.patient.firstName} + ' ' + ${file.patient.lastName}"></td>
<td th:text="${file.doctor.firstName} + ' ' + ${file.doctor.lastName}"></td>
<td th:text="${file.history}"></td>
<!-- Afficher l'historique médical -->
<td>
<ul>
<li th:each="history : ${file.healthHistoricalList}">
<p th:text="'Antécédent: ' + ${history.antecedent}"></p>
<p th:text="'Notes: ' + ${history.notes}"></p>
<p th:text="'Date Consultation: ' + ${history.consultationDate}"></p>
</li>
</ul>
</td>
<td>
<a th:href="@{/medical-files/{id}(id=${file.id})}" class="btn btn-info">Consulter</a>
</td>
......
......@@ -3,68 +3,63 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Détails du dossier médical</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<title>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">Détails du 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>
<h6 class="card-subtitle mb-2 text-muted">Médecin :
<span th:text="${medicalFile.doctor != null ? medicalFile.doctor.firstName : 'Inconnu'}"></span>
<span th:text="${medicalFile.doctor != null ? medicalFile.doctor.lastName : ''}"></span>
</h6>
<p class="card-text"><strong>Historique médical :</strong>
<span th:text="${medicalFile.history != null ? medicalFile.history : 'Non disponible'}"></span>
</p>
</div>
<!-- Titre du dossier médical -->
<h1 class="text-center mb-4">Dossier Médical de <span
th:text="${medicalFile.patient.firstName} + ' ' + ${medicalFile.patient.lastName}"></span></h1>
<!-- Formulaire de mise à jour de l'historique -->
<form method="post" th:action="@{/medical-files/{id}/history(id=${medicalFile.id})}">
<div class="mb-3">
<label class="form-label">Historique médical :</label>
<textarea class="form-control" name="history" th:text="${medicalFile.history}"></textarea>
<!-- Informations générales -->
<div class="card mb-4">
<div class="card-header bg-primary text-white">
<h3>Informations générales</h3>
</div>
<div class="card-body">
<p><strong>Allergies:</strong> <span th:text="${medicalFile.allergy}"></span></p>
<p><strong>Traitement:</strong> <span th:text="${medicalFile.treatment}"></span></p>
</div>
</div>
<button type="submit" class="btn btn-success">Mettre à jour l'historique</button>
</form>
<!-- Formulaire de téléchargement du document -->
<form method="post" th:action="@{/medical-files/{id}/documents(id=${medicalFile.id})}" enctype="multipart/form-data">
<label for="file">Importer un document :</label>
<input type="file" name="document" id="file" class="form-control mb-2"/>
<button type="submit" class="btn btn-primary">Uploader le document</button>
</form>
<!-- Historique médical -->
<div class="card mb-4">
<div class="card-header bg-success text-white">
<h3>Historique médical</h3>
</div>
<div class="card-body">
<ul>
<li th:each="history : ${medicalFile.healthHistoricalList}">
<p><strong>Antécédent:</strong> <span th:text="${history.antecedent}"></span></p>
<p><strong>Notes:</strong> <span th:text="${history.notes}"></span></p>
<p><strong>Date de consultation:</strong> <span th:text="${history.consultationDate}"></span></p>
</li>
</ul>
</div>
</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.documents}" 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})}" class="btn btn-sm btn-warning">
Télécharger
</a>
<form th:action="@{/medical-files/{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" onclick="return confirm('Voulez-vous vraiment supprimer ce document ?');">
Supprimer
</button>
</form>
<!-- Documents -->
<div class="card mb-4">
<div class="card-header bg-info text-white">
<h3>Documents</h3>
</div>
<div class="card-body">
<ul>
<li th:each="document : ${medicalFile.documentList}">
<a th:href="@{/medical-files/{id}/documents/{docId}(id=${medicalFile.id}, docId=${document.id})}"
class="btn btn-link" th:text="${document.fileName}"></a>
</li>
</ul>
</div>
</div>
<!-- Retour à la liste -->
<a href="/medical-files" class="btn btn-secondary mt-3">Retour à la liste</a>
<a href="/medical-files" 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>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment