diff --git a/pom.xml b/pom.xml
index 17b76ca6305e77c3c5b1f2781d78e72b0a1653da..4a6eede41af76662db97dc2dda70c2fd224ee4e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,9 +9,9 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>fr.but.infoetu</groupId>
- <artifactId>MeetingPlannr</artifactId>
+ <artifactId>meetingplannr</artifactId>
<version>0.0.1-SNAPSHOT</version>
- <name>MeetingPlannr</name>
+ <name>meetingplannr</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
@@ -69,6 +69,10 @@
<artifactId>tomcat-embed-jasper</artifactId>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingController.java b/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingController.java
index 5437580d9de2ad0576015e2b1f5cd8cf3a9e6b30..0a4606e9344e0489f7b630a08fff2d7ec44bc269 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingController.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingController.java
@@ -1,19 +1,29 @@
-package fr.but.infoetu.MeetingPlannr;
+package fr.but.infoetu.meetingplannr;
+import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
-import fr.but.infoetu.MeetingPlannr.pojo.User;
-import fr.but.infoetu.MeetingPlannr.repository.MeetingRepository;
-import fr.but.infoetu.MeetingPlannr.repository.RequestRepository;
-import fr.but.infoetu.MeetingPlannr.repository.UserRepository;
+import fr.but.infoetu.meetingplannr.pojo.Meeting;
+import fr.but.infoetu.meetingplannr.pojo.User;
+import fr.but.infoetu.meetingplannr.repository.MeetingRepository;
+import fr.but.infoetu.meetingplannr.repository.RequestRepository;
+import fr.but.infoetu.meetingplannr.repository.UserRepository;
+import fr.but.infoetu.meetingplannr.service.UserService;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
@@ -27,48 +37,220 @@ public class MeetingController {
@Autowired
RequestRepository rr;
- @RequestMapping(value = "login", method = RequestMethod.GET)
- private String loginForm(){
- return "login";
+ @Autowired
+ UserService userService;
+
+ @RequestMapping
+ private String redirectHome(HttpSession session) {
+ if (session.getAttribute("currentUser") == null) {
+ return "public/login";
+ }
+ return "user/listeAction";
}
- @RequestMapping(value = "login", method = RequestMethod.POST)
- private String loginFormPost(String email, String password, HttpSession session){
- Optional<User> userOpt = ur.findByEmail(email);
- if(userOpt.isPresent()){
- User user = userOpt.get();
- if(user.getPassword().equals(password)){
- session.setAttribute("currentUser", user);
- System.out.println("Bienvenue " + user.getSurname());
- return "listeAction";
- }
- }
- return "login";
+ @RequestMapping(value = "public/login", method = RequestMethod.GET)
+ private String loginForm(){
+ System.out.println("Is authenticated : " + isAuthenticated());
+ if (isAuthenticated()) {
+ return "redirect:/user/listeAction";
+ }
+ return "public/login";
}
- @RequestMapping(value = "register", method = RequestMethod.GET)
+ @RequestMapping(value = "public/register", method = RequestMethod.GET)
private String registerForm(){
- return "register";
+ if (isAuthenticated()) {
+ return "redirect:/user/listeAction";
+ }
+ return "public/register";
}
- @RequestMapping(value = "register", method = RequestMethod.POST)
- private String registerFormPost(@Valid User user, BindingResult res, Model model, HttpSession session){
- System.out.println(user);
- if(res.hasErrors()){
- return "register";
+ @RequestMapping(value = "public/register", method = RequestMethod.POST)
+ private String registerFormPost(@Valid User user, BindingResult res, Model model, HttpSession session) {
+ if (res.hasErrors()) {
+ StringBuilder errorMessage = new StringBuilder("Veuillez corriger les erreurs suivantes :<br>");
+ res.getFieldErrors().forEach(error -> errorMessage.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("<br>"));
+ model.addAttribute("errorMessage", errorMessage.toString());
+ return "public/register";
}
- Optional<User> userOpt = ur.findByEmail(user.getEmail());
- if(userOpt.isPresent()){
- return "login";
+ Optional<User> userOpt = ur.findByUsername(user.getUsername());
+ if (userOpt.isPresent()) {
+ model.addAttribute("errorMessage", "Cet email est déjà utilisé.");
+ return "public/register";
}
- ur.save(user);
+ userService.createUser(user);
session.setAttribute("currentUser", user);
- return "listeAction";
+ // Automatically log in the user
+ UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), user.getAuthorities());
+ SecurityContextHolder.getContext().setAuthentication(authToken);
+
+ return "redirect:/user/listeAction";
+ }
+
+ @RequestMapping(value = "user/listeAction", method = RequestMethod.GET)
+ private String listeAction(@AuthenticationPrincipal UserDetails details, Model model){
+ if (details == null) {
+ return "redirect:/public/login";
+ }
+ User user = ur.findByUsername(details.getUsername()).get();
+ model.addAttribute("currentUser", user);
+ return "user/listeAction";
+ }
+
+ @RequestMapping(value = "user/profile", method = RequestMethod.GET)
+ private String profile(@AuthenticationPrincipal UserDetails details, Model model) {
+ if (details == null) {
+ return "redirect:/public/login";
+ }
+ User user = ur.findByUsername(details.getUsername()).get();
+ model.addAttribute("currentUser", user);
+ return "user/profile";
+ }
+
+ @RequestMapping(value = "user/editProfile", method = RequestMethod.GET)
+ private String editProfile(@AuthenticationPrincipal UserDetails details, Model model) {
+ if (details == null) {
+ return "redirect:/public/login";
+ }
+ User user = ur.findByUsername(details.getUsername()).get();
+ model.addAttribute("currentUser", user);
+ return "user/editProfile";
+ }
+
+
+ @RequestMapping(value = "user/updateProfile", method = RequestMethod.POST)
+ private String updateProfile(User user, BindingResult res, Model model, @AuthenticationPrincipal UserDetails details) {
+ System.out.println(user);
+
+ if (res.hasErrors()) {
+ StringBuilder errorMessage = new StringBuilder("Veuillez corriger les erreurs suivantes :<br>");
+ res.getFieldErrors().forEach(error -> errorMessage.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("<br>"));
+ model.addAttribute("errorMessage", errorMessage.toString());
+ return "user/editProfile";
+ }
+
+ if (details == null) {
+ model.addAttribute("errorMessage", "Utilisateur non connecté.");
+ return "public/login";
+ }
+
+ User currentUser = ur.findByUsername(details.getUsername()).get();
+ Optional<User> existingUser = ur.findByUsername(user.getUsername());
+ if (existingUser.isPresent() && existingUser.get().getUno() != (currentUser.getUno())) {
+ model.addAttribute("errorMessage", "Cet email est déjà utilisé.");
+ return "user/editProfile";
+ }
+
+ currentUser.setName(user.getName());
+ currentUser.setSurname(user.getSurname());
+
+ ur.save(currentUser);
+
+ return "redirect:/user/profile";
+ }
+
+ @RequestMapping(value = "user/meetings", method = RequestMethod.GET)
+ private String meetings(@AuthenticationPrincipal UserDetails details, Model model) {
+ if (details == null) {
+ return "redirect:/public/login";
+ }
+ User user = ur.findByUsername(details.getUsername()).get();
+ List<Meeting> meetings = mr.findByUserOrderByDateAsc(user);
+ model.addAttribute("meetings", meetings);
+ model.addAttribute("currentUser", user);
+ return "user/rendezVous";
+ }
+
+ @RequestMapping(value = "user/meetings/detail/{mno}", method = RequestMethod.GET)
+ private String appointmentDetail(@PathVariable int mno, @AuthenticationPrincipal UserDetails details, Model model) {
+ if (details == null) {
+ return "redirect:/public/login";
+ }
+
+ Optional<Meeting> meetingOpt = mr.findById(mno);
+ if (!meetingOpt.isPresent()) {
+ return "redirect:/user/meetings";
+ }
+
+ Meeting meeting = meetingOpt.get();
+ User currentUser = ur.findByUsername(details.getUsername()).get();
+
+ model.addAttribute("meeting", meeting);
+ model.addAttribute("isOwner", meeting.getUser().getUno() == currentUser.getUno());
+
+ return "user/detailRendezVous";
+ }
+
+ @RequestMapping(value = "user/meetings/edit/{mno}", method = RequestMethod.GET)
+ private String editMeeting(@PathVariable int mno, @AuthenticationPrincipal UserDetails details, Model model) {
+ Optional<Meeting> meetingOpt = mr.findById(mno);
+ if (!meetingOpt.isPresent()) {
+ return "redirect:/user/meetings";
+ }
+
+ Meeting meeting = meetingOpt.get();
+ User currentUser = ur.findByUsername(details.getUsername()).get();
+
+ if (meeting.getUser().getUno() != currentUser.getUno()) {
+ return "redirect:/user/meetings";
+ }
+
+ model.addAttribute("meeting", meeting);
+ return "user/editMeeting";
+ }
+
+ @RequestMapping(value = "user/meetings/update/{mno}", method = RequestMethod.POST)
+ private String updateMeeting(@PathVariable int mno, Meeting updatedMeeting,
+ BindingResult result, @AuthenticationPrincipal UserDetails details,
+ Model model) {
+ if (result.hasErrors()) {
+ model.addAttribute("errorMessage", "Veuillez corriger les erreurs du formulaire.");
+ return "user/editMeeting";
+ }
+
+ Optional<Meeting> meetingOpt = mr.findById(mno);
+ if (!meetingOpt.isPresent()) {
+ return "redirect:/user/meetings";
+ }
+
+ Meeting existingMeeting = meetingOpt.get();
+ User currentUser = ur.findByUsername(details.getUsername()).get();
+
+ if (existingMeeting.getUser().getUno() != currentUser.getUno()) {
+ return "redirect:/user/meetings";
+ }
+
+ existingMeeting.getRequest().setReason(updatedMeeting.getRequest().getReason());
+ existingMeeting.getRequest().setDescription(updatedMeeting.getRequest().getDescription());
+
+ mr.save(existingMeeting);
+ rr.save(existingMeeting.getRequest());
+
+ return "redirect:/user/meetings/detail/" + mno;
+ }
+
+ @RequestMapping(value = "user/meetings/delete/{mno}", method = RequestMethod.GET)
+ private String deleteMeeting(@PathVariable int mno, @AuthenticationPrincipal UserDetails details) {
+ Optional<Meeting> meetingOpt = mr.findById(mno);
+ if (!meetingOpt.isPresent()) {
+ return "redirect:/user/meetings";
+ }
+
+ Meeting meeting = meetingOpt.get();
+ User currentUser = ur.findByUsername(details.getUsername()).get();
+
+ if (meeting.getUser().getUno() == currentUser.getUno()) {
+ mr.delete(meeting);
+ }
+
+ return "redirect:/user/meetings";
}
- @RequestMapping(value = "listeAction", method = RequestMethod.GET)
- private String listeAction(){
- return "listeAction";
+ private boolean isAuthenticated() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ return authentication != null &&
+ authentication.isAuthenticated() &&
+ !(authentication instanceof AnonymousAuthenticationToken);
}
}
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplication.java b/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplication.java
index b9e07c751962ebeae9e9126c1bf4702ac8cc2c8e..502e6a9122360e9ab5c3f4f46eec7178cb0e5823 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplication.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplication.java
@@ -1,4 +1,4 @@
-package fr.but.infoetu.MeetingPlannr;
+package fr.but.infoetu.meetingplannr;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Meeting.java b/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Meeting.java
index 4c391ddbc1dc3aa63671fd5f1ca8539517fb5ee1..430fdb2f31cf0ba587c4a3d0bc8a3a74abc454b9 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Meeting.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Meeting.java
@@ -1,4 +1,4 @@
-package fr.but.infoetu.MeetingPlannr.pojo;
+package fr.but.infoetu.meetingplannr.pojo;
import java.time.LocalDate;
@@ -10,10 +10,12 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
+@Builder
@AllArgsConstructor
@Data
@NoArgsConstructor
@@ -25,6 +27,7 @@ public class Meeting {
private int mno;
@ManyToOne
+ @NotNull
@JoinColumn(name = "rno")
private Request request;
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Request.java b/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Request.java
index 002d7abcd621753b914d18111fbe73031b71767e..e025d12d79feed9b7ab0e8df415441d14a9a076c 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Request.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/Request.java
@@ -1,18 +1,24 @@
-package fr.but.infoetu.MeetingPlannr.pojo;
+package fr.but.infoetu.meetingplannr.pojo;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.JoinColumn;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
+@Builder
@AllArgsConstructor
@Data
@NoArgsConstructor
+@Table(name = "requests")
public class Request {
private static final String REQUIRED = "is required";
@@ -25,4 +31,9 @@ public class Request {
@NotNull(message = REQUIRED)
private String description;
+
+ @ManyToOne
+ @JoinColumn(name = "uno")
+ @NotNull(message = REQUIRED)
+ private User user;
}
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/User.java b/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/User.java
index 9c7a610df35fe0ca73461eaf87a6ff73561ebdc2..4734efd5ce572b9f1b7c23e505be03131e016f50 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/User.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/pojo/User.java
@@ -1,63 +1,98 @@
-package fr.but.infoetu.MeetingPlannr.pojo;
+package fr.but.infoetu.meetingplannr.pojo;
import java.time.LocalDate;
-import org.springframework.boot.context.properties.bind.DefaultValue;
-
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
+import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PastOrPresent;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Builder.Default;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.Collections;
+
@Entity
+@Builder
@AllArgsConstructor
@Data
@NoArgsConstructor
@Table(name = "users")
-public class User {
- private static final String REQUIRED = "is required";
+public class User implements UserDetails {
+ private static final String REQUIRED = "est obligatoire";
@Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_uno_seq")
+ @SequenceGenerator(name = "users_uno_seq", sequenceName = "users_uno_seq", allocationSize = 1)
private int uno;
- @NotNull(message = REQUIRED)
- @Email(message = "email not valid")
- private String email;
+ @NotBlank(message = REQUIRED)
+ @Email(message = "L'email n'est pas valide")
+ private String username;
- @NotNull(message = REQUIRED)
+ @NotBlank(message = REQUIRED)
private String name;
- @NotNull(message = REQUIRED)
+ @NotBlank(message = REQUIRED)
private String surname;
- @NotNull(message = REQUIRED)
@Pattern(
regexp = "^0[1-9]([-. ]?[0-9]{2}){4}$",
- message = "invalid phone number"
+ message = "Numéro de téléphone invalide"
)
private String phoneNumber;
@NotNull(message = REQUIRED)
- @PastOrPresent(message = "date must be within the past")
+ @PastOrPresent(message = "La date doit être dans le passé")
private LocalDate birthdate;
- @NotNull(message = REQUIRED)
- @Size(min = 8, message = "password too short")
+ @Size(min = 8, message = "Le mot de passe est trop court")
private String password;
- @Column(columnDefinition = "BOOLEAN DEFAULT FALSE")
- private boolean isAdmin = false;
-
+ @Column(name = "authority", columnDefinition = "VARCHAR(50)")
+ private String authority = "ROLE_USER";
+
+ @Column(columnDefinition = "BOOLEAN DEFAULT TRUE")
+ private boolean enabled = true;
+
+ @Override
+ public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.singletonList(new SimpleGrantedAuthority(authority));
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
}
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/repository/MeetingRepository.java b/src/main/java/fr/but/infoetu/MeetingPlannr/repository/MeetingRepository.java
index bc4f7cb94f283340724b002762220725f6063161..900111b63551683f8423fb7a172ff9d1456d0c5e 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/repository/MeetingRepository.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/repository/MeetingRepository.java
@@ -1,10 +1,14 @@
-package fr.but.infoetu.MeetingPlannr.repository;
+package fr.but.infoetu.meetingplannr.repository;
+
+import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
-import fr.but.infoetu.MeetingPlannr.pojo.Meeting;
+import fr.but.infoetu.meetingplannr.pojo.Meeting;
+import fr.but.infoetu.meetingplannr.pojo.User;
public interface MeetingRepository extends JpaRepository<Meeting, Integer>{
+ List<Meeting> findByUserOrderByDateAsc(User user);
}
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/repository/RequestRepository.java b/src/main/java/fr/but/infoetu/MeetingPlannr/repository/RequestRepository.java
index 21e8ca7debb7cf679a1743eb8e19d990d4410784..bba52ce2cab23aae67e557e6396e43db7ed61e1d 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/repository/RequestRepository.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/repository/RequestRepository.java
@@ -1,9 +1,9 @@
-package fr.but.infoetu.MeetingPlannr.repository;
+package fr.but.infoetu.meetingplannr.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
-import fr.but.infoetu.MeetingPlannr.pojo.Request;
+import fr.but.infoetu.meetingplannr.pojo.Request;
public interface RequestRepository extends JpaRepository<Request, Integer>{
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/repository/UserRepository.java b/src/main/java/fr/but/infoetu/MeetingPlannr/repository/UserRepository.java
index 32e9bdf06fba183c479ce3209033ab05b47541b2..628df460eee4d3b00d101cc389e475fb03a088bb 100644
--- a/src/main/java/fr/but/infoetu/MeetingPlannr/repository/UserRepository.java
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/repository/UserRepository.java
@@ -1,12 +1,12 @@
-package fr.but.infoetu.MeetingPlannr.repository;
+package fr.but.infoetu.meetingplannr.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
-import fr.but.infoetu.MeetingPlannr.pojo.User;
+import fr.but.infoetu.meetingplannr.pojo.User;
public interface UserRepository extends JpaRepository<User, Integer>{
- Optional<User> findByEmail(String email);
+ Optional<User> findByUsername(String email);
}
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/security/Security.java b/src/main/java/fr/but/infoetu/MeetingPlannr/security/Security.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b4046b6b51f7af73b65daf364181c62e33e0fb9
--- /dev/null
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/security/Security.java
@@ -0,0 +1,93 @@
+package fr.but.infoetu.meetingplannr.security;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.provisioning.JdbcUserDetailsManager;
+import org.springframework.security.provisioning.UserDetailsManager;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
+import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
+
+import com.zaxxer.hikari.HikariDataSource;
+
+import jakarta.servlet.DispatcherType;
+
+@Configuration
+@EnableWebSecurity
+public class Security {
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Bean
+ public UserDetailsManager userDetailsManager() {
+ String usersByUsernameQuery = "select username, password, enabled from users where username = ?";
+ String authoritiesByUsernameQuery = "select username, authority from users where username = ?";
+
+ JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
+
+ users.setUsersByUsernameQuery(usersByUsernameQuery);
+ users.setAuthoritiesByUsernameQuery(authoritiesByUsernameQuery);
+
+ return users;
+ }
+
+ @Bean
+ public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
+ return config.getAuthenticationManager();
+ }
+
+ @Bean
+ public AuthenticationSuccessHandler authenticationSuccessHandler() {
+ return (request, response, authentication) -> {
+ System.out.println("User authenticated: " + authentication.getName());
+ response.sendRedirect("/user/listeAction");
+ };
+ }
+
+ @Bean
+ public SecurityFilterChain authorization(HttpSecurity http, HandlerMappingIntrospector intro) throws Exception {
+ MvcRequestMatcher.Builder mvc = new MvcRequestMatcher.Builder(intro);
+ return http
+ .csrf().disable()
+ .authorizeHttpRequests((authorize) -> authorize
+ .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
+ .requestMatchers(mvc.pattern("/public/**"),mvc.pattern("styles/**")).permitAll()
+ .requestMatchers(mvc.pattern("/perform_login")).permitAll()
+ .requestMatchers(mvc.pattern("/user/**")).authenticated()
+ .requestMatchers(mvc.pattern("/admin/**")).hasRole("ADMIN")
+ .anyRequest().authenticated()
+ )
+ .formLogin(configurer ->
+ configurer.loginPage("/public/login")
+ .loginProcessingUrl("/public/perform_login")
+ .defaultSuccessUrl("/user/listeAction", true)
+ .failureUrl("/public/login?error")
+ .permitAll()
+ )
+ .logout(configurer ->
+ configurer.logoutUrl("/perform_logout")
+ .deleteCookies("JSESSIONID")
+ .logoutSuccessUrl("/public/login?logout")
+ )
+ .userDetailsService(userDetailsManager())
+ .build();
+ }
+}
diff --git a/src/main/java/fr/but/infoetu/MeetingPlannr/service/UserService.java b/src/main/java/fr/but/infoetu/MeetingPlannr/service/UserService.java
new file mode 100644
index 0000000000000000000000000000000000000000..99d03f6ae443c91a4f24cfb9c6cc388e87e4ec4f
--- /dev/null
+++ b/src/main/java/fr/but/infoetu/MeetingPlannr/service/UserService.java
@@ -0,0 +1,22 @@
+package fr.but.infoetu.meetingplannr.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import fr.but.infoetu.meetingplannr.pojo.User;
+import fr.but.infoetu.meetingplannr.repository.UserRepository;
+
+@Service
+public class UserService {
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+ @Autowired
+ private UserRepository userRepository;
+
+ public void createUser(User user) {
+ user.setPassword(passwordEncoder.encode(user.getPassword()));
+ user.setAuthority(user.getAuthority());
+ userRepository.save(user);
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 553839bc9bf1785d3529f1c43a837bf0bf99216a..aa872880a05fd1798be0aac2ead280642a7edb83 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,15 +1,27 @@
-spring.application.name=MeetingPlannr
+spring.application.name=meetingplannr
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.datasource.driverClassName=org.postgresql.Driver
-spring.datasource.url=jdbc:postgresql://psqlserv/but3
-spring.datasource.username=paulcanceletu
-spring.datasource.password=moi
+spring.datasource.url=jdbc:postgresql://localhost:5432/but3
+spring.datasource.username=postgres
+spring.datasource.password=admin
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.open-in-view=false
-server.servlet.contextPath=/meetingplannr
\ No newline at end of file
+server.servlet.contextPath=/meetingplannr
+
+logging.level.org.hibernate.type=TRACE
+logging.level.org.hibernate.SQL=DEBUG
+logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
+logging.level.org.springframework.transaction=TRACE
+
+logging.level.org.springframework.security=DEBUG
+logging.level.org.springframework.jdbc=TRACE
+
+spring.security.filter.order=10
+server.servlet.session.timeout=30m
\ No newline at end of file
diff --git a/src/main/resources/import.sql b/src/main/resources/import.sql
index 7f7073eb00d6a928682c3db7d49eff6e9e63e2c2..d66ef5adb52b2278d9b9af35a0465a2753b1ec5c 100644
--- a/src/main/resources/import.sql
+++ b/src/main/resources/import.sql
@@ -1,7 +1,37 @@
-INSERT INTO users (email, name, surname, phone_number, birthdate, password) VALUES ('john.doe@example.com', 'John', 'Doe', '0612345678', '1990-05-15', 'password123');
-INSERT INTO users (email, name, surname, phone_number, birthdate, password) VALUES ('jane.smith@example.com', 'Jane', 'Smith', '0698765432', '1985-08-22', 'securepwd');
-INSERT INTO users (email, name, surname, phone_number, birthdate, password) VALUES ('robert.brown@example.com', 'Robert', 'Brown', '0711121314', '1992-03-12', 'robert2024');
-INSERT INTO users (email, name, surname, phone_number, birthdate, password) VALUES ('emily.jones@example.com', 'Emily', 'Jones', '0645678901', '2000-11-09', 'emily!secure');
-INSERT INTO users (email, name, surname, phone_number, birthdate, password) VALUES ('william.davis@example.com', 'William', 'Davis', '0623456789', '1988-07-30', 'password789');
-INSERT INTO users (email, name, surname, phone_number, birthdate, password, is_admin) VALUES ('paul.cancel@net.fr', 'Paul', 'Cancel', '0682015653', '2004-12-26', 'maywennjuliagoat', true);
-INSERT INTO users (email, name, surname, phone_number, birthdate, password, is_admin) VALUES ('theo.vienne@net.fr', 'Theo', 'Vienne', '0619515793', '2000-08-31', 'noemiegoat', true);
+DROP SEQUENCE IF EXISTS users_uno_seq;
+CREATE SEQUENCE users_uno_seq START WITH 1;
+
+-- password: password123
+INSERT INTO users (uno, username, name, surname, phone_number, birthdate, password, authority, enabled) VALUES (nextval('users_uno_seq'), 'john.doe@example.com', 'John', 'Doe', '0612345678', '1990-05-15', '$2a$12$o0C1lgpgzoxPrE64DHda6O0DEDqQznVxqXb5y6gzWne3BP4nZMWrC', 'ROLE_USER', true);
+
+-- password: securepwd
+INSERT INTO users (uno, username, name, surname, phone_number, birthdate, password, authority, enabled) VALUES (nextval('users_uno_seq'), 'jane.smith@example.com', 'Jane', 'Smith', '0698765432', '1985-08-22', '$2a$12$9DmwZZv31epkRx6kUOCeueYRCrlAUyV1J0iB6eienUWRKT3ozpLGu', 'ROLE_USER', true);
+
+-- password: robert2024
+INSERT INTO users (uno, username, name, surname, phone_number, birthdate, password, authority, enabled) VALUES (nextval('users_uno_seq'), 'robert.brown@example.com', 'Robert', 'Brown', '0711121314', '1992-03-12', '$2a$12$bTyqZfn.UGxEXThkvSeU2uKUgO1o6rRadIqg8yYeo9WFLIcnVgGpq', 'ROLE_USER', true);
+
+-- password: emily!secure
+INSERT INTO users (uno, username, name, surname, phone_number, birthdate, password, authority, enabled) VALUES (nextval('users_uno_seq'), 'emily.jones@example.com', 'Emily', 'Jones', '0645678901', '2000-11-09', '$2a$12$MDEm7.8TV90OrE1PhuDfCeJlrLlZAtIj0H5uNEybKVO.cGru3qUD6', 'ROLE_USER', true);
+
+-- password: password789
+INSERT INTO users (uno, username, name, surname, phone_number, birthdate, password, authority, enabled) VALUES (nextval('users_uno_seq'), 'william.davis@example.com', 'William', 'Davis', '0623456789', '1988-07-30', '$2a$12$/T572UEV.ptFg0.KEeSLnev8tj75Ubxm1xAsHZx2/kyneBdDTGbuu', 'ROLE_USER', true);
+
+-- password: testgoat
+INSERT INTO users (uno, username, name, surname, phone_number, birthdate, password, authority, enabled) VALUES (nextval('users_uno_seq'), 'paul.cancel@net.fr', 'Paul', 'Cancel', '0682015653', '2004-12-26', '$2a$12$4agvRLzb.KKGSKLjDi4bZelLWCAQKI15xwFMEI4mpYYgfeo4DyThW', 'ROLE_ADMIN', true);
+
+-- password: noemiegoat
+INSERT INTO users (uno, username, name, surname, phone_number, birthdate, password, authority, enabled) VALUES (nextval('users_uno_seq'), 'theo.vienne@net.fr', 'Theo', 'Vienne', '0619515793', '2000-08-31', '$2a$12$XWqr1MGt9oSxRm2YfEMQle4QWq9r9QcpSXDcOgsEzEQTqtLRdBgcC', 'ROLE_ADMIN', true);
+
+
+INSERT INTO requests (reason, description, uno) VALUES ('Rendez-vous pour discussion projet', 'Discussion des objectifs du projet', 6);
+INSERT INTO requests (reason, description, uno) VALUES ('Point d''avancement mensuel', 'Revue mensuelle des progrès', 6);
+INSERT INTO requests (reason, description, uno) VALUES ('Réunion de planification', 'Planification des prochaines étapes', 6);
+INSERT INTO requests (reason, description, uno) VALUES ('Bilan trimestriel', 'Evaluation des résultats du trimestre', 6);
+INSERT INTO requests (reason, description, uno) VALUES ('Session de développement', 'Session de codage en équipe', 6);
+
+-- Création des meetings liés aux requests
+INSERT INTO meeting (date, uno, rno) VALUES ('2024-03-20', 6, (SELECT rno FROM requests WHERE reason = 'Rendez-vous pour discussion projet'));
+INSERT INTO meeting (date, uno, rno) VALUES ('2024-03-25', 6, (SELECT rno FROM requests WHERE reason = 'Point d''avancement mensuel'));
+INSERT INTO meeting (date, uno, rno) VALUES ('2024-04-01', 6, (SELECT rno FROM requests WHERE reason = 'Réunion de planification'));
+INSERT INTO meeting (date, uno, rno) VALUES ('2024-04-15', 6, (SELECT rno FROM requests WHERE reason = 'Bilan trimestriel'));
+INSERT INTO meeting (date, uno, rno) VALUES ('2024-05-02', 6, (SELECT rno FROM requests WHERE reason = 'Session de développement'));
\ No newline at end of file
diff --git a/src/main/resources/static/styles/main.css b/src/main/resources/static/styles/main.css
new file mode 100644
index 0000000000000000000000000000000000000000..947458f3296941c81bacd64a4cf4615caea08fa3
--- /dev/null
+++ b/src/main/resources/static/styles/main.css
@@ -0,0 +1,361 @@
+/* Style de base */
+body {
+ font-family: Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ background-color: #f4f4f9;
+}
+h1, h2 {
+ text-align: center;
+ color: #333;
+}
+.container {
+ max-width: 800px;
+ margin: 90px auto 80px auto; /* Réduit la marge du haut */
+ padding: 0 30px 30px 30px; /* Supprime le padding du haut */
+ background-color: #fff;
+ border-radius: 15px;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.08);
+ min-height: calc(100vh - 140px); /* Ajout d'une hauteur minimale */
+ display: flex;
+ flex-direction: column;
+}
+.error {
+ color: red;
+ font-size: 0.9em;
+}
+
+/* Boutons */
+button {
+ padding: 12px 24px;
+ font-size: 16px;
+ color: white;
+ border: none;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+}
+button:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2);
+}
+button.logout {
+ background-color: #dc3545;
+}
+button.logout:hover {
+ background-color: #c82333;
+}
+button.submit {
+ background: #28a745;
+}
+button.submit:hover {
+ background-color: #218838;
+}
+button.back {
+ background-color: #007bff;
+}
+button.back:hover {
+ background-color: #0056b3;
+}
+
+
+/* Formulaires */
+.form-container, .container {
+ max-width: 500px;
+ margin: 50px auto;
+ padding: 20px;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ background-color: #fff;
+}
+.form-group {
+ margin-bottom: 15px;
+}
+.form-group label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: bold;
+ color: #555;
+}
+.form-group input {
+ width: 100%;
+ padding: 12px;
+ box-sizing: border-box;
+ border: 2px solid #e1e1e1;
+ border-radius: 8px;
+ font-size: 16px;
+ transition: border-color 0.3s ease;
+}
+.form-group input:focus, .form-group textarea:focus {
+ border-color: #007bff;
+ outline: none;
+ box-shadow: 0 0 0 3px rgba(0,123,255,0.1);
+}
+
+/* Style pour le formulaire d'édition */
+.form-group textarea {
+ width: 100%;
+ padding: 12px;
+ box-sizing: border-box;
+ border: 2px solid #e1e1e1;
+ border-radius: 8px;
+ font-size: 16px;
+ resize: vertical;
+ min-height: 100px;
+ transition: border-color 0.3s ease;
+}
+
+.form-group input[type="date"] {
+ width: 100%;
+ padding: 8px;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ font-size: 14px;
+}
+
+/* Profil */
+.profile-info {
+ background: #f8f9fa;
+ padding: 25px;
+ border-radius: 10px;
+ margin-top: 30px;
+}
+.profile-info p {
+ margin: 15px 0;
+ padding: 10px;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
+}
+.actions {
+ margin-top: 30px;
+ text-align: center;
+}
+.actions button {
+ margin: 10px 0;
+}
+
+/* Bannière */
+.banner {
+ background: linear-gradient(135deg, #0056b3, #007bff);
+ color: white;
+ padding: 20px;
+ text-align: center;
+ font-size: 18px;
+ margin: 50px -30px 30px -30px;
+ border-radius: 15px 15px 15px 15px;
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
+ position: relative;
+}
+
+.meeting-detail {
+ padding: 20px;
+ margin-bottom: 30px;
+}
+
+.detail-section {
+ background-color: #f8f9fa;
+ border-radius: 8px;
+ padding: 20px;
+ margin-bottom: 20px;
+}
+
+.detail-section h2 {
+ color: #007bff;
+ font-size: 1.2em;
+ margin-bottom: 15px;
+ text-align: left;
+}
+
+.detail-section p {
+ margin: 10px 0;
+ line-height: 1.5;
+}
+
+.detail-section strong {
+ color: #495057;
+ margin-right: 10px;
+}
+
+.actions {
+ display: flex;
+ gap: 10px;
+ justify-content: center;
+}
+
+/* Nouveau conteneur pour le contenu principal */
+.main-content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.liste-actions {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ justify-content: center;
+ align-items: center;
+ padding: 20px 0;
+}
+
+.liste-actions form {
+ width: 250px;
+}
+
+.liste-actions button {
+ width: 100%;
+}
+
+.meeting-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20px;
+ background: white;
+ border-radius: 10px;
+ margin-bottom: 20px;
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
+ transition: transform 0.2s, box-shadow 0.2s;
+}
+
+.meeting-item:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 6px 12px rgba(0,0,0,0.15);
+}
+
+.meeting-item button {
+ margin-left: 10px;
+}
+
+.meeting-content {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.meeting-info {
+ flex-grow: 1;
+}
+
+.meeting-info p {
+ margin: 5px 0;
+ color: #333;
+}
+
+.meeting-actions {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.meeting-actions button {
+ width: 100%;
+}
+
+.meeting-info {
+ flex-grow: 1;
+}
+
+.meeting-info p {
+ margin: 5px 0;
+}
+
+.meeting-actions {
+ margin-left: 20px;
+ flex-shrink: 0;
+}
+
+/* Header Styles - Updated */
+.app-header {
+ background: linear-gradient(135deg, #0056b3, #007bff);
+ color: white;
+ padding: 1rem; /* Réduit légèrement le padding */
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1000;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+
+.header-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.logo {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.logo a {
+ text-decoration: none;
+ color: white;
+ display: flex;
+ align-items: center;
+ gap: 15px;
+}
+
+.logo-icon {
+ font-size: 2rem;
+}
+
+.logo h1 {
+ margin: 0;
+ font-size: 2.2rem;
+ font-weight: 700;
+ letter-spacing: 1px;
+}
+
+.header-subtitle {
+ font-size: 1.1rem;
+ margin-top: 0.5rem;
+ opacity: 0.9;
+}
+
+/* Footer - Updated */
+.app-footer {
+ background: linear-gradient(135deg, #333, #222);
+ color: white;
+ padding: 1.5rem;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ text-align: center;
+ box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
+}
+
+.footer-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ font-size: 0.9rem;
+ opacity: 0.9;
+}
+
+/* Cards Style */
+.meeting-item {
+ background: white;
+ border-radius: 10px;
+ padding: 20px;
+ margin-bottom: 20px;
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
+ transition: transform 0.2s, box-shadow 0.2s;
+}
+
+.meeting-item:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 6px 12px rgba(0,0,0,0.15);
+}
+
+/* ...existing code... */
diff --git a/src/main/webapp/WEB-INF/jsp/common/footer.jsp b/src/main/webapp/WEB-INF/jsp/common/footer.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..9642d63044b7c8edda97e5afd7d92b3b5fd88ae6
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/common/footer.jsp
@@ -0,0 +1,6 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<footer class="app-footer">
+ <div class="footer-content">
+ <p>© 2024 MeetingPlannr - Tous droits réservés</p>
+ </div>
+</footer>
diff --git a/src/main/webapp/WEB-INF/jsp/common/header.jsp b/src/main/webapp/WEB-INF/jsp/common/header.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..246a40937dbaa3ccb84889a4807fa1617999a4c2
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/common/header.jsp
@@ -0,0 +1,13 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<header class="app-header">
+ <div class="header-content">
+ <div class="logo">
+ <a href="${pageContext.request.contextPath}/user/listeAction">
+ <h1>MeetingPlannr</h1>
+ </a>
+ </div>
+ <div class="header-subtitle">
+ Gestionnaire de rendez-vous
+ </div>
+ </div>
+</header>
diff --git a/src/main/webapp/WEB-INF/jsp/listeAction.jsp b/src/main/webapp/WEB-INF/jsp/listeAction.jsp
deleted file mode 100644
index 325f4348c1c0b7acda3623bf65a607ea750ab223..0000000000000000000000000000000000000000
--- a/src/main/webapp/WEB-INF/jsp/listeAction.jsp
+++ /dev/null
@@ -1,81 +0,0 @@
-<%@ page contentType="text/html;charset=UTF-8" language="java" %>
-<%@ page import="fr.but.infoetu.MeetingPlannr.pojo.User" %>
-<!DOCTYPE html>
-<html>
-<head>
- <title>Liste des Actions</title>
- <style>
- body {
- font-family: Arial, sans-serif;
- margin: 0;
- padding: 0;
- background-color: #f4f4f9;
- }
- .container {
- max-width: 800px;
- margin: 50px auto;
- padding: 20px;
- background-color: #fff;
- border-radius: 8px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
- }
- h1 {
- text-align: center;
- color: #333;
- }
- .actions {
- display: flex;
- flex-direction: column;
- gap: 15px;
- }
- .actions button {
- padding: 10px 20px;
- font-size: 16px;
- color: #fff;
- background-color: #007bff;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- transition: background-color 0.3s;
- }
- .actions button:hover {
- background-color: #0056b3;
- }
- .actions button.logout {
- background-color: #dc3545;
- }
- .actions button.logout:hover {
- background-color: #c82333;
- }
- </style>
-</head>
-<body>
- <%
- User currentUser = (User) request.getSession().getAttribute("currentUser")
- %>
- <div class="container">
- <h1>Actions Disponibles</h1>
- <div class="actions">
- <!-- Bouton pour voir le calendrier et poser des requêtes -->
- <form action="/calendar" method="get">
- <button type="submit">Voir le Calendrier</button>
- </form>
-
- <!-- Bouton pour accéder à ses rendez-vous -->
- <form action="/appointments" method="get">
- <button type="submit">Mes Rendez-Vous</button>
- </form>
-
- <!-- Bouton pour voir les détails de son profil -->
- <form action="/profile" method="get">
- <button type="submit">Mon Profil</button>
- </form>
-
- <!-- Bouton pour se déconnecter -->
- <form action="/logout" method="post">
- <button type="submit" class="logout">Se Déconnecter</button>
- </form>
- </div>
- </div>
-</body>
-</html>
diff --git a/src/main/webapp/WEB-INF/jsp/login.jsp b/src/main/webapp/WEB-INF/jsp/login.jsp
deleted file mode 100644
index bf259c31ca40b62bb325c306de471e896d894245..0000000000000000000000000000000000000000
--- a/src/main/webapp/WEB-INF/jsp/login.jsp
+++ /dev/null
@@ -1,88 +0,0 @@
-<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
-<!DOCTYPE html>
-<html>
-<head>
- <title>Login</title>
- <style>
- body {
- font-family: Arial, sans-serif;
- margin: 0;
- padding: 0;
- background-color: #f4f4f9;
- }
- .container {
- max-width: 400px;
- margin: 100px auto;
- padding: 20px;
- background: #ffffff;
- border: 1px solid #ddd;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- }
- h2 {
- text-align: center;
- color: #333;
- }
- .form-group {
- margin-bottom: 15px;
- }
- label {
- display: block;
- margin-bottom: 5px;
- color: #555;
- }
- input[type="email"],
- input[type="password"] {
- width: 100%;
- padding: 10px;
- border: 1px solid #ccc;
- border-radius: 5px;
- font-size: 14px;
- }
- button {
- width: 100%;
- padding: 10px;
- background: #007bff;
- border: none;
- color: white;
- font-size: 16px;
- border-radius: 5px;
- cursor: pointer;
- margin: 10px;
- }
- button:hover {
- background: #0056b3;
- }
- .error {
- color: red;
- font-size: 14px;
- }
- </style>
-</head>
-<body>
- <div class="container">
- <h2>Login</h2>
- <form action="login" method="POST">
- <div class="form-group">
- <label for="email">Email :</label>
- <input type="email" id="email" name="email" placeholder="Entrez votre email">
- </div>
- <div class="form-group">
- <label for="password">Mot de passe :</label>
- <input type="password" id="password" name="password" placeholder="Entrez votre mot de passe">
- </div>
- <button type="submit">Se connecter</button>
- <a href="/register">
- Créer un nouveau compte
- </a>
- </form>
- <%
- String errorMessage = (String) request.getAttribute("errorMessage");
- if (errorMessage != null) {
- %>
- <div class="error"><%= errorMessage %></div>
- <%
- }
- %>
- </div>
-</body>
-</html>
diff --git a/src/main/webapp/WEB-INF/jsp/public/login.jsp b/src/main/webapp/WEB-INF/jsp/public/login.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..0b5499d2a582a0d60940a6670e0374ed6110c3ff
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/public/login.jsp
@@ -0,0 +1,45 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Login</title>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
+</head>
+<body>
+ <div class="container">
+ <h2>Login</h2>
+ <form action="${pageContext.request.contextPath}/public/perform_login" method="POST">
+ <div class="form-group">
+ <label for="username">Email :</label>
+ <input type="email" id="username" name="username" placeholder="Entrez votre email">
+ </div>
+ <div class="form-group">
+ <label for="password">Mot de passe :</label>
+ <input type="password" id="password" name="password" placeholder="Entrez votre mot de passe">
+ </div>
+ <button type="submit">Se connecter</button>
+ <a href="register">
+ Créer un nouveau compte
+ </a>
+ </form>
+ <%
+ String errorMessage = (String) request.getAttribute("errorMessage");
+ if (errorMessage != null) {
+ %>
+ <div class="error"><%= errorMessage %></div>
+ <%
+ }
+ %>
+ <br>
+ <%
+ String error = request.getParameter("error");
+ if (error != null) {
+ %>
+ <div class="error">Email ou mot de passe incorrect</div>
+ <%
+ }
+ %>
+ </div>
+
+</body>
+</html>
diff --git a/src/main/webapp/WEB-INF/jsp/register.jsp b/src/main/webapp/WEB-INF/jsp/public/register.jsp
similarity index 54%
rename from src/main/webapp/WEB-INF/jsp/register.jsp
rename to src/main/webapp/WEB-INF/jsp/public/register.jsp
index 9c697cc9a5b897bbc6f11b8e5daaf5fcac819eb3..33d548832c6f0bcb7969dde2553388ebce16b481 100644
--- a/src/main/webapp/WEB-INF/jsp/register.jsp
+++ b/src/main/webapp/WEB-INF/jsp/public/register.jsp
@@ -3,57 +3,15 @@
<html>
<head>
<title>Register</title>
- <style>
- body {
- font-family: Arial, sans-serif;
- }
- .form-container {
- max-width: 500px;
- margin: 50px auto;
- padding: 20px;
- border: 1px solid #ccc;
- border-radius: 5px;
- }
- .form-container h1 {
- text-align: center;
- }
- .form-group {
- margin-bottom: 15px;
- }
- .form-group label {
- display: block;
- font-weight: bold;
- }
- .form-group input {
- width: 100%;
- padding: 8px;
- box-sizing: border-box;
- }
- .error {
- color: red;
- font-size: 0.9em;
- }
- .form-group button {
- width: 100%;
- padding: 10px;
- background-color: #28a745;
- color: white;
- border: none;
- border-radius: 5px;
- font-size: 1em;
- }
- .form-group button:hover {
- background-color: #218838;
- }
- </style>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
</head>
<body>
<div class="form-container">
<h1>Register</h1>
<form action="register" method="post">
<div class="form-group">
- <label for="email">Email:</label>
- <input type="email" id="email" name="email">
+ <label for="username">Email:</label>
+ <input type="email" id="username" name="username">
</div>
<div class="form-group">
<label for="name">Name:</label>
@@ -77,8 +35,19 @@
</div>
<div class="form-group">
<button type="submit">Register</button>
+ <a href="login">
+ Se connecter
+ </a>
</div>
</form>
+ <%
+ String errorMessage = (String) request.getAttribute("errorMessage");
+ if (errorMessage != null) {
+ %>
+ <div class="error"><%= errorMessage %></div>
+ <%
+ }
+ %>
</div>
</body>
</html>
diff --git a/src/main/webapp/WEB-INF/jsp/user/detailRendezVous.jsp b/src/main/webapp/WEB-INF/jsp/user/detailRendezVous.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..b8c9e1ae0baefde48f6ed577b018944c538e56f8
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/user/detailRendezVous.jsp
@@ -0,0 +1,31 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Détail du rendez-vous</title>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
+</head>
+<body>
+ <div class="container">
+ <div class="banner">
+ <h1>Détail du rendez-vous</h1>
+ </div>
+
+ <div class="meeting-detail">
+ <div class="detail-section">
+ <h2>Informations générales</h2>
+ <p><strong>Motif:</strong> ${meeting.getRequest().getReason()}</p>
+ <p><strong>Description:</strong> ${meeting.getRequest().getDescription()}</p>
+ <p><strong>Date:</strong> ${meeting.date}</p>
+ </div>
+ </div>
+
+ <div class="actions">
+ <button onclick="window.location.href='${pageContext.request.contextPath}/user/meetings'" class="back">Retour à la liste</button>
+ <button class="submit" onclick="window.location.href='${pageContext.request.contextPath}/user/meetings/edit/${meeting.mno}'">Modifier</button>
+ <button class="logout" onclick="if(confirm('Êtes-vous sûr de vouloir supprimer ce rendez-vous?')) window.location.href='${pageContext.request.contextPath}/user/meetings/delete/${meeting.mno}'">Supprimer</button>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/src/main/webapp/WEB-INF/jsp/user/editMeeting.jsp b/src/main/webapp/WEB-INF/jsp/user/editMeeting.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..7e2c819baf987bec595b88e958161591c2872882
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/user/editMeeting.jsp
@@ -0,0 +1,45 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Modifier le rendez-vous</title>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
+</head>
+<body>
+ <div class="container">
+ <div class="banner">
+ <h1>Modifier le rendez-vous</h1>
+ </div>
+
+ <form:form action="${pageContext.request.contextPath}/user/meetings/update/${meeting.mno}"
+ method="POST"
+ modelAttribute="meeting"
+ class="form-container">
+
+ <div class="form-group">
+ <label for="request.reason">Motif :</label>
+ <form:input path="request.reason" required="true" />
+ <form:errors path="request.reason" cssClass="error" />
+ </div>
+
+ <div class="form-group">
+ <label for="request.description">Description :</label>
+ <form:textarea path="request.description" required="true" rows="4" />
+ <form:errors path="request.description" cssClass="error" />
+ </div>
+
+
+ <div class="actions">
+ <button type="submit" class="submit">Enregistrer</button>
+ <button type="button" onclick="window.location.href='${pageContext.request.contextPath}/user/meetings/detail/${meeting.mno}'" class="logout">Annuler</button>
+ </div>
+
+ <div class="error">
+ ${errorMessage}
+ </div>
+ </form:form>
+ </div>
+</body>
+</html>
diff --git a/src/main/webapp/WEB-INF/jsp/user/editProfile.jsp b/src/main/webapp/WEB-INF/jsp/user/editProfile.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..353581a92f22486fefff5a498ed3c2c43a2e88cd
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/user/editProfile.jsp
@@ -0,0 +1,40 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ page import="fr.but.infoetu.meetingplannr.pojo.User" %>
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Modifier le Profil</title>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
+</head>
+<body>
+ <div class="container">
+ <h1>Modifier le Profil</h1>
+ <div class="form-container">
+ <form action="${pageContext.request.contextPath}/user/updateProfile" method="post">
+ <div class="form-group">
+ <label for="name">Prénom :</label>
+ <input type="text" id="name" name="name" value="${currentUser.getName()}" required>
+ </div>
+ <div class="form-group">
+ <label for="surname">Nom :</label>
+ <input type="text" id="surname" name="surname" value="${currentUser.getSurname()}" required>
+ </div>
+ <div class="actions">
+ <button type="submit" class="submit">Enregistrer les modifications</button>
+ <button type="button" class="logout" onclick="window.location.href='${pageContext.request.contextPath}/user/profile'">Annuler</button>
+ </div>
+ </form>
+ <%
+ String errorMessage = (String) request.getAttribute("errorMessage");
+ if (errorMessage != null) {
+ %>
+ <div class="error"><%= errorMessage %></div>
+ <%
+ }
+ %>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/src/main/webapp/WEB-INF/jsp/user/listeAction.jsp b/src/main/webapp/WEB-INF/jsp/user/listeAction.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..5c5aba4507b8f15bfe9a123b7ae03300dc75ff4e
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/user/listeAction.jsp
@@ -0,0 +1,38 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ page import="fr.but.infoetu.meetingplannr.pojo.User" %>
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Liste des Actions - MeetingPlannr</title>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
+</head>
+<body>
+ <%@ include file="../common/header.jsp" %>
+ <div class="container">
+ <div class="banner">
+ Bonjour, ${currentUser.name} ${currentUser.surname} (${currentUser.username})
+ </div>
+ <div class="main-content">
+ <h1>Actions Disponibles</h1>
+ <div class="liste-actions">
+ <form action="${pageContext.request.contextPath}/user/calendar" method="get">
+ <button type="submit" class="submit">Voir le Calendrier</button>
+ </form>
+
+ <form action="${pageContext.request.contextPath}/user/meetings" method="get">
+ <button type="submit" class="submit">Mes Rendez-Vous</button>
+ </form>
+
+ <form action="${pageContext.request.contextPath}/user/profile" method="get">
+ <button type="submit" class="submit">Mon Profil</button>
+ </form>
+
+ <form action="${pageContext.request.contextPath}/perform_logout" method="post">
+ <button type="submit" class="logout">Se Déconnecter</button>
+ </form>
+ </div>
+ </div>
+ </div>
+ <%@ include file="../common/footer.jsp" %>
+</body>
+</html>
diff --git a/src/main/webapp/WEB-INF/jsp/user/profile.jsp b/src/main/webapp/WEB-INF/jsp/user/profile.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..8b7dd22909ee7a07013418ef594ef1d72f6e2456
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/user/profile.jsp
@@ -0,0 +1,29 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ page import="fr.but.infoetu.meetingplannr.pojo.User" %>
+<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Mon Profil</title>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
+</head>
+<body>
+ <%@ include file="../common/header.jsp" %>
+ <div class="container">
+ <h1>Mon Profil</h1>
+ <div class="profile-info">
+ <p><strong>Nom :</strong> ${currentUser.surname}</p>
+ <p><strong>Prénom :</strong> ${currentUser.name}</p>
+ <p><strong>Email :</strong> ${currentUser.username}</p>
+ </div>
+ <div class="actions">
+ <form action="${pageContext.request.contextPath}/user/editProfile" method="get">
+ <button type="submit" class="submit">Modifier mon Profil</button>
+ </form>
+ <form action="${pageContext.request.contextPath}/user/listeAction" method="get">
+ <button type="submit" class="back">Retour aux Actions</button>
+ </form>
+ </div>
+ </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/jsp/user/rendezVous.jsp b/src/main/webapp/WEB-INF/jsp/user/rendezVous.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..e43f5f5a3dc0698f1b750eb8aa1059e57ef8b22c
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/user/rendezVous.jsp
@@ -0,0 +1,46 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ page import="fr.but.infoetu.meetingplannr.pojo.User" %>
+<%@ page import="fr.but.infoetu.meetingplannr.pojo.Meeting" %>
+<%@ page import="java.util.List" %>
+<%@ page import="java.time.format.DateTimeFormatter" %>
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Mes Rendez-vous</title>
+ <link rel="stylesheet" href="${pageContext.request.contextPath}/styles/main.css">
+</head>
+<body>
+ <div class="container">
+ <h1>Mes Rendez-vous</h1>
+ <div class="meetings-list">
+ <%
+ List<Meeting> meetings = (List<Meeting>) request.getAttribute("meetings");
+ if (meetings != null && !meetings.isEmpty()) {
+ for (Meeting meeting : meetings) {
+ %>
+ <div class="meeting-item">
+ <div class="meeting-content">
+ <div class="meeting-info">
+ <p>Date: <%= meeting.getDate().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) %></p>
+ <p>Motif: <%= meeting.getRequest().getReason() %></p>
+ </div>
+ <div class="meeting-actions">
+ <button onclick="window.location.href='${pageContext.request.contextPath}/user/meetings/detail/<%= meeting.getMno() %>'" class="submit">Voir détails</button>
+ </div>
+ </div>
+ </div>
+ <%
+ }
+ } else {
+ %>
+ <p>Aucun rendez-vous programmé.</p>
+ <%
+ }
+ %>
+ </div>
+ <div class="actions">
+ <button onclick="window.location.href='${pageContext.request.contextPath}/user/listeAction'" class="back">Retour</button>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/src/test/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplicationTests.java b/src/test/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplicationTests.java
index 37ced39314f5aba8485e60df41774ee1bdc82613..ee1f8900c308da64c5aa5b119403e17b15a19ef7 100644
--- a/src/test/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplicationTests.java
+++ b/src/test/java/fr/but/infoetu/MeetingPlannr/MeetingPlannrApplicationTests.java
@@ -1,4 +1,4 @@
-package fr.but.infoetu.MeetingPlannr;
+package fr.but.infoetu.meetingplannr;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;