From 2dfa0a0ee08b8e1c4b3dcf32e8a3b727227f42d2 Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Fri, 22 Mar 2024 13:54:52 +0100 Subject: [PATCH 01/15] base msg --- frontend/src/Apps/Msg.vue | 37 +++++++++++++++++++++++++++++++++++++ frontend/src/rest/apps.js | 2 ++ frontend/src/rest/msg.js | 25 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 frontend/src/Apps/Msg.vue create mode 100644 frontend/src/rest/msg.js diff --git a/frontend/src/Apps/Msg.vue b/frontend/src/Apps/Msg.vue new file mode 100644 index 0000000..feecdbe --- /dev/null +++ b/frontend/src/Apps/Msg.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/frontend/src/rest/apps.js b/frontend/src/rest/apps.js index 99cbc10..b6568e8 100644 --- a/frontend/src/rest/apps.js +++ b/frontend/src/rest/apps.js @@ -9,6 +9,7 @@ import Profil from "@/Apps/Profil.vue" import Courses from "@/Apps/ManageCourses.vue" import Users from "@/Apps/UsersList.vue" import Students from "@/Apps/StudentsList.vue" +import Msg from "@/Apps/Msg.vue" const apps = { '/login': LoginPage, @@ -17,6 +18,7 @@ const apps = { '/manage-courses' : Courses, '/users-list' : Users, '/students-list' : Students, + '/msg' : Msg, } const appsList = { diff --git a/frontend/src/rest/msg.js b/frontend/src/rest/msg.js new file mode 100644 index 0000000..648f231 --- /dev/null +++ b/frontend/src/rest/msg.js @@ -0,0 +1,25 @@ +/******************************************************* + * File: msg.js + * Author: Anthony Debucquoy + * Scope: Extension messagerie + * Description: Messages frontend api consumer + *******************************************************/ + +import { restGet } from './restConsumer.js' + +export async function getDiscussions(){ + return [ + { + id: 1, + name: "Discussion#1", + members: [1, 2, 3, 4], + }, + { + id: 2, + name: "Discussion#2", + members: [1, 4], + } + ] + return restGet("/discussions"); +} + -- 2.46.0 From 7b9f021c243af94d7a6878aac3a1bc4e7fe26d30 Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Sat, 23 Mar 2024 01:06:32 +0100 Subject: [PATCH 02/15] first version of the frontend for messages --- frontend/src/Apps/Msg.vue | 100 ++++++++++++++++++++++++++++++++++++-- frontend/src/rest/msg.js | 62 ++++++++++++++++++++++- 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/frontend/src/Apps/Msg.vue b/frontend/src/Apps/Msg.vue index feecdbe..5a09e18 100644 --- a/frontend/src/Apps/Msg.vue +++ b/frontend/src/Apps/Msg.vue @@ -1,12 +1,35 @@ + + @@ -25,13 +48,84 @@ div#discList{ margin: 30px 0 30px 30px; background-color: rgba(255, 255, 255, 0.05); border-radius: 10px; + overflow: hidden; + padding: 10px; } +.discItem{ + color: darkorange; + display: flex; + font-family: sans-serif; + font-weight: bold; + height: 4vh; + margin: 5px; + border-radius: 0 30px 30px 0; + align-items: center; + justify-content: center; + border: 1px solid darkorange; +} + div#discussion{ + display: flex; + flex-direction: column; margin: 30px; background-color: rgba(255, 255, 255, 0.05); border-radius: 10px; } +#msgName{ + text-align: center; + display: block; + background-color: #0202f755; + border-radius: 5px; + color: white; + width: 75%; + margin: 30px auto; +} + +.discItem:hover{ + background-color: gray; +} + +#msgs{ + display: flex; + flex-grow: 1; + flex-direction: column; +} + +.msg { + background-color: aliceblue; + font-family: sans-serif; + margin: 10px; + padding: 5px; + border-radius: 3px; + max-width: 50%; + align-self: start; +} + +.msg[sender=true]{ + background-color: darkorange; + align-self: end; +} + +#messageBox{ + display: flex; + margin: 10px; + border-radius: 5px; +} + +#messageBox input[type="text"]{ + align-self: end; + flex-grow: 1; +} + +#messageBox input[type="submit"]{ + position: absolute; + right: 50px; + margin: 2px; + border: none; + padding: 0 10px; +} + diff --git a/frontend/src/rest/msg.js b/frontend/src/rest/msg.js index 648f231..9f3bf3e 100644 --- a/frontend/src/rest/msg.js +++ b/frontend/src/rest/msg.js @@ -6,6 +6,9 @@ *******************************************************/ import { restGet } from './restConsumer.js' +import { ref } from 'vue' + +export const currentDiscussion = ref({}); export async function getDiscussions(){ return [ @@ -18,8 +21,65 @@ export async function getDiscussions(){ id: 2, name: "Discussion#2", members: [1, 4], + }, + { + id: 3, + name: "Discussion#3", + members: [1, 3], } ] - return restGet("/discussions"); + // return restGet("/discussions"); +} + +export async function fetchDiscussion(id){ + currentDiscussion.value = { + id: id, + name: "Discussion#2", + msgs: [ + { + id: 1, + author: 1, + sender: true, + attachment: null, + text: "Hello world!" + }, + { + id: 2, + author: 2, + sender: false, + attachment: null, + text: "Hello What?" + }, + { + id: 3, + author: 2, + sender: false, + attachment: null, + text: "You morron" + }, + { + id: 4, + author: 1, + sender: true, + attachment: null, + text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." + }, + // { + // id: 5, + // author: 1, + // sender: true, + // attachment: null, + // text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." + // }, + { + id: 6, + author: 2, + sender: false, + attachment: null, + text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." + } + ] + } + // currentDiscussion.value = restGet("/discussion/" + id); } -- 2.46.0 From 66e7fa24a1478ba872b51680c497b0567870cbd7 Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Mon, 25 Mar 2024 00:08:44 +0100 Subject: [PATCH 03/15] Adding the discussion architectures and creating new discussions --- backend/build.gradle.kts | 2 + .../EndPoints/Msg/MessagesController.java | 49 +++++++++++++++++++ .../Msg/DiscussionRepository.java | 14 ++++++ .../Clyde/Services/Msg/DiscussionService.java | 24 +++++++++ .../herisson/Clyde/Tables/Msg/Discussion.java | 44 +++++++++++++++++ .../java/ovh/herisson/Clyde/Tables/User.java | 7 +++ frontend/src/Apps/Msg.vue | 18 ++++++- frontend/src/rest/msg.js | 35 ++++++------- 8 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java create mode 100644 backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/DiscussionRepository.java create mode 100644 backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java create mode 100644 backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index b7cabcd..794631f 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -16,6 +16,8 @@ repositories { } dependencies { + compileOnly("org.projectlombok:lombok") + annotationProcessor("org.projectlombok:lombok") implementation("org.springframework.boot:spring-boot-starter-jdbc") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-mail") diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java new file mode 100644 index 0000000..e5534f4 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java @@ -0,0 +1,49 @@ +package ovh.herisson.Clyde.EndPoints.Msg; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; + +import lombok.AllArgsConstructor; +import ovh.herisson.Clyde.Responses.UnauthorizedResponse; +import ovh.herisson.Clyde.Services.AuthenticatorService; +import ovh.herisson.Clyde.Services.Msg.DiscussionService; +import ovh.herisson.Clyde.Tables.User; +import ovh.herisson.Clyde.Tables.Msg.Discussion; + +@RestController +@CrossOrigin(originPatterns = "*", allowCredentials = "true") +@AllArgsConstructor +public class MessagesController { + + private AuthenticatorService authServ; + private DiscussionService discServ; + + @GetMapping("/discussions") + public ResponseEntity> getDiscussions(@RequestHeader("Authorization") String token ){ + User user = authServ.getUserFromToken(token); + if(user == null){ + return new UnauthorizedResponse<>(null); + } + + Iterable mock = discServ.getOwned(authServ.getUserFromToken(token)); + + return new ResponseEntity<>(mock, HttpStatus.OK); + } + + @GetMapping("/discussion/{id}") + public ResponseEntity getDiscussion(@RequestHeader("Authorization") String token, @PathVariable long id){ + return null; // TODO + } + + @PostMapping("/discussion") + public ResponseEntity createDiscussion(@RequestHeader("Authorization") String token, @RequestBody Discussion data){ + return new ResponseEntity<>(discServ.create(data.getName(), authServ.getUserFromToken(token)), HttpStatus.OK); + } +} diff --git a/backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/DiscussionRepository.java b/backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/DiscussionRepository.java new file mode 100644 index 0000000..3e74cb4 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/DiscussionRepository.java @@ -0,0 +1,14 @@ +package ovh.herisson.Clyde.Repositories.Msg; + +import java.util.List; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; + +import ovh.herisson.Clyde.Tables.Msg.Discussion; + +public interface DiscussionRepository extends CrudRepository{ + + @Query("SELECT d FROM Discussion d INNER JOIN FETCH d.members dm WHERE dm.id = ?1") + List findByMembership(long userid); +} diff --git a/backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java b/backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java new file mode 100644 index 0000000..e1b36e5 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java @@ -0,0 +1,24 @@ +package ovh.herisson.Clyde.Services.Msg; + +import org.springframework.stereotype.Service; + +import lombok.AllArgsConstructor; +import ovh.herisson.Clyde.Repositories.Msg.DiscussionRepository; +import ovh.herisson.Clyde.Tables.User; +import ovh.herisson.Clyde.Tables.Msg.Discussion; + +@Service +@AllArgsConstructor +public class DiscussionService { + + private DiscussionRepository discRepo; + + public Discussion create(String name, User author){ + return discRepo.save(new Discussion(name, author)); + } + + public Iterable getOwned(User author){ + return discRepo.findByMembership(author.getRegNo()); + } + +} diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java new file mode 100644 index 0000000..57e5958 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java @@ -0,0 +1,44 @@ +package ovh.herisson.Clyde.Tables.Msg; + +import java.util.List; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import ovh.herisson.Clyde.Tables.User; + +@Entity +@Getter +@Setter +@NoArgsConstructor +public class Discussion{ + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + private String name; + + @ManyToMany + @JoinTable( + name = "discussion_members", + joinColumns = @JoinColumn(name = "discussion_id"), + inverseJoinColumns = @JoinColumn(name = "user_id") + ) + private List members; + + public Discussion(String name){ + this.name = name; + } + + public Discussion(String name, User user){ + this.name = name; + this.members = List.of(user); + } +} diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java index de958df..300a58c 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java @@ -1,7 +1,10 @@ package ovh.herisson.Clyde.Tables; import jakarta.persistence.*; +import ovh.herisson.Clyde.Tables.Msg.Discussion; + import java.util.Date; +import java.util.List; @Entity @@ -20,6 +23,10 @@ public class User { private String profilePictureUrl; private ovh.herisson.Clyde.Tables.Role role; private String password; + + @ManyToMany( mappedBy = "members" ) + private List discussions; + public User(String lastName, String firstName, String email, String address, String country, Date birthDate, String profilePictureUrl, Role role, String password) { diff --git a/frontend/src/Apps/Msg.vue b/frontend/src/Apps/Msg.vue index 5a09e18..254df1d 100644 --- a/frontend/src/Apps/Msg.vue +++ b/frontend/src/Apps/Msg.vue @@ -7,9 +7,9 @@ @@ -17,6 +17,7 @@
{{ discussion.name }}
+

{{currentDiscussion.name}}

@@ -50,6 +51,8 @@ div#discList{ border-radius: 10px; overflow: hidden; padding: 10px; + display: flex; + flex-direction: column; } @@ -66,6 +69,17 @@ div#discList{ border: 1px solid darkorange; } +#createDiscussion{ + height: 4vh; + margin: 5px; + color: white; + background-color: green; + border-radius: 0 30px 30px 0; + border: none; + font-weight: 900; + font-size: 2em; +} + div#discussion{ display: flex; flex-direction: column; diff --git a/frontend/src/rest/msg.js b/frontend/src/rest/msg.js index 9f3bf3e..06c084c 100644 --- a/frontend/src/rest/msg.js +++ b/frontend/src/rest/msg.js @@ -5,30 +5,19 @@ * Description: Messages frontend api consumer *******************************************************/ -import { restGet } from './restConsumer.js' +import { restGet, restPost } from './restConsumer.js' import { ref } from 'vue' export const currentDiscussion = ref({}); +/** + * @return array of + * - id + * - name + * - members + */ export async function getDiscussions(){ - return [ - { - id: 1, - name: "Discussion#1", - members: [1, 2, 3, 4], - }, - { - id: 2, - name: "Discussion#2", - members: [1, 4], - }, - { - id: 3, - name: "Discussion#3", - members: [1, 3], - } - ] - // return restGet("/discussions"); + return restGet("/discussions"); } export async function fetchDiscussion(id){ @@ -83,3 +72,11 @@ export async function fetchDiscussion(id){ // currentDiscussion.value = restGet("/discussion/" + id); } +export async function createDiscussion(name){ + restPost("/discussion", {name: name}); +} + + +export async function invite(id, regNo){ + restPost("/discussion/"+ id+ "/invite", {user: regNo}); +} -- 2.46.0 From 914f6bdf365e0df43f03086121e428871764c9f8 Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Mon, 25 Mar 2024 09:43:45 +0100 Subject: [PATCH 04/15] fix for new discussions not appearing right away --- frontend/src/Apps/Msg.vue | 4 ++-- frontend/src/rest/msg.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/Apps/Msg.vue b/frontend/src/Apps/Msg.vue index 254df1d..433300c 100644 --- a/frontend/src/Apps/Msg.vue +++ b/frontend/src/Apps/Msg.vue @@ -9,7 +9,7 @@ import { ref, reactive } from 'vue' import { getDiscussions, currentDiscussion, fetchDiscussion, createDiscussion } from '@/rest/msg.js' - const discussionsList = ref(await getDiscussions()); + const discussionsList = reactive(await getDiscussions()); @@ -17,7 +17,7 @@
{{ discussion.name }}
- +

{{currentDiscussion.name}}

diff --git a/frontend/src/rest/msg.js b/frontend/src/rest/msg.js index 06c084c..1cecd42 100644 --- a/frontend/src/rest/msg.js +++ b/frontend/src/rest/msg.js @@ -73,7 +73,7 @@ export async function fetchDiscussion(id){ } export async function createDiscussion(name){ - restPost("/discussion", {name: name}); + return restPost("/discussion", {name: name}); } -- 2.46.0 From b4499e04c715ea771aa5b20516261db9897202a9 Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Wed, 27 Mar 2024 19:50:52 +0100 Subject: [PATCH 05/15] Managing the message with backend Using DTO to change the way discussions and message are sent to the client --- .../herisson/Clyde/DTO/Msg/DiscussionDTO.java | 26 +++++++++++ .../herisson/Clyde/DTO/Msg/MessagesDTO.java | 23 ++++++++++ .../EndPoints/Msg/MessagesController.java | 37 +++++++++++++++- .../Repositories/Msg/MessageRepository.java | 8 ++++ .../Clyde/Services/Msg/DiscussionService.java | 11 ++++- .../herisson/Clyde/Tables/Msg/Discussion.java | 10 +++++ .../herisson/Clyde/Tables/Msg/Message.java | 44 +++++++++++++++++++ 7 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/DiscussionDTO.java create mode 100644 backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/MessagesDTO.java create mode 100644 backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/MessageRepository.java create mode 100644 backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java diff --git a/backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/DiscussionDTO.java b/backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/DiscussionDTO.java new file mode 100644 index 0000000..7b4d4f8 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/DiscussionDTO.java @@ -0,0 +1,26 @@ +package ovh.herisson.Clyde.DTO.Msg; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.AllArgsConstructor; +import lombok.Data; +import ovh.herisson.Clyde.Tables.User; +import ovh.herisson.Clyde.Tables.Msg.Discussion; +import ovh.herisson.Clyde.DTO.Msg.MessagesDTO; + +@Data +@AllArgsConstructor +public class DiscussionDTO { + private long id; + private String name; + private List members; + private List msgs; + + public static DiscussionDTO construct(Discussion d, User u){ + List msgsdto = new ArrayList<>(); + d.getMsgs().forEach(x -> msgsdto.add(MessagesDTO.construct(x, u))); + return new DiscussionDTO(d.getId(), d.getName(), d.getMembers(), msgsdto); + } +} diff --git a/backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/MessagesDTO.java b/backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/MessagesDTO.java new file mode 100644 index 0000000..7eb7ea1 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/DTO/Msg/MessagesDTO.java @@ -0,0 +1,23 @@ +package ovh.herisson.Clyde.DTO.Msg; + +import lombok.AllArgsConstructor; +import lombok.Data; +import ovh.herisson.Clyde.Tables.User; +import ovh.herisson.Clyde.Tables.Msg.Message; + +@Data +@AllArgsConstructor +public class MessagesDTO { + private long id; + private String content; + private User author; + private boolean sender; + //TODO: Attachment + + public static MessagesDTO construct(Message m, User user){ + boolean sender = false; + if(m.getAuthor().equals(user)) + sender = true; + return new MessagesDTO(m.getId(), m.getContent(), m.getAuthor(), sender); + } +} diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java index e5534f4..a40545f 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java @@ -4,6 +4,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -11,11 +12,14 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; import lombok.AllArgsConstructor; +import ovh.herisson.Clyde.DTO.Msg.DiscussionDTO; +import ovh.herisson.Clyde.Repositories.Msg.DiscussionRepository; import ovh.herisson.Clyde.Responses.UnauthorizedResponse; import ovh.herisson.Clyde.Services.AuthenticatorService; import ovh.herisson.Clyde.Services.Msg.DiscussionService; import ovh.herisson.Clyde.Tables.User; import ovh.herisson.Clyde.Tables.Msg.Discussion; +import ovh.herisson.Clyde.Tables.Msg.Message; @RestController @CrossOrigin(originPatterns = "*", allowCredentials = "true") @@ -24,6 +28,7 @@ public class MessagesController { private AuthenticatorService authServ; private DiscussionService discServ; + private DiscussionRepository discRepo; @GetMapping("/discussions") public ResponseEntity> getDiscussions(@RequestHeader("Authorization") String token ){ @@ -38,10 +43,38 @@ public class MessagesController { } @GetMapping("/discussion/{id}") - public ResponseEntity getDiscussion(@RequestHeader("Authorization") String token, @PathVariable long id){ - return null; // TODO + public ResponseEntity getDiscussion(@RequestHeader("Authorization") String token, @PathVariable long id){ + return new ResponseEntity<>(DiscussionDTO.construct(discRepo.findById(id).orElse(null), authServ.getUserFromToken(token)), HttpStatus.OK); } + @PatchMapping("/discussion/{id}") + public ResponseEntity AlterDiscussion(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Discussion data){ + User user = authServ.getUserFromToken(token); + if(user == null){ + return new UnauthorizedResponse<>(null); + } + + Discussion disc = discRepo.findById(id).orElse(null); + disc.setName(data.getName()); + discRepo.save(disc); + return new ResponseEntity<>(disc, HttpStatus.OK); + } + + @PostMapping("/discussion/{id}") + public ResponseEntity sendMessage(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Message msg){ + User user = authServ.getUserFromToken(token); + if(user == null){ + return new UnauthorizedResponse<>(null); + } + + Discussion disc = discRepo.findById(id).orElse(null); + msg.setAuthor(user); + if(disc != null) + discServ.CreateMessage(disc, msg); + return new ResponseEntity<>(disc, HttpStatus.OK); + } + + @PostMapping("/discussion") public ResponseEntity createDiscussion(@RequestHeader("Authorization") String token, @RequestBody Discussion data){ return new ResponseEntity<>(discServ.create(data.getName(), authServ.getUserFromToken(token)), HttpStatus.OK); diff --git a/backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/MessageRepository.java b/backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/MessageRepository.java new file mode 100644 index 0000000..8c90e92 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/Repositories/Msg/MessageRepository.java @@ -0,0 +1,8 @@ +package ovh.herisson.Clyde.Repositories.Msg; + +import org.springframework.data.repository.CrudRepository; + +import ovh.herisson.Clyde.Tables.Msg.Message; + +public interface MessageRepository extends CrudRepository { +} diff --git a/backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java b/backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java index e1b36e5..c1aa534 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Services/Msg/DiscussionService.java @@ -1,16 +1,19 @@ package ovh.herisson.Clyde.Services.Msg; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.databind.util.JSONPObject; + import ovh.herisson.Clyde.Repositories.Msg.DiscussionRepository; import ovh.herisson.Clyde.Tables.User; import ovh.herisson.Clyde.Tables.Msg.Discussion; +import ovh.herisson.Clyde.Tables.Msg.Message; @Service -@AllArgsConstructor public class DiscussionService { + @Autowired private DiscussionRepository discRepo; public Discussion create(String name, User author){ @@ -21,4 +24,8 @@ public class DiscussionService { return discRepo.findByMembership(author.getRegNo()); } + public Discussion CreateMessage(Discussion disc, Message msg){ + disc.addMessage(msg); + return discRepo.save(disc); + } } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java index 57e5958..028bb4f 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java @@ -2,6 +2,7 @@ package ovh.herisson.Clyde.Tables.Msg; import java.util.List; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -9,6 +10,7 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToMany; +import jakarta.persistence.OneToMany; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -33,6 +35,9 @@ public class Discussion{ ) private List members; + @OneToMany(mappedBy="discussion", orphanRemoval = true, cascade = CascadeType.ALL) + private List msgs; + public Discussion(String name){ this.name = name; } @@ -41,4 +46,9 @@ public class Discussion{ this.name = name; this.members = List.of(user); } + + public void addMessage(Message msg){ + msg.setDiscussion(this); + msgs.add(msg); + } } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java new file mode 100644 index 0000000..a06e2b3 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java @@ -0,0 +1,44 @@ +package ovh.herisson.Clyde.Tables.Msg; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import ovh.herisson.Clyde.Tables.User; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Message { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + private String content; + + @OneToOne + private User author; + + public User getAuthor() { + return author; + } + + @OneToOne + private Message response; + + @ManyToOne(optional = false) + @JsonIgnore + private Discussion discussion; + + //TODO: Attachment +} -- 2.46.0 From 1522d74ed3f48dbc26614ea0d2db2e2904d3ef24 Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Wed, 27 Mar 2024 19:52:48 +0100 Subject: [PATCH 06/15] messsaging on the frontend --- frontend/src/Apps/Msg.vue | 21 ++++++---- frontend/src/rest/msg.js | 87 +++++++++++++-------------------------- 2 files changed, 41 insertions(+), 67 deletions(-) diff --git a/frontend/src/Apps/Msg.vue b/frontend/src/Apps/Msg.vue index 433300c..92c9c49 100644 --- a/frontend/src/Apps/Msg.vue +++ b/frontend/src/Apps/Msg.vue @@ -7,9 +7,9 @@ @@ -17,18 +17,18 @@
{{ discussion.name }}
- +
-

{{currentDiscussion.name}}

+

- {{ msg.text }} + {{ msg.content }}
- - + +
@@ -56,6 +56,11 @@ div#discList{ } +.InputTitle{ + all: inherit; + margin: auto; +} + .discItem{ color: darkorange; display: flex; @@ -91,7 +96,7 @@ div#discussion{ #msgName{ text-align: center; display: block; - background-color: #0202f755; + background-color: #2a1981; border-radius: 5px; color: white; width: 75%; diff --git a/frontend/src/rest/msg.js b/frontend/src/rest/msg.js index 1cecd42..d1a9521 100644 --- a/frontend/src/rest/msg.js +++ b/frontend/src/rest/msg.js @@ -5,78 +5,47 @@ * Description: Messages frontend api consumer *******************************************************/ -import { restGet, restPost } from './restConsumer.js' +import { restGet, restPost, restPatch } from './restConsumer.js' import { ref } from 'vue' -export const currentDiscussion = ref({}); - /** - * @return array of * - id * - name * - members */ -export async function getDiscussions(){ - return restGet("/discussions"); -} +export const discussionsList = ref({}); +export const currentDiscussion = ref({}); -export async function fetchDiscussion(id){ - currentDiscussion.value = { - id: id, - name: "Discussion#2", - msgs: [ - { - id: 1, - author: 1, - sender: true, - attachment: null, - text: "Hello world!" - }, - { - id: 2, - author: 2, - sender: false, - attachment: null, - text: "Hello What?" - }, - { - id: 3, - author: 2, - sender: false, - attachment: null, - text: "You morron" - }, - { - id: 4, - author: 1, - sender: true, - attachment: null, - text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." - }, - // { - // id: 5, - // author: 1, - // sender: true, - // attachment: null, - // text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." - // }, - { - id: 6, - author: 2, - sender: false, - attachment: null, - text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." - } - ] - } - // currentDiscussion.value = restGet("/discussion/" + id); -} export async function createDiscussion(name){ - return restPost("/discussion", {name: name}); + let disc = await restPost("/discussion", {name: name}); + discussionsList.value.push(disc); } export async function invite(id, regNo){ restPost("/discussion/"+ id+ "/invite", {user: regNo}); } + +export async function sendMessage(id, content, responseId){ + let data = { + content: content, + response: responseId, + } + restPost("/discussion/" + id, data); +} + +export async function updateDiscussionName(id, name){ + restPatch("/discussion/" + id, {name: name}).then(() => fetchDiscussions()); +} + + +async function fetchDiscussions(){ + discussionsList.value = await restGet("/discussions"); +} + +export async function fetchDiscussion(id){ + currentDiscussion.value = await restGet("/discussion/" + id); +} + +await fetchDiscussions(); -- 2.46.0 From 729d1ad5041e1b106d6d05f79b81fba4736be000 Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Wed, 27 Mar 2024 23:54:59 +0100 Subject: [PATCH 07/15] adding members management --- .../EndPoints/Msg/MessagesController.java | 18 +++++++ .../herisson/Clyde/Tables/Msg/Discussion.java | 4 ++ .../herisson/Clyde/Tables/Msg/Message.java | 4 +- .../java/ovh/herisson/Clyde/Tables/User.java | 6 +++ frontend/src/Apps/Msg.vue | 47 +++++++++++++++++-- frontend/src/rest/msg.js | 6 +-- 6 files changed, 77 insertions(+), 8 deletions(-) diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java index a40545f..8cee27c 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java @@ -1,5 +1,6 @@ package ovh.herisson.Clyde.EndPoints.Msg; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; @@ -13,9 +14,11 @@ import org.springframework.web.bind.annotation.RestController; import lombok.AllArgsConstructor; import ovh.herisson.Clyde.DTO.Msg.DiscussionDTO; +import ovh.herisson.Clyde.Repositories.UserRepository; import ovh.herisson.Clyde.Repositories.Msg.DiscussionRepository; import ovh.herisson.Clyde.Responses.UnauthorizedResponse; import ovh.herisson.Clyde.Services.AuthenticatorService; +import ovh.herisson.Clyde.Services.UserService; import ovh.herisson.Clyde.Services.Msg.DiscussionService; import ovh.herisson.Clyde.Tables.User; import ovh.herisson.Clyde.Tables.Msg.Discussion; @@ -29,6 +32,7 @@ public class MessagesController { private AuthenticatorService authServ; private DiscussionService discServ; private DiscussionRepository discRepo; + private UserService userServ; @GetMapping("/discussions") public ResponseEntity> getDiscussions(@RequestHeader("Authorization") String token ){ @@ -60,6 +64,20 @@ public class MessagesController { return new ResponseEntity<>(disc, HttpStatus.OK); } + @PatchMapping("/discussion/{id}/add") + public ResponseEntity AlterDiscussion(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody User data){ + User user = authServ.getUserFromToken(token); + if(user == null){ + return new UnauthorizedResponse<>(null); + } + + Discussion disc = discRepo.findById(id).orElse(null); + User invited = userServ.getUserById(data.getRegNo()); + disc.addMember(invited); + discRepo.save(disc); + return new ResponseEntity<>(disc, HttpStatus.OK); + } + @PostMapping("/discussion/{id}") public ResponseEntity sendMessage(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Message msg){ User user = authServ.getUserFromToken(token); diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java index 028bb4f..e98bd1e 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java @@ -51,4 +51,8 @@ public class Discussion{ msg.setDiscussion(this); msgs.add(msg); } + + public void addMember(User user) { + members.add(user); + } } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java index a06e2b3..ea1f473 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Message.java @@ -2,11 +2,13 @@ package ovh.herisson.Clyde.Tables.Msg; import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import lombok.AllArgsConstructor; import lombok.Getter; @@ -26,7 +28,7 @@ public class Message { private long id; private String content; - @OneToOne + @ManyToOne private User author; public User getAuthor() { diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java index 300a58c..2badd32 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java @@ -2,6 +2,7 @@ package ovh.herisson.Clyde.Tables; import jakarta.persistence.*; import ovh.herisson.Clyde.Tables.Msg.Discussion; +import ovh.herisson.Clyde.Tables.Msg.Message; import java.util.Date; import java.util.List; @@ -24,6 +25,11 @@ public class User { private ovh.herisson.Clyde.Tables.Role role; private String password; + ////// Extension Messagerie ///// + @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) + private List msgs; + ///////////////////////////////// + @ManyToMany( mappedBy = "members" ) private List discussions; diff --git a/frontend/src/Apps/Msg.vue b/frontend/src/Apps/Msg.vue index 92c9c49..b74f980 100644 --- a/frontend/src/Apps/Msg.vue +++ b/frontend/src/Apps/Msg.vue @@ -7,9 +7,10 @@ @@ -19,8 +20,8 @@
{{ discussion.name }}
-
-

+
+

{{ msg.content }} @@ -31,6 +32,10 @@
+
+
{{ member.firstName }} {{ member.lastName.toUpperCase() }}
+ +
@@ -42,7 +47,7 @@ div#msg{ height: 100%; display: grid; - grid-template-columns: 20% auto; + grid-template-columns: 20% auto 10%; } div#discList{ @@ -53,7 +58,17 @@ div#discList{ padding: 10px; display: flex; flex-direction: column; +} +div#members{ + margin: 30px 0; + border-radius: 10px 0 0 10px; + background-color: red; + background-color: rgba(255, 255, 255, 0.05); + overflow: hidden; + display: flex; + padding: 10px 0 0 10px; + flex-direction: column; } .InputTitle{ @@ -74,6 +89,19 @@ div#discList{ border: 1px solid darkorange; } +.memberItem{ + color: darkorange; + display: flex; + font-family: sans-serif; + font-weight: bold; + height: 4vh; + margin: 5px; + border-radius: 30px 0 0 30px; + align-items: center; + justify-content: center; + border: 1px solid darkorange; +} + #createDiscussion{ height: 4vh; margin: 5px; @@ -84,6 +112,17 @@ div#discList{ font-weight: 900; font-size: 2em; } +#addMembers{ + height: 4vh; + margin: 5px; + text-align: center; + color: white; + background-color: green; + border-radius: 30px 0 0 30px; + border: none; + font-weight: 900; + font-size: 2em; +} div#discussion{ display: flex; diff --git a/frontend/src/rest/msg.js b/frontend/src/rest/msg.js index d1a9521..a27161b 100644 --- a/frontend/src/rest/msg.js +++ b/frontend/src/rest/msg.js @@ -13,8 +13,8 @@ import { ref } from 'vue' * - name * - members */ -export const discussionsList = ref({}); -export const currentDiscussion = ref({}); +export const discussionsList = ref(); +export const currentDiscussion = ref([]); export async function createDiscussion(name){ @@ -24,7 +24,7 @@ export async function createDiscussion(name){ export async function invite(id, regNo){ - restPost("/discussion/"+ id+ "/invite", {user: regNo}); + restPatch("/discussion/"+ id+ "/add", {regNo: parseInt(regNo)}).then(() => fetchDiscussion(id)) } export async function sendMessage(id, content, responseId){ -- 2.46.0 From 2bdffe6ab4962d660a6302e114b2028f8f439aef Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Fri, 29 Mar 2024 14:30:46 +0100 Subject: [PATCH 08/15] remove member of a discussion --- .../Clyde/EndPoints/Msg/MessagesController.java | 16 +++++++++++++++- .../herisson/Clyde/Tables/Msg/Discussion.java | 4 ++++ frontend/src/Apps/Msg.vue | 17 +++++++++++++++-- frontend/src/rest/msg.js | 4 ++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java index 8cee27c..591e172 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/Msg/MessagesController.java @@ -65,7 +65,7 @@ public class MessagesController { } @PatchMapping("/discussion/{id}/add") - public ResponseEntity AlterDiscussion(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody User data){ + public ResponseEntity invite(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody User data){ User user = authServ.getUserFromToken(token); if(user == null){ return new UnauthorizedResponse<>(null); @@ -78,6 +78,20 @@ public class MessagesController { return new ResponseEntity<>(disc, HttpStatus.OK); } + @PatchMapping("/discussion/{id}/remove") + public ResponseEntity removeMember(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody User data){ + User user = authServ.getUserFromToken(token); + if(user == null){ + return new UnauthorizedResponse<>(null); + } + + Discussion disc = discRepo.findById(id).orElse(null); + User member = userServ.getUserById(data.getRegNo()); + disc.delMember(member); + discRepo.save(disc); + return new ResponseEntity<>(disc, HttpStatus.OK); + } + @PostMapping("/discussion/{id}") public ResponseEntity sendMessage(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Message msg){ User user = authServ.getUserFromToken(token); diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java index e98bd1e..ee0912e 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/Msg/Discussion.java @@ -55,4 +55,8 @@ public class Discussion{ public void addMember(User user) { members.add(user); } + + public void delMember(User user) { + members.remove(user); + } } diff --git a/frontend/src/Apps/Msg.vue b/frontend/src/Apps/Msg.vue index b74f980..a5aa1f4 100644 --- a/frontend/src/Apps/Msg.vue +++ b/frontend/src/Apps/Msg.vue @@ -7,7 +7,7 @@