Compare commits
22 Commits
tonitch/ma
...
76c3b76153
Author | SHA1 | Date | |
---|---|---|---|
76c3b76153 | |||
5bb7606721
|
|||
b049c46571
|
|||
7ca5c34afe
|
|||
2b9bdf8dac
|
|||
ccb954e348
|
|||
ce56e37a33
|
|||
1c61a356a4
|
|||
2bdffe6ab4
|
|||
729d1ad504
|
|||
1522d74ed3
|
|||
b4499e04c7
|
|||
914f6bdf36
|
|||
66e7fa24a1
|
|||
7b9f021c24
|
|||
2dfa0a0ee0
|
|||
9e0db361b8 | |||
7a13d412f1 | |||
9de4b06e75 | |||
123fa97611 | |||
1fad792be7 | |||
acd1262955
|
@ -16,6 +16,8 @@ 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")
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
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);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
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> {}
|
@ -0,0 +1,57 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
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,7 +1,11 @@
|
|||||||
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
|
||||||
@ -20,6 +24,15 @@ 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)
|
||||||
{
|
{
|
||||||
|
@ -86,19 +86,18 @@ window.addEventListener('hashchange', () => {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div style=" margin:50px;">
|
|
||||||
<Suspense>
|
<Suspense>
|
||||||
|
|
||||||
<component :is="currentView" />
|
<component :is="currentView" />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.container{
|
.container{
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:[firstCol-start]70px[firstCol-end secondCol-start]auto[endCol];
|
grid-template-columns:[firstCol-start]70px[firstCol-end secondCol-start]auto[endCol];
|
||||||
grid-template-rows:[firstRow-start]61px[firstRow-end secondRow-start] auto [endRow];
|
grid-template-rows:[firstRow-start]61px[firstRow-end secondRow-start] auto [endRow];
|
||||||
@ -111,6 +110,8 @@ window.addEventListener('hashchange', () => {
|
|||||||
|
|
||||||
.page {
|
.page {
|
||||||
grid-area:page;
|
grid-area:page;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
place-self:center;
|
place-self:center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-for="item of requests">
|
<div style='display:flex; justify-content:center; min-width:1140px;' v-for="item of requests">
|
||||||
<div class="bodu" v-if="item.state === 'Pending'">
|
<div class="bodu" v-if="item.state === 'Pending'">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<div class="id"><a>{{item.id}}</a></div>
|
<div class="id"><a>{{item.id}}</a></div>
|
||||||
<div class="surname"><a>{{item.lastName}}</a></div>
|
<div class="surname"><a>{{item.lastName}}</a></div>
|
||||||
<div class="firstname"><a>{{item.firstName}}</a></div>
|
<div class="firstname"><a>{{item.firstName}}</a></div>
|
||||||
@ -37,10 +36,9 @@
|
|||||||
height:100px;
|
height:100px;
|
||||||
font-size:20px;
|
font-size:20px;
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:[firstCol-start]100px[firstCol-end secondCol-start]150px[secondCol-end thirdCol-start]200px[thirdCol-end fourthCol-start]150px[fourthCol-end]150px[fifthCol-end]150px[sixthCol-end]150px[endCol];
|
grid-template-columns:10% 14.2% 19% 14.2% 14.2% 14.2% 14.2%;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"id type surname firstname infos accept refuse";
|
"id type surname firstname infos accept refuse";
|
||||||
column-gap:10px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,8 +98,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bodu {
|
.bodu {
|
||||||
width:100%;
|
margin-top:2%;
|
||||||
margin-bottom:10px;
|
width:66%;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
border-radius:9px;
|
border-radius:9px;
|
||||||
background-color:rgb(50,50,50);
|
background-color:rgb(50,50,50);
|
||||||
|
@ -56,10 +56,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class='loginBox'>
|
<div class="setup">
|
||||||
|
|
||||||
<div v-if="loginPage">
|
<div v-if="loginPage">
|
||||||
<form @submit.prevent=" login(outputs.email,outputs.password);goBackHome();"class="form">
|
<div class='loginBox' style="margin-top:30%;">
|
||||||
|
<form @submit.prevent="login(outputs.email,outputs.password);goBackHome();"class="form">
|
||||||
<h1 style="color:rgb(239,60,168); font-family: sans-serif;">
|
<h1 style="color:rgb(239,60,168); font-family: sans-serif;">
|
||||||
{{i18n("login.guest.signin")}}
|
{{i18n("login.guest.signin")}}
|
||||||
</h1>
|
</h1>
|
||||||
@ -74,13 +74,14 @@
|
|||||||
<div class="register">
|
<div class="register">
|
||||||
<a @click="loginPage=!loginPage">{{i18n("login.guest.register")}}</a>
|
<a @click="loginPage=!loginPage">{{i18n("login.guest.register")}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="inputBox">
|
<div class="inputBox" style="margin-bottom:35px;">
|
||||||
<input type="submit" v-model="submitValue">
|
<input type="submit" v-model="submitValue">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
<div class='loginBox' style="margin-top:30%; margin-bottom:50%;">
|
||||||
<form class="form">
|
<form class="form">
|
||||||
<h1 style="color:rgb(239,60,168); font-family: sans-serif; text-align:center;">
|
<h1 style="color:rgb(239,60,168); font-family: sans-serif; text-align:center;">
|
||||||
{{i18n("login.guest.welcome")}}
|
{{i18n("login.guest.welcome")}}
|
||||||
@ -128,9 +129,12 @@
|
|||||||
<p>{{i18n("login.guest.country")}}</p>
|
<p>{{i18n("login.guest.country")}}</p>
|
||||||
<input type="text" v-model="outputs.country">
|
<input type="text" v-model="outputs.country">
|
||||||
</div>
|
</div>
|
||||||
<form novalidate enctype="multipart/form-data" class="inputBox">
|
<form class="inputBox"novalidate enctype="multipart/form-data">
|
||||||
<p>{{i18n("profile.picture").toUpperCase()}}</p>
|
<p>{{i18n("profile.picture").toUpperCase()}}</p>
|
||||||
|
<label class="browser">
|
||||||
|
Parcourir . . .
|
||||||
<input type="file" :disabled="imageSaved" @change="ppData = uploadProfilePicture($event.target.files); imageSaved = true;" accept="image/*">
|
<input type="file" :disabled="imageSaved" @change="ppData = uploadProfilePicture($event.target.files); imageSaved = true;" accept="image/*">
|
||||||
|
</label>
|
||||||
</form>
|
</form>
|
||||||
<div class="inputBox">
|
<div class="inputBox">
|
||||||
<p>{{i18n("Curriculum").toUpperCase()}}</p>
|
<p>{{i18n("Curriculum").toUpperCase()}}</p>
|
||||||
@ -154,34 +158,25 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.Home{
|
|
||||||
position:absolute;
|
|
||||||
display: flex;
|
|
||||||
z-index: 100;
|
|
||||||
padding: 8px 16px;
|
|
||||||
color:rgb(255, 255, 255);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Home:hover{
|
.setup {
|
||||||
width:40px;
|
margin-left: auto;
|
||||||
background-color: black;
|
margin-right:auto;
|
||||||
border-radius:6px;
|
min-width:400px;
|
||||||
color:white;
|
|
||||||
transform: translate(0px ,1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
width:25%;
|
||||||
|
height:60%;
|
||||||
|
}
|
||||||
|
|
||||||
.loginBox {
|
.loginBox {
|
||||||
background-color: rgb(24,24,24);
|
background-color: rgb(24,24,24);
|
||||||
width: 400px;
|
|
||||||
display:flex;
|
display:flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 40px;
|
border-radius: 5%;
|
||||||
border-radius: 20px;
|
|
||||||
box-shadow:0 5px 25px #000000;
|
box-shadow:0 5px 25px #000000;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -190,9 +185,8 @@
|
|||||||
width:100%;
|
width:100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
|
||||||
align-items:center;
|
align-items:center;
|
||||||
gap: 15px;
|
gap: 3%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -200,12 +194,12 @@
|
|||||||
|
|
||||||
width:100%;
|
width:100%;
|
||||||
border: none;
|
border: none;
|
||||||
margin-right: 50px;
|
margin-right: 12.5%;
|
||||||
padding-left: 10px;
|
padding-left: 2.5%;
|
||||||
padding-top:10px;
|
padding-top:2.5%;
|
||||||
padding-bottom:10px;
|
padding-bottom:2.5%;
|
||||||
outline:none;
|
outline:none;
|
||||||
border-radius: 4px;
|
border-radius: 10px;
|
||||||
font-size:1.35em;
|
font-size:1.35em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,8 +214,9 @@
|
|||||||
|
|
||||||
.register{
|
.register{
|
||||||
color:rgb(239,60,168);
|
color:rgb(239,60,168);
|
||||||
width: 100%;
|
width:70%;
|
||||||
display:flex;
|
margin-bottom:20px;
|
||||||
|
margin-top:20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,6 +245,21 @@ input[type=submit],button,select{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=file]{
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser{
|
||||||
|
display:inline-block;
|
||||||
|
cursor:pointer;
|
||||||
|
border-radius:20px;
|
||||||
|
background-color:rgb(239,60,168);
|
||||||
|
padding:5%;
|
||||||
|
font-size:1.35em;
|
||||||
|
font-family:sans-serif;
|
||||||
|
background:#FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
button:active ,.switchpage:active{
|
button:active ,.switchpage:active{
|
||||||
opacity:0.8;
|
opacity:0.8;
|
||||||
|
|
||||||
|
@ -105,7 +105,8 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="createMod">
|
<div v-if="createMod">
|
||||||
<form class="listElement">
|
<form class="listElement" style="width:40%;margin-right:auto;margin-left:auto;">
|
||||||
|
|
||||||
<div style="margin-bottom:20px;">
|
<div style="margin-bottom:20px;">
|
||||||
{{i18n("name")}} :
|
{{i18n("name")}} :
|
||||||
<input v-model="toAdd.title">
|
<input v-model="toAdd.title">
|
||||||
@ -125,7 +126,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="deleteMod">
|
<div v-if="deleteMod">
|
||||||
<form class="listElement">
|
<form class="listElement" style="width:40%;margin-right:auto;margin-left:auto;">
|
||||||
<div style="margin-bottom:20px;">
|
<div style="margin-bottom:20px;">
|
||||||
{{i18n("courses.toDelete")}} :
|
{{i18n("courses.toDelete")}} :
|
||||||
<select style="max-width:200px;" class="teacher" v-model="toRemove">
|
<select style="max-width:200px;" class="teacher" v-model="toRemove">
|
||||||
@ -138,7 +139,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!createMod && !deleteMod" v-for="item in curriculum" :key="item.title">
|
<div v-if="!createMod && !deleteMod" v-for="item in curriculum" :key="item.title" style="width:50%;margin-left:auto; margin-right:auto;">
|
||||||
<div v-if="editElementID !== item.title" style ="padding:15px 15px 15px 15px;">
|
<div v-if="editElementID !== item.title" style ="padding:15px 15px 15px 15px;">
|
||||||
<button @click="editElementID = item.title; setModify(item); ">
|
<button @click="editElementID = item.title; setModify(item); ">
|
||||||
{{i18n("courses.modify")}}
|
{{i18n("courses.modify")}}
|
||||||
@ -149,6 +150,7 @@
|
|||||||
<button @click="editElementID= '';"> {{i18n("courses.back")}} </button>
|
<button @click="editElementID= '';"> {{i18n("courses.back")}} </button>
|
||||||
</div>
|
</div>
|
||||||
<div class="listElement" >
|
<div class="listElement" >
|
||||||
|
|
||||||
<div class="containerElement" v-if="editElementID !== item.title" >
|
<div class="containerElement" v-if="editElementID !== item.title" >
|
||||||
|
|
||||||
<div class="name"> {{item.title}} </div>
|
<div class="name"> {{item.title}} </div>
|
||||||
@ -172,17 +174,27 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.body {
|
.body {
|
||||||
width:100%;
|
width:100%;
|
||||||
margin-bottom:10px;
|
margin-top:3.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.infosContainer {
|
||||||
|
min-width:350px;
|
||||||
|
padding-bottom:50px;
|
||||||
|
border:2px solid black;
|
||||||
|
font-size:25px;
|
||||||
|
color:white;
|
||||||
|
padding:20px;
|
||||||
|
background-color:rgb(50,50,50);
|
||||||
|
border-radius:20px;
|
||||||
|
}
|
||||||
|
|
||||||
.containerElement{
|
.containerElement{
|
||||||
justify-content:center;
|
justify-content:center;
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:350px 350px 200px;
|
grid-template-columns:38.8% 38.8% 22.4%;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"name teacher credits";
|
"name teacher credits";
|
||||||
column-gap:10px;
|
column-gap:10px; }
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
grid-area:name;
|
grid-area:name;
|
||||||
@ -200,6 +212,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.listElement{
|
.listElement{
|
||||||
|
min-width:625px;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
font-size:25px;
|
font-size:25px;
|
||||||
color:white;
|
color:white;
|
||||||
@ -207,6 +220,7 @@
|
|||||||
background-color:rgb(50,50,50);
|
background-color:rgb(50,50,50);
|
||||||
border-radius:20px;
|
border-radius:20px;
|
||||||
margin-bottom:10px;
|
margin-bottom:10px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modify{
|
.modify{
|
||||||
@ -255,10 +269,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.listTitle{
|
.listTitle{
|
||||||
|
min-width:380px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width:400px;
|
width:25%;
|
||||||
margin-left:auto;
|
margin-left:auto;
|
||||||
margin-right:auto;
|
margin-right:auto;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
@ -266,7 +281,8 @@
|
|||||||
color:white;
|
color:white;
|
||||||
padding:20px;
|
padding:20px;
|
||||||
background-color:rgb(50,50,50);
|
background-color:rgb(50,50,50);
|
||||||
border-radius:20px;margin-bottom:10px;
|
border-radius:20px;
|
||||||
|
margin-bottom:10px;
|
||||||
|
|
||||||
button:hover{
|
button:hover{
|
||||||
opacity:0.8;
|
opacity:0.8;
|
||||||
|
213
frontend/src/Apps/Msg.vue
Normal file
213
frontend/src/Apps/Msg.vue
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
<!----------------------------------------------------
|
||||||
|
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>
|
@ -210,11 +210,11 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.container{
|
.container{
|
||||||
|
min-width:675px;
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:200px 900px;
|
grid-template-columns:10vw 50vw;
|
||||||
grid-template-rows:200px auto;
|
grid-template-rows:200px auto;
|
||||||
column-gap:30px;
|
column-gap:2.7%;
|
||||||
row-gap:45px;
|
row-gap:45px;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"profilPic globalInfos"
|
"profilPic globalInfos"
|
||||||
@ -222,6 +222,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.profilPic{
|
.profilPic{
|
||||||
|
width:100%;
|
||||||
grid-area:profilPic;
|
grid-area:profilPic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,13 +243,17 @@
|
|||||||
grid-area:minfos;
|
grid-area:minfos;
|
||||||
}
|
}
|
||||||
.body {
|
.body {
|
||||||
|
min-width:960px;
|
||||||
width:100%;
|
width:100%;
|
||||||
margin-bottom:10px;
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:center;
|
||||||
|
margin-top:5%;
|
||||||
}
|
}
|
||||||
.containerElement{
|
.containerElement{
|
||||||
justify-content:center;
|
justify-content:center;
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:350px 350px 200px;
|
grid-template-columns:38.8% 38.8% 22.4%;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"name teacher credits";
|
"name teacher credits";
|
||||||
column-gap:10px;
|
column-gap:10px;
|
||||||
@ -271,10 +276,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.listTitle{
|
.listTitle{
|
||||||
|
min-width:197px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width:200px;
|
width:8vw;
|
||||||
margin-left:auto;
|
margin-left:auto;
|
||||||
margin-right:auto;
|
margin-right:auto;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
@ -286,6 +292,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.listElement{
|
.listElement{
|
||||||
|
min-width:625px;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
font-size:25px;
|
font-size:25px;
|
||||||
color:white;
|
color:white;
|
||||||
@ -296,6 +303,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.infosContainer {
|
.infosContainer {
|
||||||
|
min-width:350px;
|
||||||
padding-bottom:50px;
|
padding-bottom:50px;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
font-size:25px;
|
font-size:25px;
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
const users = await getStudents();
|
const users = await getStudents();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template style="margin-top:5%;">
|
||||||
<div v-for="item in users">
|
<div style="display:flex; justify-content:center; " v-for="item in users">
|
||||||
<div class="bodu">
|
<div class="bodu">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="status"><a style="margin-left:30px">{{item.status}}</a></div>
|
<div class="status"><a style="margin-left:30px">{{item.status}}</a></div>
|
||||||
@ -25,10 +25,9 @@
|
|||||||
height:100px;
|
height:100px;
|
||||||
font-size:30px;
|
font-size:30px;
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:250px 250px 250px 250px 150px;
|
grid-template-columns:21.7% 21.7% 21.7% 21.7% 13.1%;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"status option surname firstname infos";
|
"status option surname firstname infos";
|
||||||
column-gap:10px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,21 +41,6 @@
|
|||||||
align-self:center;
|
align-self:center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refuse{
|
|
||||||
grid-area:refuse;
|
|
||||||
align-self:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.titles {
|
|
||||||
grid-area:titles;
|
|
||||||
background-color:rgb(215,215,215);
|
|
||||||
}
|
|
||||||
.id{
|
|
||||||
grid-area:id;
|
|
||||||
margin-left:40px;
|
|
||||||
align-self:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status{
|
.status{
|
||||||
grid-area:status;
|
grid-area:status;
|
||||||
align-self:center;
|
align-self:center;
|
||||||
@ -81,15 +65,15 @@
|
|||||||
button{
|
button{
|
||||||
font-size:15px;
|
font-size:15px;
|
||||||
height:50px;
|
height:50px;
|
||||||
width:100px;
|
width:75%;
|
||||||
border:none;
|
border:none;
|
||||||
border-radius:20px;
|
border-radius:20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bodu {
|
.bodu {
|
||||||
width:100%;
|
margin-top:2%;
|
||||||
margin-bottom:10px;
|
width:66%;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
border-radius:9px;
|
border-radius:9px;
|
||||||
background-color:rgb(50,50,50);
|
background-color:rgb(50,50,50);
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
const users = await getAllUsers();
|
const users = await getAllUsers();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template style="margin-top:5%;">
|
||||||
<div v-for="item in users">
|
<div style="display:flex; justify-content:center; min-width:1140px;" v-for="item in users">
|
||||||
<div class="bodu">
|
<div class="bodu">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="role"><a style="margin-left:30px">{{i18n(item.role)}}</a></div>
|
<div class="role"><a style="margin-left:30px">{{i18n(item.role)}}</a></div>
|
||||||
@ -22,23 +22,20 @@
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.container{
|
.container{
|
||||||
justify-content:center;
|
|
||||||
align-items:center;
|
|
||||||
color:white;
|
color:white;
|
||||||
height:100px;
|
height:100px;
|
||||||
font-size:30px;
|
font-size:30px;
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:250px 250px 250px 150px;
|
grid-template-columns:27.7% 27.7% 27.7% 16.9%;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"role surname firstname infos";
|
"role surname firstname infos";
|
||||||
column-gap:10px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.infos {
|
.infos {
|
||||||
|
|
||||||
grid-area:infos;
|
grid-area:infos;
|
||||||
align-items:center;
|
align-self:center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.role {
|
.role {
|
||||||
@ -67,20 +64,18 @@
|
|||||||
button{
|
button{
|
||||||
font-size:15px;
|
font-size:15px;
|
||||||
height:50px;
|
height:50px;
|
||||||
width:100px;
|
width:75%;
|
||||||
border:none;
|
border:none;
|
||||||
border-radius:20px;
|
border-radius:20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bodu {
|
.bodu {
|
||||||
width:100%;
|
margin-top:2%;
|
||||||
margin-bottom:10px;
|
width:66%;
|
||||||
border:2px solid black;
|
border:2px solid black;
|
||||||
border-radius:9px;
|
border-radius:9px;
|
||||||
background-color:rgb(50,50,50);
|
background-color:rgb(50,50,50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
body {
|
body {
|
||||||
background-color: rgb(53, 25, 60);
|
background-color: rgb(53, 25, 60);
|
||||||
margin:0;
|
margin:0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ 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"
|
||||||
|
|
||||||
const apps = {
|
const apps = {
|
||||||
'/login': LoginPage,
|
'/login': LoginPage,
|
||||||
@ -17,6 +18,7 @@ const apps = {
|
|||||||
'/manage-courses' : Courses,
|
'/manage-courses' : Courses,
|
||||||
'/users-list' : Users,
|
'/users-list' : Users,
|
||||||
'/students-list' : Students,
|
'/students-list' : Students,
|
||||||
|
'/msg' : Msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
const appsList = {
|
const appsList = {
|
||||||
|
60
frontend/src/rest/msg.js
Normal file
60
frontend/src/rest/msg.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*******************************************************
|
||||||
|
* 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