Browse Source

Refactor + implement websocket

tripeur 4 years ago
parent
commit
4159306fa1

+ 4 - 0
pom.xml

@@ -69,6 +69,10 @@
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-security</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-websocket</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.springframework.security</groupId>
       <artifactId>spring-security-test</artifactId>

+ 209 - 0
src/main/java/fr/jaquin/bdlg/planner/controller/ApiEvenementController.java

@@ -0,0 +1,209 @@
+package fr.jaquin.bdlg.planner.controller;
+
+import java.security.Principal;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.server.ResponseStatusException;
+import fr.jaquin.bdlg.planner.persistence.Evenement;
+import fr.jaquin.bdlg.planner.persistence.EvenementAlreadyExistException;
+import fr.jaquin.bdlg.planner.persistence.EvenementData;
+import fr.jaquin.bdlg.planner.persistence.EvenementDataLob;
+import fr.jaquin.bdlg.planner.persistence.EvenementNotFoundException;
+import fr.jaquin.bdlg.planner.persistence.PlanningView;
+import fr.jaquin.bdlg.planner.persistence.repositories.EvenementLobRepository;
+import fr.jaquin.bdlg.planner.persistence.repositories.EvenementRepository;
+import fr.jaquin.bdlg.planner.persistence.repositories.MyUserRepository;
+import fr.jaquin.bdlg.planner.persistence.repositories.PlanningViewRepository;
+import fr.jaquin.bdlg.planner.persistence.repositories.QuestionnaireQuestionRepo;
+import fr.jaquin.bdlg.planner.persistence.repositories.QuestionnaireRepo;
+import fr.jaquin.bdlg.planner.persistence.repositories.RegistrationRepository;
+import fr.jaquin.bdlg.planner.security.MyUser;
+
+@RestController
+@RequestMapping("/api")
+public class ApiEvenementController {
+
+  private final EvenementRepository repository;
+
+  private final EvenementLobRepository repositoryLob;
+  private final PlanningViewRepository repositoryView;
+
+  private final MyUserRepository repositoryUser;
+
+  public ApiEvenementController(EvenementRepository repository,
+      EvenementLobRepository repositoryLob, PlanningViewRepository repositoryView,
+      MyUserRepository repositoryUser, RegistrationRepository repositoryVolunteer,
+      QuestionnaireRepo repositoryQuestionnaire,
+      QuestionnaireQuestionRepo repositoryQuestionnaireQuestion) {
+    this.repository = repository;
+    this.repositoryLob = repositoryLob;
+    this.repositoryUser = repositoryUser;
+    this.repositoryView = repositoryView;
+  }
+
+  @GetMapping("/evenements")
+  public List<Evenement> getEvenements() {
+    return (List<Evenement>) repository.findByLastVersionIsTrue();
+  }
+
+  // Single evenement data
+  @GetMapping("/evenements/{uuid}")
+  String one(@PathVariable String uuid) {
+    List<Evenement> allVersions = repository.findFirst1ByUuidOrderByLastModifiedDesc(uuid);
+    if (allVersions.size() < 1) {
+      throw new EvenementNotFoundException(uuid);
+    }
+    return repositoryLob.findById(allVersions.get(0).getId())
+        .orElseThrow(() -> new EvenementNotFoundException(uuid)).getJsonContent();
+  }
+
+  @GetMapping("/evenements/history/{uuid}")
+  List<Evenement> history(@PathVariable String uuid) {
+    return repository.findByUuidOrderByLastModifiedDesc(uuid);
+  }
+
+  @GetMapping("/evenements/history/{uuid}/content/{id}")
+  String historyContent(@PathVariable String uuid, @PathVariable Long id) {
+    Optional<EvenementDataLob> lob = repositoryLob.findById(id);
+    if (lob.isPresent() && lob.get().getEvenement().getUuid().equals(uuid)) {
+      return lob.get().getJsonContent();
+    } else {
+      throw new EvenementNotFoundException(uuid);
+    }
+  }
+
+  @DeleteMapping("/evenements/history/{uuid}/content/{id}")
+  boolean deleteHistoryEvenement(@PathVariable String uuid, @PathVariable Long id) {
+    Optional<Evenement> evt = repository.findById(id);
+    if (!evt.isPresent()) {
+      return false;
+    }
+    if (evt.get().getUuid().equals(uuid)) {
+      return false;
+    }
+    repositoryLob.deleteById(id);
+    repository.deleteById(id);
+    return true;
+  }
+
+  @PostMapping("/evenements")
+  Evenement newEvenement(Principal principal, @RequestBody EvenementData evt) {
+    if (repository.findFirst1ByUuidOrderByLastModifiedDesc(evt.getUuid()).size() > 0) {
+      throw new ResponseStatusException(HttpStatus.CONFLICT, "",
+          new EvenementAlreadyExistException(evt.getUuid()));
+    }
+    return saveEvenementData(evt, principal.getName());
+  }
+
+  @PutMapping("/evenements/{uuid}")
+  Evenement updateEvenement(Principal principal, @RequestBody EvenementData evt,
+      @PathVariable String uuid) {
+    List<Evenement> previous = repository.findFirst1ByUuidOrderByLastModifiedDesc(uuid);
+    if (previous.size() == 0) {
+      throw new ResponseStatusException(HttpStatus.NOT_FOUND, "",
+          new EvenementNotFoundException(uuid));
+    }
+    Evenement lastversioEvenement = previous.get(0);
+    if (lastversioEvenement.getContentHash().equals(evt.getContentHash())) {
+      return lastversioEvenement;
+    } else {
+      lastversioEvenement.setLastVersion(false);
+      repository.save(lastversioEvenement);
+      return saveEvenementData(evt, principal.getName());
+    }
+  }
+
+  @DeleteMapping("/evenements/{uuid}")
+  boolean deleteEvenement(@PathVariable String uuid) {
+    List<Evenement> list = repository.findByUuid(uuid);
+    for (Evenement evenement : list) {
+      repositoryLob.deleteById(evenement.getId());
+    }
+    repository.deleteAll(list);
+    return true;
+  }
+
+  private Evenement saveEvenementData(EvenementData evt, String username) {
+    MyUser customUser = repositoryUser.findByUsername(username);
+    Evenement newEvenement = new Evenement();
+    newEvenement.setName(evt.getName());
+    newEvenement.setUuid(evt.getUuid());
+    newEvenement.setLastModified(LocalDateTime.now());
+    newEvenement.setLastEditor(customUser);
+    newEvenement.setLastVersion(true);
+    newEvenement.setContentHash(evt.getContentHash());
+    newEvenement = repository.save(newEvenement);
+    EvenementDataLob blob = new EvenementDataLob();
+    blob.setEvenement(newEvenement);
+    blob.setJsonContent(evt.getContent());
+    repositoryLob.save(blob);
+    return newEvenement;
+  }
+
+  @GetMapping("/evenements/{uuid}/views")
+  List<PlanningView> getPlanningViews(@PathVariable String uuid) {
+    return repositoryView.findByPlanningUuid(uuid);
+  }
+
+  @GetMapping("/evenements/{planningUuid}/views/{uuid}")
+  PlanningView getPlanningViews(@PathVariable String planningUuid, @PathVariable String uuid) {
+    Optional<PlanningView> res = repositoryView.findByUuid(uuid);
+    if (res.isPresent()) {
+      return res.get();
+    } else {
+      throw new ResponseStatusException(HttpStatus.NOT_FOUND, "",
+          new EvenementNotFoundException(uuid));
+    }
+  }
+
+  @PostMapping("/evenements/{planningUuid}/views")
+  void createPlanningView(@PathVariable String planningUuid, @RequestBody PlanningView view) {
+    Optional<PlanningView> res = repositoryView.findByUuid(view.getUuid());
+    if (res.isPresent()) {
+      throw new ResponseStatusException(HttpStatus.CONFLICT, "",
+          new EvenementNotFoundException(view.getUuid()));
+    } else {
+      repositoryView.save(view);
+    }
+  }
+
+  @PutMapping("/evenements/{planningUuid}/views/{uuid}")
+  void updatePlanningView(@PathVariable String planningUuid, @PathVariable String uuid,
+      @RequestBody PlanningView view) {
+    Optional<PlanningView> res = repositoryView.findByUuid(view.getUuid());
+    if (res.isPresent()) {
+      PlanningView obj = res.get();
+
+      obj.setStart(view.getStart());
+      obj.setEnd(view.getEnd());
+      obj.setName(view.getName());
+      obj.setRessourceUuidList(view.getRessourceUuidList());
+
+      repositoryView.save(obj);
+    } else {
+      throw new ResponseStatusException(HttpStatus.NOT_FOUND, "",
+          new EvenementNotFoundException(view.getUuid()));
+    }
+  }
+
+  @DeleteMapping("/evenements/{planningUuid}/views/{uuid}")
+  void deletePlanningView(@PathVariable String planningUuid, @PathVariable String uuid) {
+    Optional<PlanningView> res = repositoryView.findByUuid(uuid);
+    if (res.isPresent()) {
+      repositoryView.delete(res.get());
+    } else {
+      throw new ResponseStatusException(HttpStatus.NOT_FOUND, "",
+          new EvenementNotFoundException(uuid));
+    }
+  }
+}

+ 4 - 114
src/main/java/fr/jaquin/bdlg/planner/controller/ApiController.java → src/main/java/fr/jaquin/bdlg/planner/controller/ApiInscriptionController.java

@@ -1,7 +1,5 @@
 package fr.jaquin.bdlg.planner.controller;
 
-import java.security.Principal;
-import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Optional;
 import org.springframework.http.HttpStatus;
@@ -14,10 +12,6 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.server.ResponseStatusException;
-import fr.jaquin.bdlg.planner.persistence.Evenement;
-import fr.jaquin.bdlg.planner.persistence.EvenementAlreadyExistException;
-import fr.jaquin.bdlg.planner.persistence.EvenementData;
-import fr.jaquin.bdlg.planner.persistence.EvenementDataLob;
 import fr.jaquin.bdlg.planner.persistence.EvenementNotFoundException;
 import fr.jaquin.bdlg.planner.persistence.Questionnaire;
 import fr.jaquin.bdlg.planner.persistence.QuestionnaireQuestion;
@@ -26,137 +20,33 @@ import fr.jaquin.bdlg.planner.persistence.Volunteer;
 import fr.jaquin.bdlg.planner.persistence.repositories.EvenementLobRepository;
 import fr.jaquin.bdlg.planner.persistence.repositories.EvenementRepository;
 import fr.jaquin.bdlg.planner.persistence.repositories.MyUserRepository;
+import fr.jaquin.bdlg.planner.persistence.repositories.PlanningViewRepository;
 import fr.jaquin.bdlg.planner.persistence.repositories.QuestionnaireQuestionRepo;
 import fr.jaquin.bdlg.planner.persistence.repositories.QuestionnaireRepo;
 import fr.jaquin.bdlg.planner.persistence.repositories.RegistrationRepository;
-import fr.jaquin.bdlg.planner.security.MyUser;
 
 @RestController
 @RequestMapping("/api")
-public class ApiController {
+public class ApiInscriptionController {
 
   private final EvenementRepository repository;
 
-  private final EvenementLobRepository repositoryLob;
-
-  private final MyUserRepository repositoryUser;
-
   private final RegistrationRepository repositoryVolunteer;
 
   private final QuestionnaireRepo repositoryQuestionnaire;
   private final QuestionnaireQuestionRepo repositoryQuestionnaireQuestion;
 
-  public ApiController(EvenementRepository repository, EvenementLobRepository repositoryLob,
+  public ApiInscriptionController(EvenementRepository repository,
+      EvenementLobRepository repositoryLob, PlanningViewRepository repositoryView,
       MyUserRepository repositoryUser, RegistrationRepository repositoryVolunteer,
       QuestionnaireRepo repositoryQuestionnaire,
       QuestionnaireQuestionRepo repositoryQuestionnaireQuestion) {
     this.repository = repository;
-    this.repositoryLob = repositoryLob;
-    this.repositoryUser = repositoryUser;
     this.repositoryVolunteer = repositoryVolunteer;
     this.repositoryQuestionnaire = repositoryQuestionnaire;
     this.repositoryQuestionnaireQuestion = repositoryQuestionnaireQuestion;
   }
 
-  @GetMapping("/evenements")
-  public List<Evenement> getEvenements() {
-    return (List<Evenement>) repository.findByLastVersionIsTrue();
-  }
-
-  // Single evenement data
-  @GetMapping("/evenements/{uuid}")
-  String one(@PathVariable String uuid) {
-    List<Evenement> allVersions = repository.findFirst1ByUuidOrderByLastModifiedDesc(uuid);
-    if (allVersions.size() < 1) {
-      throw new EvenementNotFoundException(uuid);
-    }
-    return repositoryLob.findById(allVersions.get(0).getId())
-        .orElseThrow(() -> new EvenementNotFoundException(uuid)).getJsonContent();
-  }
-
-  @GetMapping("/evenements/history/{uuid}")
-  List<Evenement> history(@PathVariable String uuid) {
-    return repository.findByUuidOrderByLastModifiedDesc(uuid);
-  }
-
-  @GetMapping("/evenements/history/{uuid}/content/{id}")
-  String historyContent(@PathVariable String uuid, @PathVariable Long id) {
-    Optional<EvenementDataLob> lob = repositoryLob.findById(id);
-    if (lob.isPresent() && lob.get().getEvenement().getUuid().equals(uuid)) {
-      return lob.get().getJsonContent();
-    } else {
-      throw new EvenementNotFoundException(uuid);
-    }
-  }
-
-  @DeleteMapping("/evenements/history/{uuid}/content/{id}")
-  boolean deleteHistoryEvenement(@PathVariable String uuid, @PathVariable Long id) {
-    Optional<Evenement> evt = repository.findById(id);
-    if (!evt.isPresent()) {
-      return false;
-    }
-    if (evt.get().getUuid().equals(uuid)) {
-      return false;
-    }
-    repositoryLob.deleteById(id);
-    repository.deleteById(id);
-    return true;
-  }
-
-  @PostMapping("/evenements")
-  Evenement newEvenement(Principal principal, @RequestBody EvenementData evt) {
-    if (repository.findFirst1ByUuidOrderByLastModifiedDesc(evt.getUuid()).size() > 0) {
-      throw new ResponseStatusException(HttpStatus.CONFLICT, "",
-          new EvenementAlreadyExistException(evt.getUuid()));
-    }
-    return saveEvenementData(evt, principal.getName());
-  }
-
-  @PutMapping("/evenements/{uuid}")
-  Evenement updateEvenement(Principal principal, @RequestBody EvenementData evt,
-      @PathVariable String uuid) {
-    List<Evenement> previous = repository.findFirst1ByUuidOrderByLastModifiedDesc(uuid);
-    if (previous.size() == 0) {
-      throw new ResponseStatusException(HttpStatus.NOT_FOUND, "",
-          new EvenementNotFoundException(uuid));
-    }
-    Evenement lastversioEvenement = previous.get(0);
-    if (lastversioEvenement.getContentHash().equals(evt.getContentHash())) {
-      return lastversioEvenement;
-    } else {
-      lastversioEvenement.setLastVersion(false);
-      repository.save(lastversioEvenement);
-      return saveEvenementData(evt, principal.getName());
-    }
-  }
-
-  @DeleteMapping("/evenements/{uuid}")
-  boolean deleteEvenement(@PathVariable String uuid) {
-    List<Evenement> list = repository.findByUuid(uuid);
-    for (Evenement evenement : list) {
-      repositoryLob.deleteById(evenement.getId());
-    }
-    repository.deleteAll(list);
-    return true;
-  }
-
-  private Evenement saveEvenementData(EvenementData evt, String username) {
-    MyUser customUser = repositoryUser.findByUsername(username);
-    Evenement newEvenement = new Evenement();
-    newEvenement.setName(evt.getName());
-    newEvenement.setUuid(evt.getUuid());
-    newEvenement.setLastModified(LocalDateTime.now());
-    newEvenement.setLastEditor(customUser);
-    newEvenement.setLastVersion(true);
-    newEvenement.setContentHash(evt.getContentHash());
-    newEvenement = repository.save(newEvenement);
-    EvenementDataLob blob = new EvenementDataLob();
-    blob.setEvenement(newEvenement);
-    blob.setJsonContent(evt.getContent());
-    repositoryLob.save(blob);
-    return newEvenement;
-  }
-
   @GetMapping("/inscription/{uuid}")
   List<Volunteer> getVolunteers(@PathVariable String uuid) {
     return repositoryVolunteer.findByEventUuidAndImportedFalse(uuid);

+ 6 - 3
src/main/java/fr/jaquin/bdlg/planner/controller/UserController.java

@@ -43,13 +43,18 @@ public class UserController {
     }
   }
 
+  @GetMapping("/username")
+  String getUser(Principal principal) {
+    return principal.getName();
+  }
+
   @GetMapping("/users")
   List<MyUser> getUsers() {
     return (List<MyUser>) repositoryUser.findAll();
   }
 
   @PostMapping("/users")
-  MyUser getUsers(@RequestBody MyUser user) {
+  MyUser postUsers(@RequestBody MyUser user) {
     if (repositoryUser.findByUsername(user.getUsername()) == null) {
       return repositoryUser.save(user);
     } else {
@@ -59,7 +64,6 @@ public class UserController {
 
   @PutMapping("/users/{username}")
   MyUser updateUsers(@RequestBody MyUser user, @PathVariable String username) {
-
     MyUser u = repositoryUser.findByUsername(username);
     if (u == null) {
       throw new ResponseStatusException(HttpStatus.NOT_FOUND, "");
@@ -72,7 +76,6 @@ public class UserController {
 
   @PutMapping("/users/changePassword/{username}")
   MyUser updateUsersPassword(@RequestBody MyUser user, @PathVariable String username) {
-
     MyUser u = repositoryUser.findByUsername(username);
     if (u == null) {
       throw new ResponseStatusException(HttpStatus.NOT_FOUND, "");

+ 79 - 0
src/main/java/fr/jaquin/bdlg/planner/persistence/PlanningView.java

@@ -0,0 +1,79 @@
+package fr.jaquin.bdlg.planner.persistence;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+
+@Entity
+public class PlanningView {
+  @Id
+  private String uuid;
+  private String planningUuid;
+  private String name;
+  private LocalDateTime start;
+  private LocalDateTime end;
+
+  @ElementCollection
+  @CollectionTable(name = "planning_view_top_ressource", joinColumns = @JoinColumn(name = "planning_view_id"))
+  @Column(name = "ressource_id")
+  private List<String> ressourceUuidList;
+
+  public PlanningView() {
+    this.ressourceUuidList = new ArrayList<String>();
+  }
+
+  public String getUuid() {
+    return this.uuid;
+  }
+
+  public void setUuid(String uuid) {
+    this.uuid = uuid;
+  }
+
+  public String getPlanningUuid() {
+    return this.planningUuid;
+  }
+
+  public void setPlanningUuid(String planningUuid) {
+    this.planningUuid = planningUuid;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public LocalDateTime getStart() {
+    return this.start;
+  }
+
+  public void setStart(LocalDateTime start) {
+    this.start = start;
+  }
+
+  public LocalDateTime getEnd() {
+    return this.end;
+  }
+
+  public void setEnd(LocalDateTime end) {
+    this.end = end;
+  }
+
+  public List<String> getRessourceUuidList() {
+    return this.ressourceUuidList;
+  }
+
+  public void setRessourceUuidList(List<String> ressourceUuidList) {
+    this.ressourceUuidList = ressourceUuidList;
+  }
+
+}

+ 12 - 0
src/main/java/fr/jaquin/bdlg/planner/persistence/repositories/PlanningViewRepository.java

@@ -0,0 +1,12 @@
+package fr.jaquin.bdlg.planner.persistence.repositories;
+
+import java.util.List;
+import java.util.Optional;
+import org.springframework.data.repository.CrudRepository;
+import fr.jaquin.bdlg.planner.persistence.PlanningView;
+
+public interface PlanningViewRepository extends CrudRepository<PlanningView, Long> {
+  List<PlanningView> findByPlanningUuid(String planningUuid);
+
+  Optional<PlanningView> findByUuid(String uuid);
+}

+ 2 - 0
src/main/java/fr/jaquin/bdlg/planner/security/WebSecurityConfig.java

@@ -57,6 +57,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
           .antMatchers(HttpMethod.POST, "/planning/solve").hasAuthority("USER")     
           .antMatchers(HttpMethod.GET,"/planner/**").hasAuthority("USER")
           .antMatchers(HttpMethod.GET,"/roles/current").hasAuthority("USER") 
+          .antMatchers(HttpMethod.GET,"/username").hasAuthority("USER") 
+          .antMatchers("/ws").hasAuthority("USER")  
           .antMatchers("/users").hasAuthority("ADMIN")
           .antMatchers("/users/**").hasAuthority("ADMIN")
           .antMatchers("/admin/**").hasAuthority("ADMIN")

+ 39 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/NotificationMessage.java

@@ -0,0 +1,39 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+public class NotificationMessage {
+  private String text;
+
+  private MessageType type;
+
+  public enum MessageType {
+    info, success, warning, error,
+  }
+
+  public NotificationMessage(String text) {
+    this.text = text;
+    this.type = MessageType.info;
+  }
+
+  public NotificationMessage(String text, MessageType type) {
+    this.text = text;
+    this.type = type;
+  }
+
+  public String getText() {
+    return this.text;
+  }
+
+  public void setText(String text) {
+    this.text = text;
+  }
+
+
+  public MessageType getType() {
+    return type;
+  }
+
+  public void setType(MessageType type) {
+    this.type = type;
+  }
+
+}

+ 50 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/PlanningUpdateMessage.java

@@ -0,0 +1,50 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+public class PlanningUpdateMessage {
+  public enum PlanningUpdateMethod {
+    toast, addCreneau, removeCreneau, editCreneau, addBenevole2Creneau, removeBenevole2Creneau, clearBenevole2Creneau,
+    addCreneauGroup, addCreneauGroupAt, removeCreneauGroup, editCreneauGroup, reorderCreneauGroup, addBenevole,
+    removeBenevole, editBenevole, addConstraint, removeConstraint, editConstraint, newVersion
+  }
+
+  private String uuid;
+  private String user;
+  private String method;
+  private String payload;
+
+  public PlanningUpdateMessage() {
+  }
+
+  public String getUuid() {
+    return this.uuid;
+  }
+
+  public void setUuid(String uuid) {
+    this.uuid = uuid;
+  }
+
+  public String getUser() {
+    return this.user;
+  }
+
+  public void setUser(String user) {
+    this.user = user;
+  }
+
+  public String getMethod() {
+    return this.method;
+  }
+
+  public void setMethod(String method) {
+    this.method = method;
+  }
+
+  public String getPayload() {
+    return this.payload;
+  }
+
+  public void setPayload(String payload) {
+    this.payload = payload;
+  }
+
+}

+ 24 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/WebSocketConfig.java

@@ -0,0 +1,24 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.messaging.simp.config.MessageBrokerRegistry;
+import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
+import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
+import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
+
+@Configuration
+@EnableWebSocketMessageBroker
+public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
+
+  @Override
+  public void configureMessageBroker(final MessageBrokerRegistry config) {
+    config.setApplicationDestinationPrefixes("/app");
+    config.enableSimpleBroker("/toast", "/planning/");
+  }
+
+  @Override
+  public void registerStompEndpoints(final StompEndpointRegistry registry) {
+    registry.addEndpoint("/ws").withSockJS();
+  }
+
+}

+ 28 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/WebsocketController.java

@@ -0,0 +1,28 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.handler.annotation.MessageMapping;
+import org.springframework.messaging.handler.annotation.Payload;
+import org.springframework.messaging.handler.annotation.SendTo;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+import org.springframework.stereotype.Controller;
+
+@Controller
+public class WebsocketController {
+
+  @Autowired
+  private SimpMessagingTemplate simpMessagingTemplate;
+
+  @MessageMapping("/greetings")
+  @SendTo("/toast")
+  public NotificationMessage greets() throws Exception {
+    System.out.println("Greetings requested");
+    return new NotificationMessage("greetings");
+  }
+
+  @MessageMapping("/notify")
+  public void shareUpdate(@Payload PlanningUpdateMessage message) throws Exception {
+    String destination = "/planning/" + message.getUuid();
+    simpMessagingTemplate.convertAndSend(destination, message);
+  }
+}