Compare commits
43 Commits
tonitch/fr
...
b7a729c899
Author | SHA1 | Date | |
---|---|---|---|
b7a729c899 | |||
fdf4993def | |||
dad6953f99 | |||
f99ed470f8 | |||
9a83d14aea | |||
76c3b76153 | |||
0cbe0dd82b | |||
3167d1f2fc | |||
a94167c8a0 | |||
d31547c4cc | |||
ec2b975467 | |||
5bb7606721
|
|||
b049c46571
|
|||
b8b193f344
|
|||
05359d64ac | |||
3d78851b29 | |||
dbe28a7fed | |||
bd7d2c2d51 | |||
91c7f42521 | |||
7ca5c34afe
|
|||
2b9bdf8dac
|
|||
ccb954e348
|
|||
bd27ffd3cb | |||
91ee3adbcd | |||
c1b2742a8f | |||
2805fede4b | |||
951feed3c8 | |||
95054fa973 | |||
3af83a58d3 | |||
47c5c14862 | |||
ce56e37a33
|
|||
1c61a356a4
|
|||
2bdffe6ab4
|
|||
729d1ad504
|
|||
1522d74ed3
|
|||
b4499e04c7
|
|||
914f6bdf36
|
|||
66e7fa24a1
|
|||
7b9f021c24
|
|||
2dfa0a0ee0
|
|||
9e0db361b8 | |||
7a13d412f1 | |||
db895a6091 |
@ -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")
|
||||||
@ -25,7 +27,7 @@ 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")
|
// 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")
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -4,5 +4,7 @@ public enum FileType {
|
|||||||
|
|
||||||
ProfilePicture,
|
ProfilePicture,
|
||||||
|
|
||||||
EducationCertificate
|
EducationCertificate,
|
||||||
|
|
||||||
|
Article,
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||||
|
|
||||||
|
public enum Access {
|
||||||
|
OpenSource,
|
||||||
|
Restricted,
|
||||||
|
Private,
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
import ovh.herisson.Clyde.Tables.User;
|
||||||
|
import java.util.Date;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Entity
|
||||||
|
public class Article {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.EAGER)
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
@JoinColumn(name ="Users")
|
||||||
|
private User author;
|
||||||
|
|
||||||
|
//todo change user to Researcher
|
||||||
|
@CreationTimestamp
|
||||||
|
@Column(nullable = false)
|
||||||
|
private Date releaseDate;
|
||||||
|
|
||||||
|
private PublishType publishType;
|
||||||
|
|
||||||
|
private String pdfLocation;
|
||||||
|
|
||||||
|
private String bibTexLocation;
|
||||||
|
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
private Access access;
|
||||||
|
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
private String summary;
|
||||||
|
|
||||||
|
private int views;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||||
|
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ArticleCoAuthors {
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "Researcher")
|
||||||
|
private Researcher coAuthor;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.EAGER)
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
@JoinColumn(name = "Article")
|
||||||
|
private Article article;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||||
|
|
||||||
|
public enum PublishType {
|
||||||
|
article,
|
||||||
|
slides,
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
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 Researcher {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private long id;
|
||||||
|
@OneToOne
|
||||||
|
private User user;
|
||||||
|
private String orcidId;
|
||||||
|
private String site;
|
||||||
|
private String Domain;
|
||||||
|
}
|
@ -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)
|
||||||
{
|
{
|
||||||
|
104
frontend/package-lock.json
generated
104
frontend/package-lock.json
generated
@ -8,6 +8,8 @@
|
|||||||
"name": "clyde",
|
"name": "clyde",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@canvasjs/vue-charts": "^1.0.4",
|
||||||
|
"@vueuse/core": "^10.9.0",
|
||||||
"vite-plugin-top-level-await": "^1.4.1",
|
"vite-plugin-top-level-await": "^1.4.1",
|
||||||
"vue": "^3.4.15",
|
"vue": "^3.4.15",
|
||||||
"vue3-toastify": "^0.2.1"
|
"vue3-toastify": "^0.2.1"
|
||||||
@ -29,6 +31,20 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@canvasjs/charts": {
|
||||||
|
"version": "3.7.45",
|
||||||
|
"resolved": "https://registry.npmjs.org/@canvasjs/charts/-/charts-3.7.45.tgz",
|
||||||
|
"integrity": "sha512-FPMX8wn+PEHzAa/GLBsL5lWB81AzKZLw51t7SiSUjMbtUN5/OIrmDcwUTw+53/Bbdd9gm2LLmxAdZsQ75JI31g=="
|
||||||
|
},
|
||||||
|
"node_modules/@canvasjs/vue-charts": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@canvasjs/vue-charts/-/vue-charts-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-PzOA8xeb/f68a39uoFZNn843dGPU36bsqmbO5DWjP7k6FwkK5AeGkYa/H3RHC02Xc6mG68vg9aFNj2Fyqhu4UQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@canvasjs/charts": "^3.7.5",
|
||||||
|
"vue": ">=3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.19.12",
|
"version": "0.19.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
|
||||||
@ -753,6 +769,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/web-bluetooth": {
|
||||||
|
"version": "0.0.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
|
||||||
|
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
|
||||||
|
},
|
||||||
"node_modules/@vitejs/plugin-vue": {
|
"node_modules/@vitejs/plugin-vue": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz",
|
||||||
@ -866,6 +887,89 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw=="
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@vueuse/core": {
|
||||||
|
"version": "10.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz",
|
||||||
|
"integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/web-bluetooth": "^0.0.20",
|
||||||
|
"@vueuse/metadata": "10.9.0",
|
||||||
|
"@vueuse/shared": "10.9.0",
|
||||||
|
"vue-demi": ">=0.14.7"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/core/node_modules/vue-demi": {
|
||||||
|
"version": "0.14.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
|
||||||
|
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/metadata": {
|
||||||
|
"version": "10.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz",
|
||||||
|
"integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/shared": {
|
||||||
|
"version": "10.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz",
|
||||||
|
"integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==",
|
||||||
|
"dependencies": {
|
||||||
|
"vue-demi": ">=0.14.7"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/shared/node_modules/vue-demi": {
|
||||||
|
"version": "0.14.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
|
||||||
|
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/agent-base": {
|
"node_modules/agent-base": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@canvasjs/vue-charts": "^1.0.4",
|
||||||
|
"@vueuse/core": "^10.9.0",
|
||||||
"vite-plugin-top-level-await": "^1.4.1",
|
"vite-plugin-top-level-await": "^1.4.1",
|
||||||
"vue": "^3.4.15",
|
"vue": "^3.4.15",
|
||||||
"vue3-toastify": "^0.2.1"
|
"vue3-toastify": "^0.2.1"
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
<!----------------------------------------------------
|
||||||
|
File: ArticleComponent.vue
|
||||||
|
Author: Maxime Bartha
|
||||||
|
Scope: Extension Publicatons scientifiquess
|
||||||
|
Description: Pop Up summarizing
|
||||||
|
----------------------------------------------------->
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref } from "vue";
|
||||||
|
import {onClickOutside} from '@vueuse/core'
|
||||||
|
let checked = ref([])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
isOpen: Boolean,
|
||||||
|
});
|
||||||
|
const example = ["Title","Author",["Co-author1", "co-Authors2"],
|
||||||
|
" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas condimentum ex tempor leo pulvinar, vitae imperdiet leo pellentesque. Aenean aliquam, ante at tempus sagittis, lorem leo feugiat felis, eget vestibulum tortor est nec libero. Cras sit amet venenatis velit, at rhoncus est. Cras id sem placerat, cursus sem et, aliquam felis. Nullam mi nunc, laoreet eget rutrum ac, blandit nec lorem. Duis fermentum aliquet tortor ac tristique. Aenean ac sagittis nulla, at auctor dolor. Vivamus et neque sodales, vestibulum dolor et, posuere urna. Pellentesque ut elit metus. Cras velit lectus, luctus auctor interdum eu, aliquam nec est. Donec elementum nisl sit amet nibh aliquam ultricies. Nullam felis orci, suscipit eu tincidunt pretium, euismod vel sem. Duis eget vehicula neque, nec gravida leo. Cras pellentesque arcu quis justo lobortis, ut semper massa rhoncus. Quisque sagittis dignissim congue. Nullam tortor ligula, mattis vel cursus id, pretium non lacus.",
|
||||||
|
"language",
|
||||||
|
"access",
|
||||||
|
]
|
||||||
|
const emit = defineEmits(["modal-close"]);
|
||||||
|
|
||||||
|
const target = ref(null)
|
||||||
|
onClickOutside(target, ()=>emit('modal-close'))
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="isOpen" class="modal-mask">
|
||||||
|
<div class="modal-wrapper">
|
||||||
|
<div class="modal-container" ref="target">
|
||||||
|
<ul v-for="n in example"><li>{{n}}</li></ul>
|
||||||
|
<div id="downloads">
|
||||||
|
<button @click.stop="emit('modal-close')">Download BibTex</button>
|
||||||
|
<button @click.stop="emit('modal-close')">Download Article</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9998;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
width: 70%;
|
||||||
|
margin: 150px auto;
|
||||||
|
padding: 20px 30px;
|
||||||
|
background: rgba(157, 99, 205);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#downloads {
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
#downloads button {
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 2px;
|
||||||
|
font-size: large;
|
||||||
|
color: white;
|
||||||
|
background: rgba(191, 64, 191,0.5);
|
||||||
|
border:2px solid black;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
92
frontend/src/Apps/ScientificPublications/FilterComponent.vue
Normal file
92
frontend/src/Apps/ScientificPublications/FilterComponent.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<!----------------------------------------------------
|
||||||
|
File: ArticleComponent.vue
|
||||||
|
Author: Maxime Bartha
|
||||||
|
Scope: Extension Publicatons scientifiquess
|
||||||
|
Description: Pop Up for selecting search Filters
|
||||||
|
----------------------------------------------------->
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import {onClickOutside} from '@vueuse/core'
|
||||||
|
let checked = ref([])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
isOpen: Boolean,
|
||||||
|
});
|
||||||
|
const example = ["A","B", "Lorem Ipsum AAAAAAAAAAAAAAAAAAA",
|
||||||
|
"H",
|
||||||
|
"H",
|
||||||
|
"H",
|
||||||
|
"H",
|
||||||
|
"H",
|
||||||
|
]
|
||||||
|
const emit = defineEmits(["modal-close"]);
|
||||||
|
|
||||||
|
const target = ref(null)
|
||||||
|
onClickOutside(target, ()=>emit('modal-close'))
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="isOpen" class="modal-mask">
|
||||||
|
<div class="modal-wrapper">
|
||||||
|
<div class="modal-container" ref="target">
|
||||||
|
<div id="filterGrid">
|
||||||
|
<div> example :<ul class="checkers"> <li v-for="n in example"> <input type="checkbox" :value=n v-model="checked"> {{n}} </li> </ul> </div>
|
||||||
|
<div class="vl"> example :<ul class="checkers"> <li v-for="n in example"> <input type="checkbox" :value=n v-model="checked"> {{n}} </li> </ul> </div>
|
||||||
|
<div class="vl"> example :<ul class="checkers"> <li v-for="n in example"> <input type="checkbox" :value=n v-model="checked"> {{n}} </li> </ul> </div>
|
||||||
|
<div> example :<ul class="checkers"> <li v-for="n in example"> <input type="checkbox" :value=n v-model="checked"> {{n}} </li> </ul> </div>
|
||||||
|
<div class="vl"> example :<ul class="checkers"> <li v-for="n in example"> <input type="checkbox" :value=n v-model="checked"> {{n}} </li> </ul> </div>
|
||||||
|
<div class="vl"> example :<ul class="checkers"> <li v-for="n in example"> <input type="checkbox" :value=n v-model="checked"> {{n}} </li> </ul> </div>
|
||||||
|
</div>
|
||||||
|
<div id="submit">
|
||||||
|
<button @click.stop="emit('modal-close')">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9998;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
width: 70%;
|
||||||
|
margin: 150px auto;
|
||||||
|
padding: 20px 30px;
|
||||||
|
background: rgba(157, 99, 205);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
|
||||||
|
}
|
||||||
|
|
||||||
|
#filterGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
column-gap: 5px;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
}
|
||||||
|
#filterGrid ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 15px;
|
||||||
|
height: 100px;
|
||||||
|
overflow: scroll;
|
||||||
|
scrollbar-color: #8a2be2 rgb(255,255,255,0.04);
|
||||||
|
background-color: rgba(255, 255, 255, 0.09);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vl {
|
||||||
|
border-left: 6px solid #8a2be2;
|
||||||
|
}
|
||||||
|
#submit {
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
295
frontend/src/Apps/ScientificPublications/ResearcherProfile.vue
Normal file
295
frontend/src/Apps/ScientificPublications/ResearcherProfile.vue
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
<!----------------------------------------------------
|
||||||
|
File: ResearcherProfile.vue
|
||||||
|
Author: Maxime Bartha
|
||||||
|
Scope: Extension Publicatons scientifiquess
|
||||||
|
Description: Researcher Profile Page containing his articles and his statistics
|
||||||
|
----------------------------------------------------->
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from "vue";
|
||||||
|
import FilterComponent from "@/Apps/ScientificPublications/FilterComponent.vue";
|
||||||
|
import ArticleComponent from "@/Apps/ScientificPublications/ArticleComponent.vue";
|
||||||
|
const input = ref("");
|
||||||
|
const statsOf = ref("");
|
||||||
|
const statsBy = ref("");
|
||||||
|
const isFilterOpened = ref(false);
|
||||||
|
const isArticleOpened = ref(false);
|
||||||
|
let chart;
|
||||||
|
|
||||||
|
const openModal = () => {
|
||||||
|
isFilterOpened.value = true;
|
||||||
|
};
|
||||||
|
const closeModal = () => {
|
||||||
|
isFilterOpened.value = false;
|
||||||
|
};
|
||||||
|
const submitFilters = ()=>{
|
||||||
|
// call only with those filters the get
|
||||||
|
}
|
||||||
|
const openArticle = (article) => {
|
||||||
|
isArticleOpened.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeArticle = () => {
|
||||||
|
isArticleOpened.value =false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadBibTex = (article) => {
|
||||||
|
//todo
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadArticle = (article) => {
|
||||||
|
//todo
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const articleList = [
|
||||||
|
["The Great Potato War Lorem Ipsum aeaDq Terelumni ","Author",["Co-author1", "co-Authors2"],
|
||||||
|
" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas condimentum ex tempor leo pulvinar, vitae imperdiet leo pellentesque. Aenean aliquam, ante at tempus sagittis, lorem leo feugiat felis, eget vestibulum tortor est nec libero. Cras sit amet venenatis velit, at rhoncus est. Cras id sem placerat, cursus sem et, aliquam felis. Nullam mi nunc, laoreet eget rutrum ac, blandit nec lorem. Duis fermentum aliquet tortor ac tristique. Aenean ac sagittis nulla, at auctor dolor. Vivamus et neque sodales, vestibulum dolor et, posuere urna. Pellentesque ut elit metus. Cras velit lectus, luctus auctor interdum eu, aliquam nec est. Donec elementum nisl sit amet nibh aliquam ultricies. Nullam felis orci, suscipit eu tincidunt pretium, euismod vel sem. Duis eget vehicula neque, nec gravida leo. Cras pellentesque arcu quis justo lobortis, ut semper massa rhoncus. Quisque sagittis dignissim congue. Nullam tortor ligula, mattis vel cursus id, pretium non lacus.",
|
||||||
|
"language",
|
||||||
|
"access",
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
const jsonMockViewsByYears= [
|
||||||
|
{label: "2004", y:4},
|
||||||
|
{label: "2005", y:99},
|
||||||
|
{label: "2007", y:555},
|
||||||
|
{label: "2009", y:22},
|
||||||
|
{label: "2011", y:1666},
|
||||||
|
]
|
||||||
|
|
||||||
|
function searchInList(list, searchInput){
|
||||||
|
let retList= []
|
||||||
|
if (searchInput === "")
|
||||||
|
return [list[0].slice(0,2)]
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
console.log(list[i])
|
||||||
|
if (lDistance(list[i][0], searchInput) < 10 || list[i][0].toUpperCase().indexOf(searchInput.toUpperCase()) > -1){
|
||||||
|
retList.push(list[i].slice(0,2))
|
||||||
|
}
|
||||||
|
console.log(list[i][0].toUpperCase().indexOf(searchInput.toUpperCase()))
|
||||||
|
}
|
||||||
|
return retList
|
||||||
|
}
|
||||||
|
|
||||||
|
function lDistance(s,t){
|
||||||
|
if (!s.length) return t.length;
|
||||||
|
if (!t.length) return s.length;
|
||||||
|
const arr = [];
|
||||||
|
for (let i = 0; i <= t.length; i++) {
|
||||||
|
arr[i] = [i];
|
||||||
|
for (let j = 1; j <= s.length; j++) {
|
||||||
|
arr[i][j] =
|
||||||
|
i === 0
|
||||||
|
? j
|
||||||
|
: Math.min(
|
||||||
|
arr[i - 1][j] + 1,
|
||||||
|
arr[i][j - 1] + 1,
|
||||||
|
arr[i - 1][j - 1] + (s[j - 1] === t[i - 1] ? 0 : 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr[t.length][s.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = reactive({
|
||||||
|
backgroundColor:null,
|
||||||
|
theme: "light2",
|
||||||
|
animationEnabled: true,
|
||||||
|
title: {
|
||||||
|
fontColor: "white",
|
||||||
|
text : "please select options",
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: "pie",
|
||||||
|
indexLabel: "{label} (#percent%)",
|
||||||
|
yValueFormatString: "#,##0",
|
||||||
|
indexLabelFontColor: "white",
|
||||||
|
toolTipContent:
|
||||||
|
"<span style='\"'color: {color};'\"'>{label}</span> {y}(#percent%)",
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
function update(){
|
||||||
|
options.title = {
|
||||||
|
fontColor: "white",
|
||||||
|
text: statsOf.value + " By "+ statsBy.value,
|
||||||
|
}
|
||||||
|
if (statsOf.value === "views" && statsBy.value === "years") {
|
||||||
|
options.data[0].dataPoints = jsonMockViewsByYears;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.title.text = statsOf.value + " By "+ statsBy.value;
|
||||||
|
chart.render()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="main">
|
||||||
|
<FilterComponent :isOpen="isFilterOpened" @modal-close="closeModal" @submit="submitFilters">
|
||||||
|
</FilterComponent>
|
||||||
|
<ArticleComponent :isOpen="isArticleOpened" @modal-close="closeArticle"></ArticleComponent>
|
||||||
|
<div id="profilePicture">
|
||||||
|
<img src="/Clyde.png" />
|
||||||
|
</div>
|
||||||
|
<div id="researcherInfos">
|
||||||
|
<div class="surrounded">John Doe</div>
|
||||||
|
<div class="surrounded">Orcid : 12144-2144-12336-B</div>
|
||||||
|
<div class="surrounded">Email : John.Doe@umons.ac.be</div>
|
||||||
|
|
||||||
|
<div class="surrounded">
|
||||||
|
site :
|
||||||
|
<a href="http://localhost:5173" style="color: #007aff">here</a>
|
||||||
|
</div>
|
||||||
|
<div class="surrounded">Domain : physics, IT</div>
|
||||||
|
<div id="coAuthorList" class="surrounded">Co-authors list : D</div>
|
||||||
|
</div>
|
||||||
|
<div id="stats">
|
||||||
|
<div class="surrounded">
|
||||||
|
Stat type :
|
||||||
|
<select @change="update()" id="stats-select" v-model="statsOf">
|
||||||
|
<option value="views">Views</option>
|
||||||
|
<option value="co-authors">Co-authors</option>
|
||||||
|
<option value="articles">Articles</option>
|
||||||
|
<option value="language">Languages</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="surrounded">
|
||||||
|
Class by:
|
||||||
|
<select @change="update()" id="classed-select" v-model="statsBy">
|
||||||
|
<option selected="selected" value="years">Years</option>
|
||||||
|
<option value="months">Months</option>
|
||||||
|
<option value="topics">Topics</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div id="statsPie">
|
||||||
|
<CanvasJSChart :options="options" id=chart @chart-ref="c => chart = c "/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="articles">
|
||||||
|
<div id="search">
|
||||||
|
<input type="text" id="search-input" placeholder="search articles" v-model="input"/>
|
||||||
|
<button id="filterButton" @click="openModal"> Filters </button>
|
||||||
|
</div>
|
||||||
|
<ul id="articlesUL">
|
||||||
|
<li id="articleLi" v-for="n in searchInList(articleList,input)">
|
||||||
|
<div class="vl"> {{n[0]}}</div>
|
||||||
|
<div class="vl"> {{n[1]}}</div>
|
||||||
|
<a @click="openArticle"> MoreInfo </a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#main {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 22% auto;
|
||||||
|
grid-template-rows: 26% auto;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#profilePicture {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#profilePicture img {
|
||||||
|
align-self: center;
|
||||||
|
justify-self: center;
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#researcherInfos {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
column-gap: 5px;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surrounded {
|
||||||
|
border: 2px solid black;
|
||||||
|
color: white;
|
||||||
|
font-size: x-large;
|
||||||
|
align-self: center;
|
||||||
|
text-align: center;
|
||||||
|
background-color: rgba(255, 255, 255, 0.09);
|
||||||
|
border-radius: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surrounded select {
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
border: 1px solid black;
|
||||||
|
color: white;
|
||||||
|
background-color: rgb(255, 255, 255, 0.1);
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
#statsPie {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#search{
|
||||||
|
width: 100%;
|
||||||
|
height: 10%;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
#search-input {
|
||||||
|
margin-left: 25px;
|
||||||
|
width: 75%;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 12px 20px 12px 40px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
height: 20px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filterButton {
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 2px;
|
||||||
|
font-size: xx-large;
|
||||||
|
color: white;
|
||||||
|
background: rgba(191, 64, 191,0.5);
|
||||||
|
border:2px solid black;
|
||||||
|
}
|
||||||
|
#filterButton:hover{
|
||||||
|
background: rgba(191, 64, 191);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#articlesUL {
|
||||||
|
list-style-type: none;
|
||||||
|
color: white;
|
||||||
|
padding: 12px;
|
||||||
|
margin: 5px;
|
||||||
|
height: 400px;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
#articleLi{
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
border: 2px solid black;
|
||||||
|
color: white;
|
||||||
|
font-size: x-large;
|
||||||
|
text-align: center;
|
||||||
|
text-indent: 7px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.09);
|
||||||
|
border-radius: 18px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
a{
|
||||||
|
color:#007aff;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vl {
|
||||||
|
border-right: 2px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -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>
|
||||||
|
|
||||||
|
@ -4,5 +4,8 @@ import 'https://kit.fontawesome.com/fb3bbd0a95.js'
|
|||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
import CanvasJSChart from '@canvasjs/vue-charts';
|
||||||
|
|
||||||
createApp(App).mount('#app')
|
const app = createApp(App);
|
||||||
|
app.use(CanvasJSChart);
|
||||||
|
app.mount('#app');
|
||||||
|
@ -9,6 +9,8 @@ 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 ResearcherProfile from "@/Apps/ScientificPublications/ResearcherProfile.vue";
|
||||||
|
import Msg from "@/Apps/Msg.vue"
|
||||||
|
|
||||||
const apps = {
|
const apps = {
|
||||||
'/login': LoginPage,
|
'/login': LoginPage,
|
||||||
@ -17,6 +19,8 @@ const apps = {
|
|||||||
'/manage-courses' : Courses,
|
'/manage-courses' : Courses,
|
||||||
'/users-list' : Users,
|
'/users-list' : Users,
|
||||||
'/students-list' : Students,
|
'/students-list' : Students,
|
||||||
|
'/researcher-profile' : ResearcherProfile,
|
||||||
|
'/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