Compare commits
4 Commits
76c3b76153
...
Schedule/m
Author | SHA1 | Date | |
---|---|---|---|
220c891c72 | |||
2b9493422d | |||
621f568ba2 | |||
972d08a54d |
1
Clyde
Submodule
1
Clyde
Submodule
Submodule Clyde added at bd27ffd3cb
@ -16,8 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.projectlombok:lombok")
|
|
||||||
annotationProcessor("org.projectlombok:lombok")
|
|
||||||
implementation("org.springframework.boot:spring-boot-starter-jdbc")
|
implementation("org.springframework.boot:spring-boot-starter-jdbc")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-mail")
|
implementation("org.springframework.boot:spring-boot-starter-mail")
|
||||||
@ -27,7 +25,6 @@ dependencies {
|
|||||||
implementation("com.kohlschutter.junixsocket:junixsocket-core:2.9.0")
|
implementation("com.kohlschutter.junixsocket:junixsocket-core:2.9.0")
|
||||||
// implementation("org.springframework.session:spring-session-jdbc")
|
// implementation("org.springframework.session:spring-session-jdbc")
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
developmentOnly("org.springframework.boot:spring-boot-docker-compose")
|
|
||||||
runtimeOnly("org.postgresql:postgresql")
|
runtimeOnly("org.postgresql:postgresql")
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
testImplementation("org.springframework.boot:spring-boot-testcontainers")
|
testImplementation("org.springframework.boot:spring-boot-testcontainers")
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.DTO.Msg;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file DiscussionDTO.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
*
|
|
||||||
* File to format a discussion using messageDTO
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
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<User> members;
|
|
||||||
private List<MessagesDTO> msgs;
|
|
||||||
|
|
||||||
public static DiscussionDTO construct(Discussion d, User u){
|
|
||||||
List<MessagesDTO> msgsdto = new ArrayList<>();
|
|
||||||
d.getMsgs().forEach(x -> msgsdto.add(MessagesDTO.construct(x, u)));
|
|
||||||
return new DiscussionDTO(d.getId(), d.getName(), d.getMembers(), msgsdto);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.DTO.Msg;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file MessagesDTO.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
*
|
|
||||||
* File to Format the response adding the sender field
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import ovh.herisson.Clyde.Tables.User;
|
|
||||||
import ovh.herisson.Clyde.Tables.Msg.Message;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class MessagesDTO {
|
|
||||||
private long id;
|
|
||||||
private String content;
|
|
||||||
private User author;
|
|
||||||
private boolean sender;
|
|
||||||
private Date created;
|
|
||||||
//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, m.getCreated());
|
|
||||||
}
|
|
||||||
}
|
|
@ -47,6 +47,7 @@ public class ApplicationsController {
|
|||||||
|
|
||||||
//if unAuthed
|
//if unAuthed
|
||||||
authorizedApps.add(Applications.Login);
|
authorizedApps.add(Applications.Login);
|
||||||
|
authorizedApps.add(Applications.Schedule);
|
||||||
|
|
||||||
User user = authServ.getUserFromToken(token);
|
User user = authServ.getUserFromToken(token);
|
||||||
if(user == null)
|
if(user == null)
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.EndPoints.Msg;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file MessagesController.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
*
|
|
||||||
* Entry point for the messages application
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
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;
|
|
||||||
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.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;
|
|
||||||
import ovh.herisson.Clyde.Tables.Msg.Message;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class MessagesController {
|
|
||||||
|
|
||||||
private AuthenticatorService authServ;
|
|
||||||
private DiscussionService discServ;
|
|
||||||
private DiscussionRepository discRepo;
|
|
||||||
private UserService userServ;
|
|
||||||
|
|
||||||
@GetMapping("/discussions")
|
|
||||||
public ResponseEntity<Iterable<Discussion>> getDiscussions(@RequestHeader("Authorization") String token ){
|
|
||||||
User user = authServ.getUserFromToken(token);
|
|
||||||
if(user == null){
|
|
||||||
return new UnauthorizedResponse<>(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterable<Discussion> mock = discServ.getOwned(authServ.getUserFromToken(token));
|
|
||||||
|
|
||||||
return new ResponseEntity<>(mock, HttpStatus.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/discussion/{id}")
|
|
||||||
public ResponseEntity<DiscussionDTO> getDiscussion(@RequestHeader("Authorization") String token, @PathVariable long id){
|
|
||||||
User user = authServ.getUserFromToken(token);
|
|
||||||
if(user == null || !discServ.hasDiscussion(user, id) ){
|
|
||||||
return new UnauthorizedResponse<>(null);
|
|
||||||
}
|
|
||||||
return new ResponseEntity<>(DiscussionDTO.construct(discRepo.findById(id).orElse(null), authServ.getUserFromToken(token)), HttpStatus.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/discussion/{id}")
|
|
||||||
public ResponseEntity<Discussion> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/discussion/{id}/add")
|
|
||||||
public ResponseEntity<Discussion> invite(@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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/discussion/{id}/remove")
|
|
||||||
public ResponseEntity<Discussion> 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<Discussion> 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<Discussion> createDiscussion(@RequestHeader("Authorization") String token, @RequestBody Discussion data){
|
|
||||||
return new ResponseEntity<>(discServ.create(data.getName(), authServ.getUserFromToken(token)), HttpStatus.OK);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.Repositories.Msg;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file DiscussionRepository.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
*
|
|
||||||
* Repository of Discussion allowing to fetch discussion by user
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
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<Discussion, Long>{
|
|
||||||
|
|
||||||
@Query("SELECT d FROM Discussion d INNER JOIN FETCH d.members dm WHERE dm.id = ?1")
|
|
||||||
List<Discussion> findByMembership(long userid);
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.Repositories.Msg;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file MessageRepository.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
|
||||||
import ovh.herisson.Clyde.Tables.Msg.Message;
|
|
||||||
|
|
||||||
public interface MessageRepository extends CrudRepository<Message, Long> {}
|
|
@ -1,57 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.Services.Msg;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file DiscussionService.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
*
|
|
||||||
* Various function utilised by the messages application
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
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
|
|
||||||
public class DiscussionService {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DiscussionRepository discRepo;
|
|
||||||
|
|
||||||
public Discussion create(String name, User author){
|
|
||||||
return discRepo.save(new Discussion(name, author));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list discussions owned by a certain user
|
|
||||||
*/
|
|
||||||
public Iterable<Discussion> getOwned(User author){
|
|
||||||
return discRepo.findByMembership(author.getRegNo());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a message and link it to it's discussion
|
|
||||||
*/
|
|
||||||
public Discussion CreateMessage(Discussion disc, Message msg){
|
|
||||||
disc.addMessage(msg);
|
|
||||||
return discRepo.save(disc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a user is in a discussion
|
|
||||||
*/
|
|
||||||
public boolean hasDiscussion(User user, long id) {
|
|
||||||
Discussion disc = discRepo.findById(id).orElse(null);
|
|
||||||
List<User> members = disc.getMembers();
|
|
||||||
return members.contains(user);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,7 @@ package ovh.herisson.Clyde.Tables;
|
|||||||
public enum Applications {
|
public enum Applications {
|
||||||
// without any token
|
// without any token
|
||||||
Login,
|
Login,
|
||||||
|
Schedule,
|
||||||
|
|
||||||
// with any token
|
// with any token
|
||||||
Profile,
|
Profile,
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.Tables.Msg;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file Discussion.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
*
|
|
||||||
* Discussion allow to regroupe multiple user in and message together
|
|
||||||
* for the messages application to work
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
|
||||||
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 jakarta.persistence.OneToMany;
|
|
||||||
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<User> members;
|
|
||||||
|
|
||||||
@OneToMany(mappedBy="discussion", orphanRemoval = true, cascade = CascadeType.ALL)
|
|
||||||
private List<Message> msgs;
|
|
||||||
|
|
||||||
public Discussion(String name){
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Discussion(String name, User user){
|
|
||||||
this.name = name;
|
|
||||||
this.members = List.of(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMessage(Message msg){
|
|
||||||
msg.setDiscussion(this);
|
|
||||||
msgs.add(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMember(User user) {
|
|
||||||
members.add(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delMember(User user) {
|
|
||||||
members.remove(user);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
package ovh.herisson.Clyde.Tables.Msg;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* @file Message.java
|
|
||||||
* @author Anthony Debucquoy
|
|
||||||
* @scope Extension messagerie
|
|
||||||
*
|
|
||||||
* Represent a message sent to a discussion
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
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 jakarta.persistence.PrePersist;
|
|
||||||
import jakarta.persistence.Temporal;
|
|
||||||
import jakarta.persistence.TemporalType;
|
|
||||||
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;
|
|
||||||
|
|
||||||
@CreationTimestamp
|
|
||||||
@Column(nullable = false)
|
|
||||||
private Date created;
|
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
private User author;
|
|
||||||
|
|
||||||
public User getAuthor() {
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
@OneToOne
|
|
||||||
private Message response;
|
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
|
||||||
@JsonIgnore
|
|
||||||
private Discussion discussion;
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +1,7 @@
|
|||||||
package ovh.herisson.Clyde.Tables;
|
package ovh.herisson.Clyde.Tables;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import ovh.herisson.Clyde.Tables.Msg.Discussion;
|
|
||||||
import ovh.herisson.Clyde.Tables.Msg.Message;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -24,15 +20,6 @@ public class User {
|
|||||||
private String profilePictureUrl;
|
private String profilePictureUrl;
|
||||||
private ovh.herisson.Clyde.Tables.Role role;
|
private ovh.herisson.Clyde.Tables.Role role;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
////// Extension Messagerie /////
|
|
||||||
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
|
|
||||||
private List<Message> msgs;
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
@ManyToMany( mappedBy = "members" )
|
|
||||||
private List<Discussion> discussions;
|
|
||||||
|
|
||||||
public User(String lastName, String firstName, String email, String address,
|
public User(String lastName, String firstName, String email, String address,
|
||||||
String country, Date birthDate, String profilePictureUrl, Role role, String password)
|
String country, Date birthDate, String profilePictureUrl, Role role, String password)
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,6 @@ window.addEventListener('hashchange', () => {
|
|||||||
const login=ref(i18n("app.login"))
|
const login=ref(i18n("app.login"))
|
||||||
const active=ref(false)
|
const active=ref(false)
|
||||||
|
|
||||||
|
|
||||||
const apps = ref([])
|
const apps = ref([])
|
||||||
appList().then(e => apps.value = e)
|
appList().then(e => apps.value = e)
|
||||||
|
|
||||||
|
@ -1,213 +0,0 @@
|
|||||||
<!----------------------------------------------------
|
|
||||||
File: Msg.vue
|
|
||||||
Author: Anthony Debucquoy
|
|
||||||
Scope: Extension messagerie
|
|
||||||
Description: Main msg page
|
|
||||||
----------------------------------------------------->
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, reactive } from 'vue'
|
|
||||||
import { discussionsList, currentDiscussion, fetchDiscussion, createDiscussion, sendMessage, updateDiscussionName, invite, removeMember} from '@/rest/msg.js'
|
|
||||||
|
|
||||||
const msgContent = ref("");
|
|
||||||
const addMember = ref(false);
|
|
||||||
const currentTitle = ref("");
|
|
||||||
|
|
||||||
function formatTime(date){
|
|
||||||
return date.getHours() + ":" + date.getMinutes() + " " + date.getDate() + "/" + date.getMonth();
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div id="msg">
|
|
||||||
<div id="discList">
|
|
||||||
<div @click="fetchDiscussion(discussion.id).then(e => currentTitle = currentDiscussion.name)" class="discItem" v-for="discussion in discussionsList" :key="discussion.id">{{ discussion.name }}</div>
|
|
||||||
<button id="createDiscussion" @click="createDiscussion('New Discussion')">+</button>
|
|
||||||
</div>
|
|
||||||
<div id="discussion" v-if="currentDiscussion.length != 0">
|
|
||||||
<h1 id=msgName ><input class="InputTitle" type="text" @change="updateDiscussionName(currentDiscussion.id, currentTitle)" v-model="currentTitle"></h1>
|
|
||||||
<div id=msgs>
|
|
||||||
<div class="msg" v-for="msg in currentDiscussion.msgs" :sender="msg.sender" :key="msg.id">
|
|
||||||
{{ msg.content }}<br/>
|
|
||||||
<span class="sender"><span v-if="!msg.sender">{{ msg.author.firstName }} {{ msg.author.lastName.toUpperCase() }}</span> {{formatTime(new Date(msg.created))}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id=messageBox>
|
|
||||||
<input type="text" @keyup.enter="sendMessage(currentDiscussion.id, msgContent, null); msgContent = ''" v-model="msgContent">
|
|
||||||
<input type="submit" @click="sendMessage(currentDiscussion.id, msgContent, null); msgContent = ''" value="send">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="members" v-if="currentDiscussion.length != 0">
|
|
||||||
<div class="memberItem" v-for="member in currentDiscussion.members" @click="removeMember(currentDiscussion.id, member.regNo)" :key="member.id"><span>{{ member.firstName }} {{ member.lastName.toUpperCase() }}</span></div>
|
|
||||||
<input type=text id="addMembers" @focus="addMember = true" @blur="addMember = false;$event.target.value = ''" @change="invite(currentDiscussion.id, $event.target.value)" :placeholder="addMember ? 'Regno' : '+'"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
div#msg{
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 20% auto 10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#discList{
|
|
||||||
margin: 30px 0 30px 30px;
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
border-radius: 10px;
|
|
||||||
overflow: hidden;
|
|
||||||
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{
|
|
||||||
all: inherit;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.memberItem:hover span{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.memberItem:hover{
|
|
||||||
background-color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.memberItem:hover:before{
|
|
||||||
color: white;
|
|
||||||
content: "X"
|
|
||||||
}
|
|
||||||
|
|
||||||
#createDiscussion{
|
|
||||||
height: 4vh;
|
|
||||||
margin: 5px;
|
|
||||||
color: white;
|
|
||||||
background-color: green;
|
|
||||||
border-radius: 0 30px 30px 0;
|
|
||||||
border: none;
|
|
||||||
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;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: 30px;
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
border-radius: 10px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#msgName{
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
background-color: #2a1981;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sender{
|
|
||||||
display: inline-block;
|
|
||||||
color: gray;
|
|
||||||
font-size: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msg[sender=true]{
|
|
||||||
background-color: darkorange;
|
|
||||||
align-self: end;
|
|
||||||
}
|
|
||||||
|
|
||||||
#messageBox{
|
|
||||||
width: 100%;
|
|
||||||
height: 30px;
|
|
||||||
background-color: white;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#messageBox input[type="text"]{
|
|
||||||
all: inherit;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#messageBox input[type="submit"]{
|
|
||||||
border: inherit;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
211
frontend/src/Apps/Schedule.vue
Normal file
211
frontend/src/Apps/Schedule.vue
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const schedule = [
|
||||||
|
{course:"Math Pour L'info",
|
||||||
|
start:"Wed Mar 27 2024 10:15 GMT+0100",
|
||||||
|
end:"Wed Mar 27 2024 12:15 GMT+0100"},
|
||||||
|
{
|
||||||
|
course:"Calculus",
|
||||||
|
start:"Wed Mar 27 2024 08:00 GMT+0100",
|
||||||
|
end:"Wed Mar 27 2024 10:00 GMT+0100"
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
course:"Physique II",
|
||||||
|
start:"Tue Mar 26 2024 10:15 GMT+0100",
|
||||||
|
end:"Tue Mar 26 2024 12:15 GMT+0100"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
course:"Math Pour L'info",
|
||||||
|
start:"Thu Mar 28 2024 10:15 GMT+0100",
|
||||||
|
end:"Thu Mar 28 2024 12:15 GMT+0100"
|
||||||
|
}]
|
||||||
|
function formatDate(date) {
|
||||||
|
var d = new Date(date),
|
||||||
|
month = '' + (d.getMonth() + 1),
|
||||||
|
day = '' + d.getDate(),
|
||||||
|
year = d.getFullYear();
|
||||||
|
|
||||||
|
if (month.length < 2)
|
||||||
|
month = '0' + month;
|
||||||
|
if (day.length < 2)
|
||||||
|
day = '0' + day;
|
||||||
|
|
||||||
|
return [day, month, year].join('-');
|
||||||
|
}
|
||||||
|
function getMonday(d) {
|
||||||
|
d = new Date(d);
|
||||||
|
var day = d.getDay(),
|
||||||
|
diff = d.getDate() - day + (day == 0 ? -6 : 1);
|
||||||
|
return new Date(d.setDate(diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAnyDays(d){
|
||||||
|
|
||||||
|
var day = new Date(mondayOfWeek.value);
|
||||||
|
day.setDate(day.getDate() + d );
|
||||||
|
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mondayOfWeek=ref(getMonday(new Date(schedule[1].start)))
|
||||||
|
|
||||||
|
function isNotCourse(element){
|
||||||
|
return element==null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function durationCourse(element){
|
||||||
|
const hour = element.end.substring(3,5) -element.start.substring(3,5);
|
||||||
|
|
||||||
|
|
||||||
|
return (element.end - element.start)%2;
|
||||||
|
}
|
||||||
|
function sortByDate(a, b) {
|
||||||
|
const nameA = a.start; // ignore upper and lowercase
|
||||||
|
const nameB = b.start; // ignore upper and lowercase
|
||||||
|
|
||||||
|
if (nameA < nameB) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (nameA > nameB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function transpose(a) {
|
||||||
|
const trans = [[],[],[],[],[],[]];
|
||||||
|
for(let i = 0; i < 6;i++){
|
||||||
|
for(let j=0; j< 7; j++){
|
||||||
|
if(a[j][i] !== null){
|
||||||
|
trans[i].push(a[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trans;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matrixFromList(list){
|
||||||
|
const matrix = [[],[],[],[],[],[],[]];
|
||||||
|
for(let key in list){
|
||||||
|
const temp = [];
|
||||||
|
const day = new Date(list[key].start);
|
||||||
|
matrix[day.getDay()].push(list[key]);
|
||||||
|
matrix[day.getDay()].sort((a,b) => sortByDate(a,b));
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const schedule2 = matrixFromList(schedule);
|
||||||
|
const scheduleByWeek = transpose(schedule2);
|
||||||
|
|
||||||
|
console.log(scheduleByWeek)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="options" >
|
||||||
|
</div>
|
||||||
|
<div class="schedule">
|
||||||
|
<table class="table">
|
||||||
|
<tr style="background-color:rgb(24,24,24)">
|
||||||
|
<th/>
|
||||||
|
<th class="header">Lundi {{formatDate(getAnyDays(0))}}</th>
|
||||||
|
<th class="header">Mardi {{formatDate(getAnyDays(1))}}</th>
|
||||||
|
<th class="header">Mercredi {{formatDate(getAnyDays(2))}}</th>
|
||||||
|
<th class="header">Jeudi {{formatDate(getAnyDays(3))}}</th>
|
||||||
|
<th class="header">Vendredi {{formatDate(getAnyDays(4))}}</th>
|
||||||
|
<th class="header">Samedi {{formatDate(getAnyDays(5))}}</th>
|
||||||
|
<th class="header">Dimanche {{formatDate(getAnyDays(6))}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(n,index) in 12">
|
||||||
|
<th class="hour">{{8 + index}}:00-{{9+index}}:00</th>
|
||||||
|
<td v-for="m in 7"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div class="courseGrid">
|
||||||
|
<div v-for="i in 7">
|
||||||
|
Test
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
.grid{
|
||||||
|
display:grid;
|
||||||
|
margin-top:2%;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:center;
|
||||||
|
grid-template-columns:15vw 70vw;
|
||||||
|
column-gap:2.5vw;
|
||||||
|
|
||||||
|
grid-template-areas:"options schedule";
|
||||||
|
}
|
||||||
|
.schedule{
|
||||||
|
position:relative;
|
||||||
|
border-radius:20px;
|
||||||
|
grid-area:schedule;
|
||||||
|
width:100%;
|
||||||
|
height:85vh;
|
||||||
|
background-color:rgba(255,255,255,0.1);
|
||||||
|
}
|
||||||
|
.options{
|
||||||
|
border-radius:20px;
|
||||||
|
grid-area:options;
|
||||||
|
background-color:rgba(255,255,255,0.1);
|
||||||
|
width:100%;
|
||||||
|
height:85vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table{
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
border-spacing:0;
|
||||||
|
border-collapse:separate;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid black
|
||||||
|
}
|
||||||
|
|
||||||
|
.hour{
|
||||||
|
background-color:rgb(72,72,72)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.header{
|
||||||
|
align-items:center;
|
||||||
|
width:12.5%;
|
||||||
|
color:#FFFFFF;
|
||||||
|
}
|
||||||
|
table th:not(:last-child),
|
||||||
|
table td:not(:last-child) {
|
||||||
|
border-right: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr:not(:last-child)>td,
|
||||||
|
table tr:not(:last-child)>th
|
||||||
|
{
|
||||||
|
border-bottom:1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.courseGrid{
|
||||||
|
top:13.75%;
|
||||||
|
left:12.5%;
|
||||||
|
position:absolute;
|
||||||
|
width:87.5%;
|
||||||
|
height:86.25%;
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns:repeat(7,1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.course{
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
background-color:rgb(100,0,100);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
@ -9,16 +9,16 @@ import Profil from "@/Apps/Profil.vue"
|
|||||||
import Courses from "@/Apps/ManageCourses.vue"
|
import Courses from "@/Apps/ManageCourses.vue"
|
||||||
import Users from "@/Apps/UsersList.vue"
|
import Users from "@/Apps/UsersList.vue"
|
||||||
import Students from "@/Apps/StudentsList.vue"
|
import Students from "@/Apps/StudentsList.vue"
|
||||||
import Msg from "@/Apps/Msg.vue"
|
import Schedule from "@/Apps/Schedule.vue"
|
||||||
|
|
||||||
const apps = {
|
const apps = {
|
||||||
|
'/schedule': Schedule,
|
||||||
'/login': LoginPage,
|
'/login': LoginPage,
|
||||||
'/inscription': Inscription,
|
'/inscription': Inscription,
|
||||||
'/profil': Profil,
|
'/profil': Profil,
|
||||||
'/manage-courses' : Courses,
|
'/manage-courses' : Courses,
|
||||||
'/users-list' : Users,
|
'/users-list' : Users,
|
||||||
'/students-list' : Students,
|
'/students-list' : Students,
|
||||||
'/msg' : Msg,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const appsList = {
|
const appsList = {
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
/*******************************************************
|
|
||||||
* File: msg.js
|
|
||||||
* Author: Anthony Debucquoy
|
|
||||||
* Scope: Extension messagerie
|
|
||||||
* Description: Messages frontend api consumer
|
|
||||||
*******************************************************/
|
|
||||||
|
|
||||||
import { restGet, restPost, restPatch } from './restConsumer.js'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* - id
|
|
||||||
* - name
|
|
||||||
* - members
|
|
||||||
*/
|
|
||||||
export const discussionsList = ref();
|
|
||||||
export const currentDiscussion = ref([]);
|
|
||||||
let timerSet = false
|
|
||||||
|
|
||||||
|
|
||||||
export async function createDiscussion(name){
|
|
||||||
let disc = await restPost("/discussion", {name: name});
|
|
||||||
discussionsList.value.push(disc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export async function invite(id, regNo){
|
|
||||||
restPatch("/discussion/"+ id+ "/add", {regNo: parseInt(regNo)}).then(() => fetchDiscussion(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function removeMember(id, regNo){
|
|
||||||
restPatch("/discussion/"+ id+ "/remove", {regNo: parseInt(regNo)}).then(() => fetchDiscussion(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function sendMessage(id, content, responseId){
|
|
||||||
let data = {
|
|
||||||
content: content,
|
|
||||||
response: responseId,
|
|
||||||
}
|
|
||||||
restPost("/discussion/" + id, data).then(() => fetchDiscussion(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
if(!timerSet){
|
|
||||||
timerSet = true;
|
|
||||||
setTimeout(() => {timerSet = false;fetchDiscussion(currentDiscussion.value.id)} , 5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await fetchDiscussions();
|
|
Reference in New Issue
Block a user