Compare commits
72 Commits
bbddcb26ad
...
b382bf957f
Author | SHA1 | Date | |
---|---|---|---|
b382bf957f | |||
22665f0565 | |||
d324d7447d | |||
4d007534b3 | |||
1a266cdfbd | |||
608b6e4893 | |||
76dcea186c | |||
a79f23fed0 | |||
219165aacf | |||
f081b7206f | |||
54d19eb888 | |||
041fe7f95d | |||
6077e65b50 | |||
be7f42aafe | |||
e998fb2ab4 | |||
a168d41aee | |||
3f4f6ed49a | |||
fed567e9ab | |||
14c5423328 | |||
7394a23b45 | |||
939b4f5492 | |||
da2c0f472d | |||
3281bf1d7e | |||
47f1bffb24 | |||
3ea48c20aa | |||
8c70108a1c | |||
e303048f7e | |||
6116cbdaa4 | |||
bdfa2e6389 | |||
d4c442c64a | |||
5c0dfa3596 | |||
24f82812f4 | |||
f269e24bb4 | |||
7a05fc1316 | |||
821377a72f | |||
388c53e47b | |||
87b02af68e | |||
f184de21a8 | |||
63d0087d0c | |||
eacdf8d47a | |||
1498cfa11e | |||
17cb969160 | |||
4720669c2c | |||
5e9eccc4f6 | |||
8650482d11 | |||
783cd8fa9f | |||
40186f9898 | |||
b7a729c899 | |||
fdf4993def | |||
dad6953f99 | |||
f99ed470f8 | |||
9a83d14aea | |||
0cbe0dd82b | |||
3167d1f2fc | |||
a94167c8a0 | |||
d31547c4cc | |||
ec2b975467 | |||
b8b193f344 | |||
05359d64ac | |||
3d78851b29 | |||
dbe28a7fed | |||
bd7d2c2d51 | |||
91c7f42521 | |||
bd27ffd3cb | |||
91ee3adbcd | |||
c1b2742a8f | |||
2805fede4b | |||
951feed3c8 | |||
95054fa973 | |||
3af83a58d3 | |||
47c5c14862 | |||
db895a6091 |
@ -0,0 +1,63 @@
|
||||
package ovh.herisson.Clyde.DTO.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file ResearchDTO.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Research format to return to front (without author's password)
|
||||
******************************************************/
|
||||
|
||||
import lombok.Data;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Access;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.PaperType;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Research;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
public class ResearchDTO {
|
||||
|
||||
private long id;
|
||||
private String title;
|
||||
private ResearcherDTO researcher;
|
||||
private final Set<ResearcherDTO> coAuthors;
|
||||
private Date releaseDate;
|
||||
private PaperType paperType;
|
||||
private String pdfLocation;
|
||||
private String bibTexLocation;
|
||||
private String language;
|
||||
private Access access;
|
||||
private String domain;
|
||||
private String summary;
|
||||
private long views;
|
||||
|
||||
private ResearchDTO(String title, ResearcherDTO researcherDTO, Date releaseDate, PaperType paperType, String pdfLocation, String language, Access access, String domain, String bibTexLocation, String summary, Set<Researcher> coAuthors, long id, long views) {
|
||||
this.title = title;
|
||||
this.researcher = researcherDTO;
|
||||
this.releaseDate = releaseDate;
|
||||
this.paperType = paperType;
|
||||
this.pdfLocation = pdfLocation;
|
||||
this.language = language;
|
||||
this.access = access;
|
||||
this.domain = domain;
|
||||
this.summary = summary;
|
||||
this.id = id;
|
||||
this.bibTexLocation = bibTexLocation;
|
||||
this.coAuthors = new HashSet<>();
|
||||
for (Researcher coAuthor: coAuthors) {
|
||||
this.coAuthors.add(ResearcherDTO.construct(coAuthor));
|
||||
}
|
||||
this.views = views;
|
||||
}
|
||||
|
||||
|
||||
public static ResearchDTO construct(Research research){
|
||||
return new ResearchDTO(research.getTitle(), ResearcherDTO.construct(research.getAuthor()), research.getReleaseDate(),
|
||||
research.getPaperType(),research.getPdfLocation(),research.getLanguage(),research.getAccess(),
|
||||
research.getDomain(),research.getBibTexLocation(), research.getSummary(), research.getCoAuthors(),research.getId(), research.getViews());
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package ovh.herisson.Clyde.DTO.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file ResearcherDTO.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Researcher Format to return to front (without user password)
|
||||
******************************************************/
|
||||
import lombok.Data;
|
||||
import ovh.herisson.Clyde.Services.ProtectionService;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class ResearcherDTO {
|
||||
|
||||
private long id;
|
||||
private Map<String,Object> user;
|
||||
private String site;
|
||||
private String domain;
|
||||
private String orcidId;
|
||||
|
||||
|
||||
private ResearcherDTO(long id, Map<String ,Object> user, String site,String domain,String orcidId){
|
||||
this.domain = domain;
|
||||
this.orcidId = orcidId;
|
||||
this.site = site;
|
||||
this.user = user;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static ResearcherDTO construct(Researcher researcher){
|
||||
return new ResearcherDTO(researcher.getId(), ProtectionService.userWithoutPassword(researcher.getUser()),researcher.getSite(),
|
||||
researcher.getDomain(),researcher.getOrcidId());
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import ovh.herisson.Clyde.Services.AuthenticatorService;
|
||||
import ovh.herisson.Clyde.Services.ScientificPublications.ResearchesService;
|
||||
import ovh.herisson.Clyde.Tables.Applications;
|
||||
import ovh.herisson.Clyde.Tables.Role;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
@ -20,7 +21,10 @@ public class ApplicationsController {
|
||||
|
||||
AuthenticatorService authServ;
|
||||
|
||||
public ApplicationsController(AuthenticatorService authServ){
|
||||
ResearchesService researchesServ;
|
||||
|
||||
public ApplicationsController(AuthenticatorService authServ, ResearchesService researchesServ){
|
||||
this.researchesServ = researchesServ;
|
||||
this.authServ = authServ;
|
||||
}
|
||||
|
||||
@ -47,6 +51,7 @@ public class ApplicationsController {
|
||||
|
||||
//if unAuthed
|
||||
authorizedApps.add(Applications.Login);
|
||||
authorizedApps.add(Applications.ListResearches);
|
||||
authorizedApps.add(Applications.Schedule);
|
||||
|
||||
User user = authServ.getUserFromToken(token);
|
||||
@ -71,10 +76,15 @@ public class ApplicationsController {
|
||||
authorizedApps.add(Applications.Requests);
|
||||
authorizedApps.add(Applications.StudentsList);}
|
||||
|
||||
if (researchesServ.getResearcherByUser(user) != null)
|
||||
authorizedApps.add(Applications.ManageResearcherProfile);
|
||||
|
||||
if (!authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin},token)){
|
||||
authorizedApps.add(Applications.UsersList);
|
||||
authorizedApps.add(Applications.ManageSchedules);
|
||||
authorizedApps.add(Applications.LessonRequests);}
|
||||
authorizedApps.add(Applications.LessonRequests);
|
||||
authorizedApps.add(Applications.CreateUser);
|
||||
}
|
||||
|
||||
if (!authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin, Role.InscriptionService},token)){
|
||||
authorizedApps.add(Applications.Payments);}
|
||||
|
@ -7,17 +7,23 @@ import ovh.herisson.Clyde.Repositories.Inscription.MinervalRepository;
|
||||
import ovh.herisson.Clyde.Repositories.Inscription.ScholarshipRequestRepository;
|
||||
import ovh.herisson.Clyde.Repositories.Inscription.UnregisterRequestRepository;
|
||||
import ovh.herisson.Clyde.Services.*;
|
||||
import ovh.herisson.Clyde.Services.Inscription.InscriptionService;
|
||||
import ovh.herisson.Clyde.Services.ScientificPublications.ResearchesService;
|
||||
import ovh.herisson.Clyde.Tables.*;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Access;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.PaperType;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Research;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
import ovh.herisson.Clyde.Services.Inscription.InscriptionService;
|
||||
import ovh.herisson.Clyde.Tables.Inscription.ExternalCurriculum;
|
||||
import ovh.herisson.Clyde.Tables.Inscription.InscriptionRequest;
|
||||
import ovh.herisson.Clyde.Tables.Inscription.Minerval;
|
||||
import ovh.herisson.Clyde.Tables.Inscription.ScholarshipRequest;
|
||||
import ovh.herisson.Clyde.Tables.Inscription.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
|
||||
|
||||
public class MockController {
|
||||
public final UserService userService;
|
||||
public final UserRepository userRepo;
|
||||
@ -36,14 +42,13 @@ public class MockController {
|
||||
public final LessonRequestService lessonRequestService;
|
||||
ArrayList<User> mockUsers;
|
||||
|
||||
public final ResearchesService researchesService;
|
||||
public final UserCurriculumRepository ucr;
|
||||
|
||||
public final MinervalRepository minervalRepository;
|
||||
|
||||
public final ScholarshipRequestRepository scholarshipRequestRepository;
|
||||
|
||||
|
||||
public final UnregisterRequestRepository uninscriptionRequestRepository;
|
||||
public MockController(UserService userService, UserRepository userRepo, TokenRepository tokenRepo, TokenService tokenService, CurriculumCourseService CurriculumCourseService, CurriculumService curriculumService, CourseService courseService, ExternalCurriculumRepository externalCurriculumRepository, InscriptionService inscriptionService, UserCurriculumRepository ucr, MinervalRepository minervalRepository, ScholarshipRequestRepository scholarshipRequestRepository, UnregisterRequestRepository unregisterRequestRepository, LessonService lessonService, ScheduleService scheduleService, ScheduleLessonService scheduleLessonService, LessonRequestService lessonRequestService){
|
||||
public MockController(UserService userService, UserRepository userRepo, TokenRepository tokenRepo, TokenService tokenService, CurriculumCourseService CurriculumCourseService, CurriculumService curriculumService, CourseService courseService, ExternalCurriculumRepository externalCurriculumRepository, ResearchesService researchesService, InscriptionService inscriptionService, UserCurriculumRepository ucr, MinervalRepository minervalRepository, ScholarshipRequestRepository scholarshipRequestRepository, UnregisterRequestRepository unregisterRequestRepository, LessonService lessonService, ScheduleService scheduleService, ScheduleLessonService scheduleLessonService, LessonRequestService lessonRequestService){
|
||||
this.userService = userService;
|
||||
this.tokenRepo = tokenRepo;
|
||||
this.userRepo = userRepo;
|
||||
@ -53,6 +58,7 @@ public class MockController {
|
||||
this.courseService = courseService;
|
||||
this.externalCurriculumRepository = externalCurriculumRepository;
|
||||
this.inscriptionService = inscriptionService;
|
||||
this.researchesService = researchesService;
|
||||
this.lessonService = lessonService;
|
||||
this.scheduleService = scheduleService;
|
||||
this.scheduleLessonService = scheduleLessonService;
|
||||
@ -70,7 +76,8 @@ public class MockController {
|
||||
*/
|
||||
|
||||
@PostMapping("/mock")
|
||||
public void postMock(){
|
||||
public void postMock() {
|
||||
|
||||
|
||||
// user part
|
||||
User herobrine = new User("brine","hero","admin@admin.com","behind","ShadowsLand",new Date(0), null,Role.Admin,"admin");
|
||||
@ -87,9 +94,9 @@ public class MockController {
|
||||
ExternalCurriculum externalCurriculum = new ExternalCurriculum(null, "HEH", "Bachelier en ingénieur", "completed", 2015, 2017, null, joe);
|
||||
externalCurriculumRepository.save(externalCurriculum);
|
||||
|
||||
Minerval minerval = new Minerval(joe.getRegNo(), 0, 852, 2023);
|
||||
minervalRepository.save(minerval);
|
||||
// Course / Curriculum part
|
||||
Minerval minerval = new Minerval(joe.getRegNo(), 0, 852, 2023);
|
||||
minervalRepository.save(minerval);
|
||||
// Course / Curriculum part
|
||||
|
||||
Curriculum infoBab1 = new Curriculum(1,"info", false);
|
||||
Curriculum chemistryBab1 = new Curriculum(1,"chemistry", false);
|
||||
@ -121,13 +128,14 @@ public class MockController {
|
||||
Course psycho1 = new Course(21, "Neuroreaction of isolated brain cells",joke);
|
||||
Course commun = new Course(2, "cours commun",joke);
|
||||
|
||||
courseService.save(progra1);
|
||||
courseService.save(chemistry1);
|
||||
courseService.save(psycho1);
|
||||
courseService.save(commun);
|
||||
courseService.save(progra1);
|
||||
courseService.save(chemistry1);
|
||||
courseService.save(psycho1);
|
||||
courseService.save(commun);
|
||||
|
||||
ScholarshipRequest ssr1 = new ScholarshipRequest(joe, RequestState.Pending, 0, new Date(), "test", "test");
|
||||
scholarshipRequestRepository.save(ssr1);
|
||||
|
||||
ScholarshipRequest ssr1 = new ScholarshipRequest(joe, RequestState.Pending, 0, new Date(), "test", "test");
|
||||
scholarshipRequestRepository.save(ssr1);
|
||||
|
||||
CurriculumCourseService.save(new CurriculumCourse(infoBab1,progra1));
|
||||
CurriculumCourseService.save(new CurriculumCourse(infoBab1,commun));
|
||||
@ -136,12 +144,42 @@ public class MockController {
|
||||
CurriculumCourseService.save(new CurriculumCourse(psychologyBab1,commun));
|
||||
CurriculumCourseService.save(new CurriculumCourse(chemistryBab1, chemistry1));
|
||||
|
||||
CurriculumCourseService.save(new CurriculumCourse(chemistryBab1,commun));
|
||||
CurriculumCourseService.save(new CurriculumCourse(chemistryBab1,chemistry1));
|
||||
CurriculumCourseService.save(new CurriculumCourse(chemistryBab1, commun));
|
||||
CurriculumCourseService.save(new CurriculumCourse(chemistryBab1, chemistry1));
|
||||
|
||||
|
||||
InscriptionRequest inscriptionRequest = new InscriptionRequest("helen","prenom","non","helen@gmail.com","america",new Date(),(long) 4,RequestState.Pending,"yes.png","password", null, new Date(), RequestState.Pending, null);
|
||||
|
||||
inscriptionService.save(inscriptionRequest);
|
||||
inscriptionService.save(inscriptionRequest);
|
||||
|
||||
///////////////////////////
|
||||
// extension Publications Scientifiques
|
||||
Researcher jojoResearcherAccount = new Researcher(jojo, "3363-22555-AB33-T", null, "IT");
|
||||
|
||||
Researcher joResearchAccount = new Researcher(joe,"N555-321213-BED-DD",null, "Physics");
|
||||
|
||||
|
||||
Researcher output = researchesService.saveResearcher(jojoResearcherAccount);
|
||||
Researcher joOutput = researchesService.saveResearcher(joResearchAccount);
|
||||
|
||||
Set<Researcher> coAuthor = new HashSet<>();
|
||||
coAuthor.add(joOutput);
|
||||
|
||||
Research jojoResearch = new Research("Graphs : Advanced Search Algorithms", output, new Date(0),
|
||||
PaperType.Article, "test.pdf", null, "english",
|
||||
Access.OpenSource, "IT", "This Article's title speaks for itself \n We'll discuss about advanced Graph search Algorithms",coAuthor);
|
||||
Research restrictedResearch = new Research("just another Name", output, new Date(1111111111),
|
||||
PaperType.Article, "restricted", null, "english",
|
||||
Access.Restricted, "Restricted", "This Article's title speaks for itself\n We'll discuss about advanced Graph search Algorithms", new HashSet<>());
|
||||
|
||||
Research privateResearch = new Research("the great Potato War", output, new Date(),
|
||||
PaperType.Article, "private", null, "english",
|
||||
Access.Private, "private", "This Article's title speaks for itself\n We'll discuss about advanced Graph search Algorithms",null);
|
||||
|
||||
|
||||
researchesService.saveResearch(restrictedResearch);
|
||||
researchesService.saveResearch(privateResearch);
|
||||
researchesService.saveResearch(jojoResearch);
|
||||
|
||||
|
||||
//Schedule part
|
||||
|
@ -0,0 +1,167 @@
|
||||
package ovh.herisson.Clyde.EndPoints.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file ResearchController.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* API class for the researches
|
||||
******************************************************/
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ovh.herisson.Clyde.DTO.ScientificPublications.ResearchDTO;
|
||||
import ovh.herisson.Clyde.DTO.ScientificPublications.ResearcherDTO;
|
||||
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
|
||||
import ovh.herisson.Clyde.Services.AuthenticatorService;
|
||||
import ovh.herisson.Clyde.Services.ScientificPublications.ResearchesService;
|
||||
import ovh.herisson.Clyde.Tables.Role;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Research;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
|
||||
@AllArgsConstructor
|
||||
public class ResearchController {
|
||||
|
||||
|
||||
|
||||
private final ResearchesService researchesServ;
|
||||
|
||||
private final AuthenticatorService authServ;
|
||||
|
||||
/** Is accessible by anyone
|
||||
* but if the user doesn't have the permission to download the research
|
||||
* the return Research Download URL will be null
|
||||
*/
|
||||
@GetMapping("/research/{id}")
|
||||
public ResponseEntity<ResearchDTO> getResearch(@RequestHeader(value = "Authorization", required = false) String token, @PathVariable long id){
|
||||
|
||||
Research research = researchesServ.getResearchById(id);
|
||||
|
||||
if (research == null)
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
|
||||
if (researchesServ.hasNoAccessTo(research,authServ.getUserFromToken(token))){
|
||||
research.setPdfLocation(null);
|
||||
}// If the user doesn't have access to the document he can't download the pdf
|
||||
|
||||
return new ResponseEntity<>(ResearchDTO.construct(research), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token used to know if the user can download or not the research pdf
|
||||
* @return every research
|
||||
*/
|
||||
@GetMapping("/researches")
|
||||
public ResponseEntity<Iterable<ResearchDTO>> getResearches(@RequestHeader(value = "Authorization",required = false) String token){
|
||||
Iterable<Research> researches = researchesServ.getAllResearches();
|
||||
|
||||
ArrayList<ResearchDTO> toReturnResearches = new ArrayList<>();
|
||||
|
||||
for (Research research: researches){
|
||||
if (researchesServ.hasNoAccessTo(research,authServ.getUserFromToken(token))){
|
||||
research.setPdfLocation(null);
|
||||
}
|
||||
toReturnResearches.add(ResearchDTO.construct(research));
|
||||
}
|
||||
return new ResponseEntity<>(toReturnResearches,HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/researches/{id}")
|
||||
public ResponseEntity<Iterable<ResearchDTO>> getResearchesFromResearcher(@RequestHeader(value = "Authorization",required = false) String token,
|
||||
@PathVariable Long id
|
||||
){
|
||||
Iterable<Research> researches = researchesServ.getResearchesByAuthor(id);
|
||||
if (researches == null) return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
|
||||
ArrayList<ResearchDTO> toReturnResearches = new ArrayList<>();
|
||||
|
||||
for (Research research: researches){
|
||||
if (researchesServ.hasNoAccessTo(research,authServ.getUserFromToken(token))){
|
||||
research.setPdfLocation(null);
|
||||
}
|
||||
toReturnResearches.add(ResearchDTO.construct(research));
|
||||
}
|
||||
return new ResponseEntity<>(toReturnResearches,HttpStatus.OK);
|
||||
}
|
||||
|
||||
/** post a new research
|
||||
*
|
||||
* @return the research saved
|
||||
*/
|
||||
@PostMapping("/research")
|
||||
public ResponseEntity<Research> postResearch(@RequestHeader("Authorization") String token, @RequestBody Research research){
|
||||
|
||||
if (authServ.isNotIn(new Role[]{Role.Admin},token) &&
|
||||
researchesServ.getResearcherByUser(authServ.getUserFromToken(token)) == null){
|
||||
return new UnauthorizedResponse<>(null);
|
||||
} // if the poster isn't a researcher
|
||||
|
||||
return new ResponseEntity<>(researchesServ.saveResearch(research), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/** post updates to the research
|
||||
* in the updates, the coAuthors have to be referenced by their ids
|
||||
*
|
||||
*/
|
||||
@PatchMapping("/research/{id}")
|
||||
public ResponseEntity<String> patchResearch(@RequestHeader("Authorization") String token,
|
||||
@RequestBody Map<String,Object> updates,
|
||||
@PathVariable long id
|
||||
)
|
||||
{
|
||||
Research research = researchesServ.getResearchById(id);
|
||||
Researcher researcher = researchesServ.getResearcherByUser(authServ.getUserFromToken(token));
|
||||
|
||||
if (research == null)
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
|
||||
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary},token) &&
|
||||
researcher != research.getAuthor()) {
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
|
||||
researchesServ.modifyResearchData(research, updates);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
/** Only Admin, Secretary and author can delete a research
|
||||
*
|
||||
*/
|
||||
@DeleteMapping("/research/{id}")
|
||||
public ResponseEntity<String> deleteResearch(@RequestHeader("Authorization") String token, @PathVariable long id){
|
||||
|
||||
Research research = researchesServ.getResearchById(id);
|
||||
Researcher researcher = researchesServ.getResearcherByUser(authServ.getUserFromToken(token));
|
||||
|
||||
if (research == null)
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
|
||||
if (authServ.isNotIn(new Role[]{Role.Admin, Role.Secretary},token) &&
|
||||
researcher != research.getAuthor()){
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
|
||||
researchesServ.deleteResearch(research);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
///////
|
||||
//views part
|
||||
@PostMapping("/addview/cdn/{url}")
|
||||
public ResponseEntity<ResearchDTO> addView(@PathVariable String url){
|
||||
System.out.println(url);
|
||||
Research research = researchesServ.getResearchByUrl("cdn/" + url);
|
||||
if (research ==null) return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
|
||||
return new ResponseEntity<>(ResearchDTO.construct(researchesServ.addView(research)), HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package ovh.herisson.Clyde.EndPoints.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file ResearcherController.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* API class for the researchers
|
||||
******************************************************/
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ovh.herisson.Clyde.DTO.ScientificPublications.ResearcherDTO;
|
||||
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
|
||||
import ovh.herisson.Clyde.Services.AuthenticatorService;
|
||||
import ovh.herisson.Clyde.Services.ScientificPublications.ResearchesService;
|
||||
import ovh.herisson.Clyde.Tables.Role;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
|
||||
@AllArgsConstructor
|
||||
public class ResearcherController {
|
||||
|
||||
ResearchesService researchesServ;
|
||||
AuthenticatorService authServ;
|
||||
|
||||
|
||||
@GetMapping("/researcher/{id}")
|
||||
public ResponseEntity<ResearcherDTO> getResearcher(@PathVariable long id){
|
||||
Researcher researcher = researchesServ.getResearcherById(id);
|
||||
return new ResponseEntity<>(ResearcherDTO.construct(researcher),HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Everyone can access every researcher Account
|
||||
* @return all the researchers accounts
|
||||
*/
|
||||
@GetMapping("/researchers")
|
||||
public ResponseEntity<Iterable<ResearcherDTO>> getAllResearchers(){
|
||||
Iterable<Researcher> researchers = researchesServ.getAllResearchers();
|
||||
ArrayList<ResearcherDTO> toReturnResearchersDTO = new ArrayList<>();
|
||||
for (Researcher researcher: researchers){
|
||||
toReturnResearchersDTO.add(ResearcherDTO.construct(researcher));
|
||||
}
|
||||
return new ResponseEntity<>(toReturnResearchersDTO, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/researcher")
|
||||
public ResponseEntity<ResearcherDTO> getSelf(@RequestHeader("Authorization") String token){
|
||||
|
||||
Researcher self = researchesServ.getResearcherByUser(authServ.getUserFromToken(token));
|
||||
|
||||
if (self ==null) return new UnauthorizedResponse<>(null);
|
||||
|
||||
return new ResponseEntity<>(ResearcherDTO.construct(self), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping("/researcher")
|
||||
public ResponseEntity<ResearcherDTO> postResearcher(@RequestHeader("Authorization") String token, @RequestBody Researcher researcher){
|
||||
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary}, token)){
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
|
||||
Researcher posted = researchesServ.saveResearcher(researcher);
|
||||
|
||||
if (posted == null) return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
|
||||
|
||||
return new ResponseEntity<>(ResearcherDTO.construct(posted), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@PatchMapping("/researcher/{id}")
|
||||
public ResponseEntity<ResearcherDTO> patchResearcher(@RequestHeader("Authorization") String token,
|
||||
@PathVariable long id,
|
||||
@RequestBody Map<String ,Object> updates){
|
||||
|
||||
Researcher researcher = researchesServ.getResearcherById(id);
|
||||
if (authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin}, token)
|
||||
&& researcher.getId() != researchesServ.getResearcherByUser(authServ.getUserFromToken(token)).getId())
|
||||
return new UnauthorizedResponse<>(null);
|
||||
|
||||
|
||||
if (researcher == null) return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
|
||||
researchesServ.modifyResearcherData(researcher,updates);
|
||||
|
||||
return new ResponseEntity<>(ResearcherDTO.construct(researcher),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/researcher/{id}")
|
||||
public ResponseEntity<String> deleteResearcher(@RequestHeader ("Authorization") String token, @PathVariable long id){
|
||||
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary},token))
|
||||
return new UnauthorizedResponse<>(null);
|
||||
|
||||
researchesServ.deleteResearcher(researchesServ.getResearcherById(id));
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package ovh.herisson.Clyde.EndPoints.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file StatController.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Api class for handling statistics
|
||||
******************************************************/
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ovh.herisson.Clyde.Services.ScientificPublications.ResearchesService;
|
||||
import ovh.herisson.Clyde.Services.ScientificPublications.StatisticsService;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
|
||||
@AllArgsConstructor
|
||||
public class StatController {
|
||||
|
||||
|
||||
private StatisticsService statServ;
|
||||
private ResearchesService researchesServ;
|
||||
|
||||
/** returns all the statistics in a 2D array
|
||||
*
|
||||
* @param id the researcher's id
|
||||
* @return all the stats in a 2D array
|
||||
*/
|
||||
@GetMapping("/stats/{id}")
|
||||
public ResponseEntity<Iterable<Iterable<Map<String, Integer>>>> getStat(@PathVariable Long id){
|
||||
|
||||
Researcher researcher = researchesServ.getResearcherById(id);
|
||||
if (researcher == null) return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
|
||||
Iterable<Iterable<Map<String,Integer>>> stats = statServ.generateStats(researcher);
|
||||
|
||||
if (stats == null) return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
|
||||
return new ResponseEntity<>(stats,HttpStatus.OK);
|
||||
|
||||
}
|
||||
}
|
@ -86,19 +86,20 @@ public class UserController {
|
||||
* @return a string clarifying the issue (if there is any)
|
||||
*/
|
||||
@PatchMapping("/user/{id}")
|
||||
public ResponseEntity<String> patchUser(@RequestHeader("Authorization") String token,
|
||||
public ResponseEntity<Map<String,Object>> patchUser(@RequestHeader("Authorization") String token,
|
||||
@RequestBody Map<String,Object> updates,
|
||||
@PathVariable Long id) {
|
||||
|
||||
if (token == null) return new UnauthorizedResponse<>(null);
|
||||
|
||||
User poster = authServ.getUserFromToken(token);
|
||||
if (poster == null) {return new UnauthorizedResponse<>("bad token");}
|
||||
if (poster == null) {return new UnauthorizedResponse<>(null);}
|
||||
|
||||
if (!userService.modifyData(id, updates, poster))
|
||||
return new UnauthorizedResponse<>("there was an issue with the updates requested");
|
||||
User modified = userService.modifyData(id,updates,poster);
|
||||
if (modified ==null)
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
|
||||
return new ResponseEntity<>(null, HttpStatus.OK);
|
||||
return new ResponseEntity<>(ProtectionService.userWithoutPassword(modified), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/teachers")
|
||||
|
@ -0,0 +1,26 @@
|
||||
package ovh.herisson.Clyde.Repositories.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file ResearchRepository.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Repository handling communication with Reseach table
|
||||
******************************************************/
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Research;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ResearchRepository extends CrudRepository<Research,Long> {
|
||||
|
||||
Research findById(long id);
|
||||
|
||||
Iterable<Research> findByAuthor(Researcher author);
|
||||
|
||||
@Query("select r from Research r where r.pdfLocation = ?1")
|
||||
Research findByPdfLocation(String url);
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package ovh.herisson.Clyde.Repositories.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file ResearcherRepository.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Repository handling communication with Reseacher table
|
||||
******************************************************/
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Research;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
public interface ResearcherRepository extends CrudRepository<Researcher,Long> {
|
||||
Researcher findByUser(User user);
|
||||
|
||||
Researcher findById(long id);
|
||||
|
||||
@Query("select r from Research r where r.author = ?1")
|
||||
Iterable<Research> findAllByAuthorId(Researcher author);
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package ovh.herisson.Clyde.Repositories.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file StatsRepository.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Repository handling communication with Reseach table for making statistics
|
||||
******************************************************/
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Research;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface StatsRepository extends CrudRepository<Research,Long> {
|
||||
|
||||
@Query("select new map(to_char(r.releaseDate, 'month') as label, sum(r.views) as y) from Research r group by to_char(r.releaseDate, 'month')")
|
||||
Iterable<Map<String ,Integer>> viewsByMonths();
|
||||
|
||||
@Query("select new map(to_char(r.releaseDate,'YYYY') as label, sum (r.views) as y) from Research r group by to_char(r.releaseDate,'YYYY')")
|
||||
Iterable<Map<String ,Integer>> viewsByYears();
|
||||
|
||||
|
||||
@Query("select new map(r.domain as label, sum(r.views) as y) from Research r group by r.domain")
|
||||
Iterable<Map<String ,Integer>> viewsByTopics();
|
||||
|
||||
|
||||
@Query("select new map(r.domain as label, count(distinct r.language) as y) from Research r group by r.domain")
|
||||
Iterable<Map<String ,Integer>> languageByTopics();
|
||||
|
||||
@Query("select new map(to_char(r.releaseDate,'YYYY') as label, count(distinct r.language) as y) from Research r group by to_char(r.releaseDate,'YYYY')")
|
||||
Iterable<Map<String ,Integer>> languageByYears();
|
||||
|
||||
@Query("select new map(to_char(r.releaseDate, 'month') as label, count(distinct r.language) as y) from Research r group by to_char(r.releaseDate, 'month')")
|
||||
Iterable<Map<String ,Integer>> languageByMonths();
|
||||
|
||||
@Query("select new map(to_char(r.releaseDate,'YYYY') as label, count(distinct r) as y) from Research r group by to_char(r.releaseDate,'YYYY')")
|
||||
Iterable<Map<String ,Integer>> researchesByYears();
|
||||
|
||||
@Query("select new map(r.domain as label, count(distinct r) as y) from Research r group by r.domain")
|
||||
Iterable<Map<String ,Integer>> researchesByTopics();
|
||||
|
||||
@Query("select new map(to_char(r.releaseDate, 'month') as label, count(distinct r) as y) from Research r group by to_char(r.releaseDate, 'month')")
|
||||
Iterable<Map<String ,Integer>> researchesByMonth();
|
||||
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
package ovh.herisson.Clyde.Services.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file ResearchesService.java
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Service for managing researcher and researches
|
||||
******************************************************/
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ovh.herisson.Clyde.Repositories.ScientificPublications.ResearchRepository;
|
||||
import ovh.herisson.Clyde.Repositories.ScientificPublications.ResearcherRepository;
|
||||
import ovh.herisson.Clyde.Tables.Role;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.*;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ResearchesService {
|
||||
|
||||
private final ResearcherRepository researcherRepo;
|
||||
private final ResearchRepository articleRepo;
|
||||
|
||||
|
||||
// researches Part
|
||||
public Research getResearchById(long id) {
|
||||
return articleRepo.findById(id);
|
||||
}
|
||||
|
||||
public Research getResearchByUrl(String url) {
|
||||
return articleRepo.findByPdfLocation(url);
|
||||
}
|
||||
|
||||
|
||||
public Iterable<Research> getResearchesByAuthor(long authorId){
|
||||
Researcher researcher = researcherRepo.findById(authorId);
|
||||
if (researcher == null) return null;
|
||||
|
||||
return researcherRepo.findAllByAuthorId(researcher);
|
||||
}
|
||||
|
||||
public Research saveResearch(Research research) {
|
||||
return articleRepo.save(research);
|
||||
}
|
||||
|
||||
public void modifyResearchData(Research research, Map<String, Object> updates) {
|
||||
for (Map.Entry<String, Object> entry : updates.entrySet()){
|
||||
switch (entry.getKey()){
|
||||
case "title":
|
||||
research.setTitle((String) entry.getValue());
|
||||
break;
|
||||
case "paperType":
|
||||
research.setPaperType((PaperType) entry.getValue());
|
||||
break;
|
||||
case "language":
|
||||
research.setLanguage((String) entry.getValue());
|
||||
break;
|
||||
case "domain":
|
||||
research.setDomain((String) entry.getValue());
|
||||
break;
|
||||
case "summary":
|
||||
research.setSummary((String) entry.getValue());
|
||||
break;
|
||||
case "access":
|
||||
research.setAccess(Access.valueOf((String) entry.getValue()));
|
||||
break;
|
||||
case "coAuthors":
|
||||
Set<Researcher> set = new HashSet<>();
|
||||
|
||||
for (int id : (List<Integer>) entry.getValue()) {
|
||||
|
||||
Researcher r = researcherRepo.findById(id);
|
||||
if (r != null){
|
||||
set.add(r);
|
||||
}
|
||||
}
|
||||
research.setCoAuthors(set);
|
||||
break;
|
||||
}
|
||||
}
|
||||
articleRepo.save(research);
|
||||
}
|
||||
|
||||
public void deleteResearch(Research research) {
|
||||
articleRepo.delete(research);
|
||||
}
|
||||
|
||||
|
||||
// Researchers Part
|
||||
public Researcher getResearcherByUser(User user){
|
||||
return researcherRepo.findByUser(user);
|
||||
}
|
||||
|
||||
public Iterable<Research> getAllResearches() {
|
||||
return articleRepo.findAll();
|
||||
}
|
||||
|
||||
public Researcher saveResearcher(Researcher researcher) {
|
||||
|
||||
if (researcherRepo.findByUser(researcher.getUser()) != null) return null;
|
||||
return researcherRepo.save(researcher);
|
||||
}
|
||||
|
||||
public Iterable<Researcher> getAllResearchers() {
|
||||
return researcherRepo.findAll();
|
||||
}
|
||||
|
||||
public Researcher getResearcherById(long id) {
|
||||
return researcherRepo.findById(id);
|
||||
}
|
||||
|
||||
public void deleteResearcher(Researcher researcher) {
|
||||
articleRepo.findAll();
|
||||
for (Research r: articleRepo.findAll())
|
||||
{
|
||||
if (r.getCoAuthors().contains(researcher)){
|
||||
r.getCoAuthors().remove(researcher);
|
||||
articleRepo.save(r);
|
||||
}
|
||||
}
|
||||
researcherRepo.delete(researcher);
|
||||
}
|
||||
|
||||
public void modifyResearcherData(Researcher researcher, Map<String, Object> updates) {
|
||||
|
||||
for (Map.Entry<String, Object> entry : updates.entrySet()){
|
||||
switch (entry.getKey()){
|
||||
case "orcidId":
|
||||
if (entry.getValue() != null)
|
||||
researcher.setOrcidId((String) entry.getValue());
|
||||
break;
|
||||
case "domain":
|
||||
if (entry.getValue() != null)
|
||||
researcher.setDomain((String) entry.getValue());
|
||||
break;
|
||||
case "site":
|
||||
if (entry.getValue() != null)
|
||||
researcher.setSite((String) entry.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
researcherRepo.save(researcher);
|
||||
}
|
||||
// Other stuff
|
||||
|
||||
public Research addView(Research research) {
|
||||
research.setViews(research.getViews()+1);
|
||||
return articleRepo.save(research);
|
||||
}
|
||||
|
||||
public boolean hasNoAccessTo(Research research, User user){
|
||||
if (research.getAccess() == Access.OpenSource) return false; // if the access is open source even non-users can see it
|
||||
if (user == null) return true; // else you need at least to be a user
|
||||
|
||||
if (user.getRole() == Role.Admin) return false;
|
||||
|
||||
|
||||
Researcher researcher = getResearcherByUser(user);
|
||||
if (researcher !=null ){
|
||||
if (research.getAuthor().getId() == researcher.getId())
|
||||
return false;
|
||||
|
||||
for (Researcher coAuthor: research.getCoAuthors()){
|
||||
if (coAuthor.getId() == researcher.getId())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return research.getAccess() != Access.Restricted || (user.getRole() != Role.Secretary &&
|
||||
user.getRole() != Role.Teacher && user.getRole() != Role.InscriptionService);
|
||||
// if the access is restricted only the staff member (above) can access the research
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package ovh.herisson.Clyde.Services.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file StatisticsService
|
||||
* @author Bartha Maxime
|
||||
* @scope Publications Scientifiques
|
||||
*
|
||||
* Service for managing statistics
|
||||
******************************************************/
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ovh.herisson.Clyde.Repositories.ScientificPublications.ResearchRepository;
|
||||
import ovh.herisson.Clyde.Repositories.ScientificPublications.StatsRepository;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Research;
|
||||
import ovh.herisson.Clyde.Tables.ScientificPublications.Researcher;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class StatisticsService {
|
||||
|
||||
|
||||
private ResearchRepository articleRepo;
|
||||
private StatsRepository statsRepo;
|
||||
|
||||
|
||||
public Iterable<Iterable<Map<String, Integer>>> generateStats(Researcher researcher){
|
||||
|
||||
Iterable<Research> researches = articleRepo.findByAuthor(researcher);
|
||||
|
||||
if (researches == null) return null;
|
||||
|
||||
|
||||
ArrayList<Iterable<Map<String,Integer>>> toReturn = new ArrayList<>();
|
||||
|
||||
toReturn.add(statsRepo.viewsByYears());
|
||||
toReturn.add(statsRepo.viewsByMonths());
|
||||
toReturn.add(statsRepo.viewsByTopics());
|
||||
|
||||
toReturn.add(statsRepo.researchesByYears());
|
||||
toReturn.add(statsRepo.researchesByMonth());
|
||||
toReturn.add(statsRepo.researchesByTopics());
|
||||
|
||||
toReturn.add(statsRepo.languageByYears());
|
||||
toReturn.add(statsRepo.languageByMonths());
|
||||
toReturn.add(statsRepo.languageByTopics());
|
||||
return toReturn;
|
||||
}
|
||||
}
|
@ -45,61 +45,55 @@ public class UserService {
|
||||
* @param targetId the id of the user to update
|
||||
* @return if the changes were done or not
|
||||
*/
|
||||
public boolean modifyData(long targetId, Map<String ,Object> updates, User poster){
|
||||
public User modifyData(long targetId, Map<String ,Object> updates, User poster){
|
||||
|
||||
User target = userRepo.findById(targetId);
|
||||
if (target == null)
|
||||
return false;
|
||||
return null;
|
||||
|
||||
if (poster.getRegNo().equals(target.getRegNo())){
|
||||
for (Map.Entry<String, Object> entry : updates.entrySet()){
|
||||
if (!target.getRegNo().equals(poster.getRegNo()) && !(poster.getRole() == Role.Secretary) &&
|
||||
!(poster.getRole() == Role.Admin))
|
||||
return null;
|
||||
|
||||
switch (entry.getKey()){
|
||||
case "firstName":
|
||||
target.setFirstName((String) entry.getValue());
|
||||
break;
|
||||
case "lastName":
|
||||
target.setLastName((String) entry.getValue());
|
||||
break;
|
||||
case "email":
|
||||
target.setEmail((String) entry.getValue());
|
||||
break;
|
||||
case "address":
|
||||
target.setAddress((String) entry.getValue());
|
||||
break;
|
||||
case "country":
|
||||
target.setCountry((String) entry.getValue());
|
||||
break;
|
||||
case "birthDate":
|
||||
target.setBirthDate((Date) entry.getValue());
|
||||
break;
|
||||
case "profilePictureUrl":
|
||||
target.setProfilePictureUrl((String) entry.getValue());
|
||||
break;
|
||||
case "password":
|
||||
target.setPassword((String) entry.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
userRepo.save(target);
|
||||
return true;
|
||||
}
|
||||
// the secretary can change roles (for example if a student becomes a teacher)
|
||||
else if (poster.getRole() == Role.Secretary)
|
||||
{
|
||||
for (Map.Entry<String, Object> entry : updates.entrySet()){
|
||||
|
||||
if ( entry.getKey().equals("role")) {
|
||||
|
||||
if (entry.getValue() == Role.Admin) {return false;}
|
||||
|
||||
target.setRole((Role) entry.getValue());
|
||||
userRepo.save(target);
|
||||
return true;
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : updates.entrySet()){
|
||||
System.out.println(entry.getValue());
|
||||
switch (entry.getKey()){
|
||||
case "firstName":
|
||||
target.setFirstName((String) entry.getValue());
|
||||
break;
|
||||
case "lastName":
|
||||
target.setLastName((String) entry.getValue());
|
||||
break;
|
||||
case "email":
|
||||
target.setEmail((String) entry.getValue());
|
||||
break;
|
||||
case "address":
|
||||
target.setAddress((String) entry.getValue());
|
||||
break;
|
||||
case "country":
|
||||
target.setCountry((String) entry.getValue());
|
||||
break;
|
||||
case "birthDate":
|
||||
target.setBirthDate((Date) entry.getValue());
|
||||
break;
|
||||
case "profilePictureUrl":
|
||||
target.setProfilePictureUrl((String) entry.getValue());
|
||||
break;
|
||||
case "password":
|
||||
target.setPassword((String) entry.getValue());
|
||||
break;
|
||||
case "role":
|
||||
//a user can't change his own role
|
||||
if (poster.getRole()==Role.Secretary || poster.getRole() == Role.Admin){
|
||||
Role wanted = Role.valueOf((String) entry.getValue());
|
||||
if (wanted == Role.Admin && poster.getRole() != Role.Admin)
|
||||
return null;
|
||||
target.setRole(wanted);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
userRepo.save(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,7 +8,6 @@ public enum Applications {
|
||||
// with any token
|
||||
Profile,
|
||||
|
||||
|
||||
// Students and higher authorization
|
||||
Msg,
|
||||
Forum,
|
||||
@ -27,6 +26,13 @@ public enum Applications {
|
||||
|
||||
// InscriptionService authorization
|
||||
Requests,
|
||||
StudentsList,
|
||||
// profile of a researcher
|
||||
ResearcherProfile,
|
||||
ManageResearcherProfile,
|
||||
|
||||
//the list of all researches (filterable)
|
||||
ListResearches,
|
||||
CreateUser,
|
||||
StudentsList,
|
||||
Payments
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package ovh.herisson.Clyde.Tables;
|
||||
public enum FileType {
|
||||
ProfilePicture,
|
||||
EducationCertificate,
|
||||
Research,
|
||||
ResearchBibTex,
|
||||
JustificationDocument,
|
||||
IdentityCard,
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file Access.java
|
||||
* @author Maxime Bartha
|
||||
* @scope Extension Publications scientifiques
|
||||
*
|
||||
* Access Type for the Articles
|
||||
*
|
||||
******************************************************/
|
||||
public enum Access {
|
||||
OpenSource, // everyone can see
|
||||
Restricted, // only Researchers and Staff Members (secretary, teachers and Inscription Service)
|
||||
Private, // only authors and co-authors
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file PaperType.java
|
||||
* @author Maxime Bartha
|
||||
* @scope Extension Publications scientifiques
|
||||
*
|
||||
* Type of the scientific paper
|
||||
*
|
||||
******************************************************/
|
||||
public enum PaperType {
|
||||
Article,
|
||||
Paper,
|
||||
Book,
|
||||
BookChapter,
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file Research.java
|
||||
* @author Maxime Bartha
|
||||
* @scope Extension Publications scientifiques
|
||||
*
|
||||
* Research entity
|
||||
******************************************************/
|
||||
import jakarta.persistence.*;
|
||||
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 java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "Research")
|
||||
public class Research {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
@JoinColumn(name ="Researcher")
|
||||
private Researcher author;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Date releaseDate;
|
||||
|
||||
private PaperType paperType;
|
||||
|
||||
private String pdfLocation;
|
||||
|
||||
private String bibTexLocation;
|
||||
|
||||
private String language;
|
||||
|
||||
private Access access;
|
||||
|
||||
private String domain;
|
||||
|
||||
private String summary;
|
||||
|
||||
private int views;
|
||||
|
||||
@ManyToMany(cascade = {CascadeType.MERGE})
|
||||
@JoinTable(name = "ResearchCoAuhors",
|
||||
joinColumns = @JoinColumn(name = "research_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "researcher_id")
|
||||
)
|
||||
private Set<Researcher> coAuthors;
|
||||
|
||||
public Research(String title, Researcher author, Date releaseDate, PaperType paperType,
|
||||
String pdfLocation, String bibTexLocation, String language, Access access, String domain, String summary,Set<Researcher> coauthors){
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
this.releaseDate = releaseDate;
|
||||
this.paperType = paperType;
|
||||
this.pdfLocation = pdfLocation;
|
||||
this.bibTexLocation = bibTexLocation;
|
||||
this.language = language;
|
||||
this.access = access;
|
||||
this.domain = domain;
|
||||
this.summary = summary;
|
||||
this.coAuthors = coauthors;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
package ovh.herisson.Clyde.Tables.ScientificPublications;
|
||||
|
||||
/******************************************************
|
||||
* @file Researcher.java
|
||||
* @author Maxime Bartha
|
||||
* @scope Extension Publications scientifiques
|
||||
*
|
||||
* Researcher entity
|
||||
******************************************************/
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "Researcher")
|
||||
public class Researcher {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
@OneToOne
|
||||
private User user;
|
||||
private String orcidId;
|
||||
private String site;
|
||||
private String domain;
|
||||
|
||||
public Researcher(User user, String orcidId, String site, String domain){
|
||||
this.user = user;
|
||||
this.orcidId = orcidId;
|
||||
this.site = site;
|
||||
this.domain = domain;
|
||||
}
|
||||
}
|
@ -54,6 +54,7 @@ public class User {
|
||||
private List<Discussion> discussions;
|
||||
/////////////////////////////////
|
||||
|
||||
/////////////////////////////////
|
||||
public User(String lastName, String firstName, String email, String address,
|
||||
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",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@canvasjs/vue-charts": "^1.0.4",
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"vite-plugin-top-level-await": "^1.4.1",
|
||||
"vue": "^3.4.15",
|
||||
"vue3-toastify": "^0.2.1"
|
||||
@ -29,6 +31,20 @@
|
||||
"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": {
|
||||
"version": "0.19.12",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "5.0.4",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
|
||||
|
@ -9,6 +9,8 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@canvasjs/vue-charts": "^1.0.4",
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"vite-plugin-top-level-await": "^1.4.1",
|
||||
"vue": "^3.4.15",
|
||||
"vue3-toastify": "^0.2.1"
|
||||
|
@ -36,6 +36,9 @@ app.language=Language
|
||||
app.manage.profile=Manage profile
|
||||
app.studentList=Students List
|
||||
app.users=Users
|
||||
app.manage.researcherProfile=Manage researcher profile
|
||||
app.list.researches=List researches
|
||||
app.Create.User=Create User
|
||||
app.manageOwnLessons=Manage Owned Courses Schedule
|
||||
app.lessonRequests=Schedule Requests
|
||||
app.payments=Payments
|
||||
@ -121,6 +124,81 @@ Curriculum=curriculum
|
||||
Credits=Credits
|
||||
InscriptionService=I.S.
|
||||
faculty=Faculty
|
||||
Year=Year
|
||||
Access=Access
|
||||
Access.Restricted=Restricted
|
||||
Access.OpenSource=OpenSource
|
||||
Access.Private=Private
|
||||
Language=Language
|
||||
Month=Month
|
||||
Month.01=january
|
||||
Month.02=february
|
||||
Month.03=march
|
||||
Month.04=april
|
||||
Month.05=may
|
||||
Month.06=june
|
||||
Month.07=july
|
||||
Month.08=august
|
||||
Month.09=september
|
||||
Month.10=october
|
||||
Month.11=november
|
||||
Month.12=december
|
||||
Domain=Domain
|
||||
PaperType=PaperType
|
||||
Submit=Submit
|
||||
Search.Researches=Search For Researches
|
||||
Search.Researchers=Search For Researchers
|
||||
Filters=Filters
|
||||
Toggle.Researcher=Toggle Researcher Search
|
||||
Untoggle.Researcher=Toggle Research Search
|
||||
MoreInfo=More Info
|
||||
Modify.Research=Modify Research
|
||||
To.Change.In.Options=To change in regular account options
|
||||
Modify.Data=Modify Data
|
||||
Confirm.Changes=Confirm Changes
|
||||
Cancel.Changes=Cancel Changes
|
||||
Post.Research=Post a new Research
|
||||
Summary=Summary
|
||||
Title=Title
|
||||
Views=Number of Views
|
||||
See.Research=See Research
|
||||
SeeBibTex=See BibTex
|
||||
Author=Author
|
||||
CoAuthors=Co-Authors
|
||||
ReleaseDate=ReleaseDate
|
||||
Article.Id=Article Id
|
||||
Delete.Research=Delete Research
|
||||
Here=Here
|
||||
Stat.Type=Stat Type
|
||||
Researches=Researches
|
||||
Please.Select.Option=Please Select an Option
|
||||
Class.By=Class By
|
||||
PaperType.Article=Article
|
||||
PaperType.Book=Book
|
||||
PaperType.Book.Chapter=Book Chapter
|
||||
PaperType.Paper=Paper
|
||||
Research.Pdf=Research Pdf
|
||||
BibTex.Pdf=BibTex Pdf
|
||||
CoAuthors.List=Co-Author List
|
||||
Confirm.Publish=Confirm Publishing
|
||||
Cancel.Publish=Cancel Publishing
|
||||
Years=Years
|
||||
Months=Months
|
||||
By=By
|
||||
RegNo=RegNo
|
||||
Address=Address
|
||||
Country=Country
|
||||
BirthDate=Birth Date
|
||||
Researcher.Delete=Delete Researcher Profile
|
||||
Researcher.Add=Create Researcher Profile
|
||||
Confirm=Confirm
|
||||
Cancel=Cancel
|
||||
LastName=Last Name
|
||||
FirstName=First Name
|
||||
Profile.Picture=Profile Picture
|
||||
Role=Role
|
||||
Password=Password
|
||||
Create.User=Create User
|
||||
msg.notification.new=You have a new message
|
||||
forum.create=Create forum
|
||||
forum.create.name=New forum's name
|
||||
|
@ -36,6 +36,9 @@ app.language=Langue
|
||||
app.manage.profile=Gérer le profil
|
||||
app.studentList=Liste des étudiants
|
||||
app.users=Utilisateurs
|
||||
app.manage.researcherProfile= gérer son profil de chercheur
|
||||
app.list.researches=Lister les recherches
|
||||
app.Create.User=créer un utilisateur
|
||||
app.manageOwnLessons=Gérer ses horaires de cours
|
||||
app.lessonRequests=Requêtes d'horaire
|
||||
app.payments=Payements
|
||||
@ -121,6 +124,79 @@ Curriculum=Cursus
|
||||
Credits=Credits
|
||||
InscriptionService=S.I.
|
||||
faculty=Faculté
|
||||
Year=Année
|
||||
Access=Accès
|
||||
Access.Restricted=Restreint
|
||||
Access.OpenSource=Libre
|
||||
Access.Private=Privé
|
||||
Language=Langue
|
||||
Month=Mois
|
||||
Month.01=janvier
|
||||
Month.02=fevrier
|
||||
Month.03=mars
|
||||
Month.04=avril
|
||||
Month.05=mai
|
||||
Month.06=juin
|
||||
Month.07=juillet
|
||||
Month.08=août
|
||||
Month.09=septembre
|
||||
Month.10=octobre
|
||||
Month.11=novembre
|
||||
Month.12=decembre
|
||||
Domain=Domaine
|
||||
PaperType=Type de recherche
|
||||
Submit=Envoyer
|
||||
Search.Researches=Chercher Par Recherche
|
||||
Search.Researchers=Chercher Par Chercheur
|
||||
Filters=Filtres
|
||||
Toggle.Researcher=Activer la recherche par chercheur
|
||||
Untoggle.Researcher=Désactiver la recherche par chercheur
|
||||
MoreInfo=Plus d'info
|
||||
Modify.Research=Modifer l'article
|
||||
To.Change.In.Options=À changer dans les options
|
||||
Modify.Data=Modifier
|
||||
Confirm.Changes=Confirmer les Changements
|
||||
Cancel.Changes=Abandonner les Changements
|
||||
Post.Research=Poster un nouvel article
|
||||
Summary=Résumé
|
||||
Title=Titre
|
||||
Views=Nombre de Vues
|
||||
See.Research=Ouvrir l'article
|
||||
SeeBibTex=Ouvrir le BibTex
|
||||
Author=Autheur
|
||||
CoAuthors=Co-Autheurs
|
||||
ReleaseDate=Date de Parution
|
||||
Article.Id=Id de l'article
|
||||
Delete.Research=Supprimer l'article
|
||||
Here=Ici
|
||||
Stat.Type=Type de Stat
|
||||
Researches=Recherches
|
||||
Please.Select.Option=Selectionnez des Options
|
||||
Class.By=Classifer Par
|
||||
PaperType.Article=Article
|
||||
PaperType.Book=Livre
|
||||
PaperType.Book.Chapter=Chapitre de Livre
|
||||
PaperType.Paper=Papier
|
||||
Research.Pdf=Pdf de la Recherche
|
||||
BibTex.Pdf=BibTex de la Recherche
|
||||
CoAuthors.List=Liste des Co-Autheurs
|
||||
Confirm.Publish=Confirmer la Publication
|
||||
Cancel.Publish=Annuler la Publication
|
||||
Years=Années
|
||||
Months=Mois
|
||||
By=par
|
||||
RegNo=Matricule
|
||||
Address=Adresse
|
||||
Country=Pays
|
||||
BirthDate=Date de Naissance
|
||||
Confirm=Confirmer
|
||||
Cancel=Annuler
|
||||
LastName=Nom de Famille
|
||||
FirstName=Prénom
|
||||
Profile.Picture=Photo de Profil
|
||||
Role=Role
|
||||
Password=Mot de Passe
|
||||
Create.User=Créer l'utilisateur
|
||||
msg.notification.new=Vous avez un nouveau message!
|
||||
forum.create=Créer un forum
|
||||
forum.create.name=Nom du forum
|
||||
|
@ -169,7 +169,7 @@ window.addEventListener('hashchange', () => {
|
||||
border-color:black;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
overflow:;
|
||||
overflow: scroll;
|
||||
transition-duration: .3s;
|
||||
}
|
||||
|
||||
|
214
frontend/src/Apps/AboutUser.vue
Normal file
214
frontend/src/Apps/AboutUser.vue
Normal file
@ -0,0 +1,214 @@
|
||||
<script setup>
|
||||
import i18n from "../i18n.js";
|
||||
import {ref} from "vue";
|
||||
import {fetchAllResearchers} from "@/rest/ScientificPublications/ManageResearch.js";
|
||||
import {deleteResearcher, postResearcher} from "@/rest/ScientificPublications/ResearcherProfile.js";
|
||||
import {patchUser} from "@/rest/Users.js";
|
||||
const props = defineProps(['user'])
|
||||
const modifying =ref(false)
|
||||
const toModify = Object.assign({},{})
|
||||
const toCreate = Object.assign({},{})
|
||||
const allResearcher = ref( await fetchAllResearchers())
|
||||
const researcher = ref()
|
||||
const user = ref(props.user)
|
||||
const isResearcher = ref(false)
|
||||
const creating = ref(false)
|
||||
|
||||
for (let i = 0; i < allResearcher.value.length; i++) {
|
||||
if (user.value.regNo === allResearcher.value[i].user.regNo){
|
||||
researcher.value = allResearcher.value[i]
|
||||
isResearcher.value = true
|
||||
}
|
||||
}
|
||||
|
||||
function getPP(){
|
||||
if(user.value.profilePictureUrl === null){
|
||||
return "/Clyde.png"
|
||||
}
|
||||
return user.value.profilePictureUrl
|
||||
}
|
||||
|
||||
async function createResearcher(){
|
||||
toCreate.user = user.value
|
||||
await postResearcher(toCreate)
|
||||
creating.value = false
|
||||
for (let i = 0; i < allResearcher.value.length; i++) {
|
||||
if (user.value.regNo === allResearcher.value[i].user.regNo){
|
||||
researcher.value = allResearcher.value[i]
|
||||
isResearcher.value = true
|
||||
}
|
||||
}
|
||||
toCreate.value = Object.assign({},{})
|
||||
}
|
||||
|
||||
async function deleteResearcherById(){
|
||||
isResearcher.value = false
|
||||
await deleteResearcher(researcher.value.id)
|
||||
allResearcher.value = await fetchAllResearchers()
|
||||
}
|
||||
|
||||
async function modify(){
|
||||
if (modifying.value){
|
||||
user.value = await patchUser(user.value.regNo, toModify)
|
||||
}
|
||||
modifying.value =!modifying.value
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="body">
|
||||
<div class="container">
|
||||
<div class="profilPic">
|
||||
<img class="subContainer" :src=getPP()>
|
||||
</div>
|
||||
<div class = "globalInfos">
|
||||
<div class="infosContainer">
|
||||
<div>
|
||||
{{i18n("RegNo")}} : {{user.regNo}}
|
||||
</div>
|
||||
<div>
|
||||
{{i18n("name")}} : {{user.firstName}} {{user.lastName}}
|
||||
</div>
|
||||
<div>
|
||||
Role :
|
||||
<span v-if="!modifying"> {{i18n(user.role)}}</span>
|
||||
<select v-else v-model="toModify.role">
|
||||
<option value="Student">{{i18n("Student")}}</option>
|
||||
<option value="Teacher">{{i18n("Teacher")}}</option>
|
||||
<option value="Secretary">{{i18n("Secretary")}}</option>
|
||||
<option value="InscriptionService">{{i18n("InscriptionService")}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
E-mail: {{user.email}}
|
||||
</div>
|
||||
<div>
|
||||
{{i18n("Address")}} :
|
||||
<span v-if="!modifying"> {{user.address}}</span>
|
||||
<input v-else type="text" v-model="toModify.address">
|
||||
</div>
|
||||
<div>
|
||||
{{i18n("Country")}} : {{user.country}}
|
||||
</div>
|
||||
<div>
|
||||
{{i18n("BirthDate")}} : {{user.birthDate.split("T")[0]}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
<button id="ModifyButton" @click="modify"> {{i18n("Modify.Data")}}</button>
|
||||
<div></div>
|
||||
<div>
|
||||
<button v-if="isResearcher" id="deleteButton" @click="deleteResearcherById"> {{i18n("Researcher.Delete")}}</button>
|
||||
<button v-else id="createButton" @click="creating = !creating"> {{i18n("Researcher.Add")}}</button>
|
||||
</div>
|
||||
<div v-if="creating">
|
||||
<button id="createButton" @click="createResearcher"> {{i18n("Confirm")}}</button>
|
||||
<button id="deleteButton" @click="creating = !creating"> {{i18n("Cancel")}}</button>
|
||||
</div>
|
||||
<div v-if="creating" style="color: white">
|
||||
<ul>
|
||||
<li>
|
||||
Orcid :
|
||||
<input type="text" v-model="toCreate.orcid"></li>
|
||||
<li>
|
||||
Site :
|
||||
<input type="text" v-model="toCreate.site"></li>
|
||||
<li>
|
||||
{{i18n("Domain")}} :
|
||||
<input type="text" v-model="toCreate.domain"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
#ModifyButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: xx-large;
|
||||
background-color:rgba(191, 64, 191,0.5);
|
||||
border-radius: 20px;
|
||||
}
|
||||
#ModifyButton:hover{
|
||||
background:rgba(191,64,191)
|
||||
}
|
||||
|
||||
.container{
|
||||
margin-top: 25px;
|
||||
min-width:675px;
|
||||
display:grid;
|
||||
grid-template-columns:10vw 50vw;
|
||||
grid-template-rows:200px auto;
|
||||
column-gap:2.7%;
|
||||
row-gap:45px;
|
||||
grid-template-areas:
|
||||
"profilPic globalInfos"
|
||||
"minfos minfos";
|
||||
}
|
||||
|
||||
.profilPic{
|
||||
grid-area:profilPic;
|
||||
}
|
||||
|
||||
.globalInfos {
|
||||
grid-area:globalInfos;
|
||||
align-self :center;
|
||||
|
||||
}
|
||||
|
||||
.body {
|
||||
min-width:960px;
|
||||
width:100%;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
margin-top:5%;
|
||||
}
|
||||
|
||||
.subContainer{
|
||||
width:100%;
|
||||
background-color:rgb(50,50,50);
|
||||
border-radius:20px;
|
||||
border:4px solid black;
|
||||
}
|
||||
|
||||
.infosContainer {
|
||||
border:2px solid black;
|
||||
font-size:23px;
|
||||
color:white;
|
||||
background-color:rgb(50,50,50);
|
||||
border-radius:10px;
|
||||
}
|
||||
|
||||
#deleteButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color: red;
|
||||
border-radius: 20px;
|
||||
}
|
||||
#deleteButton:hover{
|
||||
background: #ff2d55;
|
||||
}
|
||||
#createButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color: #07bc0c;
|
||||
border-radius: 20px
|
||||
}
|
||||
#createButton:hover{
|
||||
background: #4cd964;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
117
frontend/src/Apps/CreateUser.vue
Normal file
117
frontend/src/Apps/CreateUser.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<script setup>
|
||||
|
||||
import i18n from "@/i18n.js";
|
||||
import {uploadProfilePicture} from "@/rest/uploads.js";
|
||||
import {postUser} from "@/rest/Users.js";
|
||||
import {ref} from "vue";
|
||||
let toCreate = Object.assign({},{})
|
||||
const today = new Date()
|
||||
const date = today.getFullYear() +"-" + ("0" + (today.getMonth()+1)).slice(-2) + "-" + ("0" + today.getDate()).slice(-2);
|
||||
|
||||
|
||||
async function createUser(){
|
||||
|
||||
if (toCreate.lastName === null || toCreate.birthDate === null || toCreate.firstName === null ||
|
||||
toCreate.email === null || toCreate.address === null || toCreate.role === null || toCreate.password === null)
|
||||
return
|
||||
|
||||
await postUser(toCreate)
|
||||
toCreate = Object.assign({},{})
|
||||
}
|
||||
|
||||
async function getProfilePic(data){
|
||||
const pp= await uploadProfilePicture(data)
|
||||
toCreate.profilePictureUrl = pp.url
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="body">
|
||||
<div class="container">
|
||||
<div class = "globalInfos">
|
||||
<div class="infosContainer">
|
||||
<ul>
|
||||
<li>{{i18n("LastName")}} : <input type="text" v-model="toCreate.lastName"></li>
|
||||
<li>{{i18n("FirstName")}} : <input type="text" v-model="toCreate.firstName"></li>
|
||||
<li> E-mail : <input type="text" v-model="toCreate.email"></li>
|
||||
<li>{{i18n("Country")}} : <input type="text" v-model="toCreate.country"></li>
|
||||
<li>{{i18n("Address")}} : <input type="text" v-model="toCreate.address"></li>
|
||||
<li>{{i18n("BirthDate")}} : <input type="date" min="1924-01-01" :max="date" v-model="toCreate.birthDate"></li>
|
||||
|
||||
<li>{{i18n("Profile.Picture")}} :
|
||||
<input type="file" @change="getProfilePic($event.target.files);" accept="image/*">
|
||||
</li>
|
||||
|
||||
|
||||
<li>{{i18n("Role")}} :
|
||||
<select v-model="toCreate.role">
|
||||
<option value="Student">{{i18n("Student")}}</option>
|
||||
<option value="Teacher">{{i18n("Teacher")}}</option>
|
||||
<option value="Secretary">{{i18n("Secretary")}}</option>
|
||||
<option value="InscriptionService">{{i18n("InscriptionService")}}</option>
|
||||
</select>
|
||||
</li>
|
||||
|
||||
<li>{{i18n("Password")}} : <input type="password" v-model="toCreate.password"></li>
|
||||
|
||||
</ul>
|
||||
<div style="text-align: end"> <button id="createButton" @click="createUser"> {{i18n("Create.User")}}</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.container{
|
||||
margin-top: 25px;
|
||||
min-width:675px;
|
||||
display:grid;
|
||||
grid-template-columns:10vw 50vw;
|
||||
grid-template-rows:200px auto;
|
||||
column-gap:2.7%;
|
||||
row-gap:45px;
|
||||
grid-template-areas:
|
||||
"profilPic globalInfos"
|
||||
"minfos minfos";
|
||||
}
|
||||
.globalInfos {
|
||||
grid-area:globalInfos;
|
||||
align-self :center;
|
||||
|
||||
}
|
||||
|
||||
.body {
|
||||
min-width:960px;
|
||||
width:100%;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
margin-top:5%;
|
||||
}
|
||||
|
||||
|
||||
.infosContainer {
|
||||
border:2px solid black;
|
||||
font-size:23px;
|
||||
color:white;
|
||||
background-color:rgb(50,50,50);
|
||||
border-radius:10px;
|
||||
}
|
||||
|
||||
#createButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color: #07bc0c;
|
||||
border-radius: 20px
|
||||
}
|
||||
#createButton:hover{
|
||||
background: #4cd964;
|
||||
}
|
||||
|
||||
</style>
|
153
frontend/src/Apps/ScientificPublications/FilterComponent.vue
Normal file
153
frontend/src/Apps/ScientificPublications/FilterComponent.vue
Normal file
@ -0,0 +1,153 @@
|
||||
<!----------------------------------------------------
|
||||
File: ResearchComponent.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'
|
||||
import i18n from "@/i18n.js";
|
||||
const yearList = ref([])
|
||||
const yearCheckedList = ref([])
|
||||
const monthList = ref([])
|
||||
const monthCheckedList = ref([])
|
||||
const accessList = ref([])
|
||||
const accessCheckedList = ref([])
|
||||
const languageList = ref([])
|
||||
const languageCheckedList = ref([])
|
||||
const domainList = ref([])
|
||||
const domainCheckedList = ref([])
|
||||
const paperTypeList = ref([])
|
||||
const paperTypCheckedList = ref([])
|
||||
|
||||
const filters = Object.assign({},{
|
||||
year:[],
|
||||
month:[],
|
||||
access:[],
|
||||
language:[],
|
||||
domain:[],
|
||||
paperType:[],
|
||||
})
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
isOpen: Boolean,
|
||||
allArticles: ref([Object])
|
||||
});
|
||||
|
||||
|
||||
function submit(){
|
||||
filters.paperType = paperTypCheckedList.value
|
||||
filters.year = yearCheckedList.value
|
||||
filters.month = monthCheckedList.value
|
||||
filters.access = accessCheckedList.value
|
||||
filters.language = languageCheckedList.value
|
||||
filters.domain = domainCheckedList.value
|
||||
emit("modal-close")
|
||||
emit("submit", filters)
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (let i=0;i< props.allArticles.length;i++) {
|
||||
let r = props.allArticles[i];
|
||||
let year = r.releaseDate.split("-")[0]
|
||||
let month = r.releaseDate.split("-")[1]
|
||||
|
||||
if (!yearList.value.includes(year) && year !== null) yearList.value.push(year);
|
||||
|
||||
if (!monthList.value.includes(month) && month !== null) monthList.value.push(month);
|
||||
|
||||
if (!accessList.value.includes(r.access) && r.access !== null ) accessList.value.push(r.access);
|
||||
|
||||
if (!languageList.value.includes(r.language) && r.language !== null) languageList.value.push(r.language);
|
||||
|
||||
if (!domainList.value.includes(r.domain) && r.domain !== null) domainList.value.push(r.domain);
|
||||
|
||||
if (!paperTypeList.value.includes(r.paperType) && r.paperType !== null) paperTypeList.value.push(r.paperType);
|
||||
}
|
||||
const emit = defineEmits(["modal-close", "submit"]);
|
||||
|
||||
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> {{i18n("Year")}} :<ul class="checkers"> <li v-for="n in yearList"> <input type="checkbox" :value=n v-model="yearCheckedList"> {{n}} </li> </ul> </div>
|
||||
<div class="vl"> {{i18n("Access")}}:<ul class="checkers"> <li v-for="n in accessList"> <input type="checkbox" :value=n v-model="accessCheckedList"> {{i18n("Access."+n)}} </li> </ul> </div>
|
||||
<div class="vl"> {{i18n("Language")}} :<ul class="checkers"> <li v-for="n in languageList"> <input type="checkbox" :value=n v-model="languageCheckedList"> {{n}} </li> </ul> </div>
|
||||
<div> {{i18n("Month")}} :<ul class="checkers"> <li v-for="n in monthList"> <input type="checkbox" :value=n v-model="monthCheckedList"> {{i18n("Month." + n)}} </li> </ul> </div>
|
||||
<div class="vl"> {{i18n("Domain")}} :<ul class="checkers"> <li v-for="n in domainList"> <input type="checkbox" :value=n v-model="domainCheckedList"> {{n}} </li> </ul> </div>
|
||||
<div class="vl"> {{i18n("PaperType")}} :<ul class="checkers"> <li v-for="n in paperTypeList"> <input type="checkbox" :value=n v-model="paperTypCheckedList"> {{n}} </li> </ul> </div>
|
||||
</div>
|
||||
<div id="submit">
|
||||
<button @click.stop="submit">{{i18n("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;
|
||||
}
|
||||
|
||||
#submit button {
|
||||
margin-left: 2px;
|
||||
font-size: large;
|
||||
color: white;
|
||||
background: rgba(191, 64, 191,0.5);
|
||||
border:2px solid black;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#submit button:hover{
|
||||
background: rgba(191, 64, 191);
|
||||
}
|
||||
|
||||
</style>
|
226
frontend/src/Apps/ScientificPublications/ListResearches.vue
Normal file
226
frontend/src/Apps/ScientificPublications/ListResearches.vue
Normal file
@ -0,0 +1,226 @@
|
||||
<!----------------------------------------------------
|
||||
File: ListResearches.vue
|
||||
Author: Maxime Bartha
|
||||
Scope: Extension Publicatons scientifiquess
|
||||
Description: Listing of the researches with filters
|
||||
----------------------------------------------------->
|
||||
<script setup>
|
||||
import {ref, watch} from "vue";
|
||||
import FilterComponent from "@/Apps/ScientificPublications/FilterComponent.vue";
|
||||
import ArticleComponent from "@/Apps/ScientificPublications/ResearchComponent.vue";
|
||||
import {fetchAllResearches} from "@/rest/ScientificPublications/ManageResearch.js";
|
||||
import i18n from "../../i18n.js";
|
||||
const input = ref("")
|
||||
const isFilterOpened = ref(false);
|
||||
const isResearchOpened = ref(false);
|
||||
const articleToDisplay = ref(Object)
|
||||
const isResearcher = ref(false)
|
||||
const filters = ref(null)
|
||||
const researchList = ref(await fetchAllResearches())
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
researchList:ref(),
|
||||
manage:Boolean,
|
||||
allResearcher:ref()
|
||||
});
|
||||
|
||||
if (typeof props.researchList !== 'undefined'){
|
||||
researchList.value = props.researchList
|
||||
}
|
||||
watch(
|
||||
() => props.researchList,
|
||||
(newValue) => {
|
||||
researchList.value = newValue
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const openFilter = () => {
|
||||
isFilterOpened.value = true;
|
||||
};
|
||||
const closeFilter = () => {
|
||||
isFilterOpened.value = false;
|
||||
};
|
||||
const submitFilters = (receivedFilters)=>{
|
||||
filters.value = receivedFilters
|
||||
}
|
||||
|
||||
|
||||
const openResearch = (article) => {
|
||||
isResearchOpened.value = true;
|
||||
articleToDisplay.value = article;
|
||||
}
|
||||
|
||||
const closeResearch = () => {
|
||||
isResearchOpened.value =false;
|
||||
articleToDisplay.value = null;
|
||||
}
|
||||
|
||||
|
||||
function searchInList(list, searchInput) {
|
||||
let retList = []
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let researcher = list[i].researcher.user.firstName + " " +list[i].researcher.user.lastName
|
||||
if (isResearcher.value && (lDistance(researcher, searchInput) < 5 || researcher.toUpperCase().indexOf(searchInput.toUpperCase()) > -1)){
|
||||
retList.push(list[i])
|
||||
}
|
||||
if (!isResearcher.value && (lDistance(list[i].title, searchInput) < 10 || list[i].title.toUpperCase().indexOf(searchInput.toUpperCase()) > -1)){
|
||||
|
||||
if (filters.value === null) {
|
||||
retList.push(list[i])
|
||||
continue;
|
||||
}
|
||||
if ( (filters.value.access.length === 0 || filters.value.access.includes(list[i].access))
|
||||
&& ( filters.value.domain.length === 0|| filters.value.domain.includes(list[i].domain))
|
||||
&& ( filters.value.paperType.length === 0 || filters.value.paperType.includes(list[i].paperType))
|
||||
&& ( filters.value.year.length === 0|| filters.value.year.includes(list[i].releaseDate.split("-")[0]))
|
||||
&& ( filters.value.month.length === 0|| filters.value.month.includes(list[i].releaseDate.split("-")[1]))
|
||||
&& ( filters.value.language.length === 0|| filters.value.language.includes(list[i].language)))
|
||||
{
|
||||
retList.push(list[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
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 emit = defineEmits(["modified"]);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="researches">
|
||||
<FilterComponent :isOpen="isFilterOpened" :allArticles="researchList" @modal-close="closeFilter" @submit="submitFilters"></FilterComponent>
|
||||
<ArticleComponent :allResearcher="allResearcher" :article="articleToDisplay" :isOpen="isResearchOpened" :manage="props.manage" @modal-close="closeResearch" @modified="emit('modified')"></ArticleComponent>
|
||||
<div id="search">
|
||||
<input v-if="!isResearcher" type="text" id="search-input" :placeholder="i18n('Search.Researches')" v-model="input"/>
|
||||
<input v-else type="text" id="search-input" :placeholder="i18n('Search.Researchers')" v-model="input"/>
|
||||
<button v-if="!isResearcher" id="filterButton" @click="openFilter"> {{i18n("Filters")}} </button>
|
||||
<button v-if="!isResearcher" id="unToggledResearchButton" @click="isResearcher = !isResearcher"> {{i18n("Toggle.Researcher")}}</button>
|
||||
<button v-if="isResearcher" id="toggledResearchButton" @click="isResearcher = !isResearcher"> {{i18n("Untoggle.Researcher")}}</button>
|
||||
</div>
|
||||
<div id="researches">
|
||||
<ul id="researchUL">
|
||||
<li id="researchLi" v-for="n in searchInList(researchList,input)">
|
||||
<div class="vl"> {{n.title}}</div>
|
||||
<div class="vl"> <a :href="'#/researcher-profile?id=' + n.researcher.id"> {{ n.researcher.user.firstName +" "+ n.researcher.user.lastName }}</a>
|
||||
</div>
|
||||
<a v-if="!manage" @click="openResearch(n)"> {{i18n("MoreInfo")}}</a>
|
||||
<a v-else @click="openResearch(n)"> {{i18n("Modify.Research")}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
#researches{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
#researchUL {
|
||||
list-style-type: none;
|
||||
color: white;
|
||||
padding: 12px;
|
||||
margin: 5px;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
#researchLi{
|
||||
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;
|
||||
}
|
||||
|
||||
#unToggledResearchButton{
|
||||
align-self: center;
|
||||
margin-left: 2px;
|
||||
font-size:16px ;
|
||||
color: white;
|
||||
background: #2a1981;
|
||||
border:2px solid black;
|
||||
}
|
||||
|
||||
#unToggledResearchButton:hover{
|
||||
background: #5ac8fa;
|
||||
|
||||
}
|
||||
|
||||
#toggledResearchButton {
|
||||
align-self: center;
|
||||
margin-left: 2px;
|
||||
font-size: large;
|
||||
color: white;
|
||||
background: crimson;
|
||||
border:2px solid black;
|
||||
}
|
||||
#toggledResearchButton:hover{
|
||||
background: #ff2d55;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,184 @@
|
||||
<!----------------------------------------------------
|
||||
File: ManageResearchesProfile.vue
|
||||
Author: Maxime Bartha
|
||||
Scope: Extension Publicatons scientifiquess
|
||||
Description: Managing Researcher Profile page
|
||||
----------------------------------------------------->
|
||||
<script setup>
|
||||
import { ref} from "vue";
|
||||
import {fetchResearches, } from "@/rest/ScientificPublications/ResearcherProfile.js";
|
||||
import {getSelf, patchProfile} from "@/rest/ScientificPublications/ManageResearcherProfile.js";
|
||||
import ResearchPostComponent from "@/Apps/ScientificPublications/ResearchPostComponent.vue";
|
||||
import ListResearches from "@/Apps/ScientificPublications/ListResearches.vue";
|
||||
import i18n from "../../i18n.js";
|
||||
import {fetchAllResearchers} from "@/rest/ScientificPublications/ManageResearch.js";
|
||||
const input = ref("");
|
||||
const isPostResearchOpened = ref(false);
|
||||
const changing = ref(false);
|
||||
|
||||
let toModify= Object.assign({}, {});
|
||||
|
||||
const researcher = ref(await getSelf());
|
||||
const researchList = ref(await fetchResearches(researcher.value.id));
|
||||
const allResearcher = ref(await fetchAllResearchers())
|
||||
function openPostResearch(){
|
||||
isPostResearchOpened.value = true
|
||||
}
|
||||
function cancelChanges(){
|
||||
changing.value = false
|
||||
toModify= Object.assign({}, {});
|
||||
}
|
||||
async function confirmChanges(){
|
||||
await patchProfile(researcher.value.id, toModify)
|
||||
changing.value = false
|
||||
toModify= Object.assign({}, {});
|
||||
researcher.value = await getSelf();
|
||||
}
|
||||
|
||||
async function modifiedResearch(){
|
||||
researchList.value = await fetchResearches(researcher.value.id)
|
||||
}
|
||||
|
||||
function getPP(){
|
||||
if(researcher.value.user.profilePictureUrl === null){
|
||||
return "/Clyde.png"
|
||||
}
|
||||
return researcher.value.user.profilePictureUrl
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template> <div class="body"><div id="main">
|
||||
<ResearchPostComponent :allResearcher="allResearcher" :researcher="researcher" :isOpen="isPostResearchOpened" @modal-close="isPostResearchOpened = false" @posted="modifiedResearch"></ResearchPostComponent>
|
||||
<div id="profilePicture">
|
||||
<img :src=getPP() />
|
||||
</div>
|
||||
<div id="researcherInfos">
|
||||
<div class="surrounded" v-if="!changing">{{researcher.user.lastName}} {{researcher.user.firstName}}</div>
|
||||
<div class="surrounded" v-else> {{i18n("To.Change.In.Options")}}</div>
|
||||
|
||||
<div class="surrounded" v-if="!changing">Orcid : {{researcher.orcidId}}</div>
|
||||
<div class="surrounded" v-else>Orcid : <input v-model="toModify.orcidId"> </div>
|
||||
|
||||
<div class="surrounded" v-if="!changing">Email : {{researcher.user.email}}</div>
|
||||
<div class="surrounded" v-else> {{i18n("To.Change.In.Options")}}</div>
|
||||
|
||||
<div class="surrounded" v-if="!changing">
|
||||
Site : <a :href=researcher.site style="color: #007aff"> {{researcher.site}}</a>
|
||||
</div>
|
||||
<div class="surrounded" v-else>Site : <input v-model="toModify.site"></div>
|
||||
|
||||
<div class="surrounded" v-if="!changing">{{i18n("Domain")}} : {{researcher.domain}}</div>
|
||||
<div class="surrounded" v-else>Domain : <input v-model="toModify.domain"></div>
|
||||
|
||||
<div style="text-align: center; align-self: center" v-if="!changing"> <button class="modifyButton" @click="changing = !changing">{{i18n("Modify.Data")}}</button></div>
|
||||
<div v-else style="text-align: center; align-self: center">
|
||||
<button id="confirmButton" @click="confirmChanges"> {{i18n("Confirm.Changes")}}</button>
|
||||
<button id="cancelButton" @click="cancelChanges"> {{i18n("Cancel.Changes")}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="postArticle" style="text-align: center">
|
||||
<button class="modifyButton" @click="openPostResearch">{{i18n("Post.Research")}}</button>
|
||||
|
||||
|
||||
</div>
|
||||
<div> <ListResearches :allResearcher="allResearcher" :research-list="researchList" :manage="true" @modified="modifiedResearch"></ListResearches> </div>
|
||||
</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;
|
||||
}
|
||||
|
||||
.modifyButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: xx-large;
|
||||
background-color:rgba(191, 64, 191,0.5);
|
||||
border-radius: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.modifyButton:hover{
|
||||
background:rgba(191,64,191)
|
||||
}
|
||||
|
||||
#cancelButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color: red;
|
||||
border-radius: 20px;
|
||||
}
|
||||
#cancelButton:hover{
|
||||
background: #ff2d55;
|
||||
}
|
||||
|
||||
#confirmButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color: #07bc0c;
|
||||
border-radius: 20px;
|
||||
}
|
||||
#confirmButton:hover{
|
||||
background: #4cd964;
|
||||
}
|
||||
|
||||
a{
|
||||
color:#007aff;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
242
frontend/src/Apps/ScientificPublications/ResearchComponent.vue
Normal file
242
frontend/src/Apps/ScientificPublications/ResearchComponent.vue
Normal file
@ -0,0 +1,242 @@
|
||||
<!----------------------------------------------------
|
||||
File: ResearchComponent.vue
|
||||
Author: Maxime Bartha
|
||||
Scope: Extension Publicatons scientifiquess
|
||||
Description: Pop Up summarizing a research infos
|
||||
----------------------------------------------------->
|
||||
|
||||
<script setup xmlns="http://www.w3.org/1999/html">
|
||||
import {ref, watch} from "vue";
|
||||
import {onClickOutside} from '@vueuse/core'
|
||||
import {
|
||||
patchArticle,
|
||||
deleteArticle,
|
||||
addView,
|
||||
} from "@/rest/ScientificPublications/ManageResearch.js";
|
||||
import i18n from "../../i18n.js";
|
||||
const coAuthors = ref()
|
||||
const restURL = import.meta.env.VITE_CLYDE_MODE === 'container' ? "http://localhost:8000": import.meta.env.DEV ? "http://localhost:5173" : "https://clyde.herisson.ovh/api"
|
||||
const props = defineProps({
|
||||
isOpen: Boolean,
|
||||
article: ref(Object),
|
||||
manage:Boolean,
|
||||
allResearcher: ref()
|
||||
});
|
||||
|
||||
|
||||
watch(
|
||||
() => props.article,
|
||||
(newValue) => {
|
||||
if (newValue !== null)
|
||||
coAuthors.value = newValue.coAuthors
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
function format(date){
|
||||
let split = date.split("-")
|
||||
let month = split[1]
|
||||
let day = split[2].split("T")[0]
|
||||
let year = split[0]
|
||||
return day +"/"+ month +"/"+ year
|
||||
}
|
||||
|
||||
const emit = defineEmits(["modal-close","modified"]);
|
||||
|
||||
const target = ref(null)
|
||||
onClickOutside(target, ()=>{emit('modal-close'); })
|
||||
|
||||
let toModify= Object.assign({}, {});
|
||||
|
||||
function cancelChanges(){
|
||||
toModify= Object.assign({}, {});
|
||||
emit('modal-close')
|
||||
}
|
||||
|
||||
async function confirmChanges(){
|
||||
let coAuthorsId =[]
|
||||
coAuthors.value.forEach(n => (coAuthorsId.push(n.id)))
|
||||
toModify.coAuthors = coAuthorsId
|
||||
await patchArticle(props.article.id, toModify)
|
||||
toModify= Object.assign({}, {});
|
||||
emit('modal-close')
|
||||
emit("modified")
|
||||
}
|
||||
|
||||
async function deleteThisArticle(){
|
||||
await deleteArticle(props.article.id)
|
||||
emit('modal-close')
|
||||
emit("modified")
|
||||
}
|
||||
function downloadPdf(){
|
||||
return (restURL + "/" + props.article.pdfLocation)
|
||||
}
|
||||
|
||||
function downloadBibTex(){
|
||||
return (restURL + "/" + props.article.bibTexLocation)
|
||||
}
|
||||
|
||||
async function articleClicked(){
|
||||
await addView(props.article.pdfLocation)
|
||||
emit('modal-close')
|
||||
emit('modified')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="isOpen" class="modal-mask">
|
||||
<div class="modal-wrapper">
|
||||
<div class="modal-container" ref="target">
|
||||
<div><ul>
|
||||
<li>{{i18n("Article.Id")}} : {{article.id}}</li>
|
||||
<li>{{i18n("Title")}} : {{article.title}}</li>
|
||||
<li>{{i18n("Author")}} : {{article.researcher.user.lastName + " " + article.researcher.user.firstName}}</li>
|
||||
<li>{{i18n("CoAuthors")}} : <ul id="coAuthors" v-for="n in article.coAuthors"> <li id="coAuthorsLi"> {{n.user.firstName}} {{n.user.lastName}}, </li></ul></li>
|
||||
<li>{{i18n("Summary")}} : {{article.summary}}</li>
|
||||
<li>{{i18n("ReleaseDate")}} : {{format(article.releaseDate)}}</li>
|
||||
<li>{{i18n("Language")}} : {{article.language}}</li>
|
||||
<li>{{i18n("PaperType")}} : {{article.paperType}}</li>
|
||||
<li>{{i18n("Domain")}} : {{article.domain}}</li>
|
||||
<li>{{i18n("Views")}} : {{article.views}}</li>
|
||||
<li>{{i18n("Access")}} : {{i18n(article.access)}}</li>
|
||||
</ul>
|
||||
<div id="downloads" v-if="article.pdfLocation !== null && !manage">
|
||||
<a :href=downloadPdf() @click.stop="articleClicked" target="_blank">{{i18n("See.Research")}}</a>
|
||||
<a v-if="article.bibTexLocation !== null" :href=downloadBibTex() @click.stop="emit('modal-close')" target="_blank">{{i18n("See.BibTex")}}</a> </div>
|
||||
</div>
|
||||
<div v-if="manage" id="manage">
|
||||
<div>
|
||||
<ul>
|
||||
<li>{{i18n("Title")}} : <input v-model="toModify.title"></li>
|
||||
<li>{{i18n("Language")}} : <input v-model="toModify.language"></li>
|
||||
<li>{{i18n("Summary")}} : <input v-model="toModify.summary"></li>
|
||||
<li>{{i18n("Domain")}} : <input v-model="toModify.domain"></li>
|
||||
<li>{{i18n("Access")}} :
|
||||
<select id="classed-select" v-model="toModify.access">
|
||||
<option value="OpenSource">{{i18n("Access.OpenSource")}}</option>
|
||||
<option value="Restricted">{{i18n("Access.Restricted")}}</option>
|
||||
<option value="Private">{{i18n("Access.Private")}}</option>
|
||||
</select></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div> {{i18n("CoAuthors.List")}} :
|
||||
<ul id="coAuthorListUl" style="list-style-type: none;" v-for="n in props.allResearcher">
|
||||
<li v-if="n.id !== props.article.researcher.id"> <input type="checkbox" :value=n v-model="coAuthors"> {{n.id}} : {{n.user.firstName}} {{n.user.lastName}}</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<button id="confirmButton" @click="confirmChanges"> {{i18n("Confirm.Changes")}}</button>
|
||||
<button id="cancelButton" @click="cancelChanges">{{i18n("Cancel.Changes")}}</button>
|
||||
</div>
|
||||
<div style="text-align: end">
|
||||
<button id="deleteButton" @click="deleteThisArticle">{{i18n("Delete.Research")}} </button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 120%;
|
||||
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);
|
||||
}
|
||||
|
||||
.modal-container ul{
|
||||
margin-top: 9px;
|
||||
}
|
||||
#manage{
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
}
|
||||
|
||||
#coAuthors{
|
||||
list-style: none;
|
||||
display: inline;
|
||||
padding: 0;
|
||||
}
|
||||
#coAuthorsLi{
|
||||
display: inline;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
#downloads {
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
#coAuthorListUl{
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#downloads a {
|
||||
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;
|
||||
text-underline-mode: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
#downloads button:hover{
|
||||
background: rgba(191, 64, 191);
|
||||
}
|
||||
|
||||
#deleteButton{
|
||||
align-self: end;
|
||||
text-align: end;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
border-radius: 20px;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
#deleteButton:hover{
|
||||
background: #ff2d55;
|
||||
}
|
||||
|
||||
#cancelButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color:rgba(191, 64, 191,0.5);
|
||||
border-radius: 20px;
|
||||
}
|
||||
#cancelButton:hover{
|
||||
background:rgba(191,64,191)
|
||||
}
|
||||
|
||||
#confirmButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color: #07bc0c;
|
||||
border-radius: 20px;
|
||||
}
|
||||
#confirmButton:hover{
|
||||
background: #4cd964;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,177 @@
|
||||
<!----------------------------------------------------
|
||||
File: ResearchPostComponent.vue
|
||||
Author: Maxime Bartha
|
||||
Scope: Extension Publicatons scientifiquess
|
||||
Description: pop up for posting a research
|
||||
----------------------------------------------------->
|
||||
<script setup>
|
||||
|
||||
import { ref } from "vue";
|
||||
import {onClickOutside} from '@vueuse/core'
|
||||
import {uploadFile, postResearch} from "@/rest/ScientificPublications/ManageResearch.js";
|
||||
import i18n from "../../i18n.js";
|
||||
const coAuthors = ref([])
|
||||
|
||||
let toPost = Object.assign({}, {coAuthors:[]});
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
isOpen: Boolean,
|
||||
researcher: ref(Object),
|
||||
allResearcher:ref()
|
||||
});
|
||||
|
||||
|
||||
async function uploadResearchPdf(pdf){
|
||||
const data = await uploadFile(pdf);
|
||||
toPost.pdfLocation = data.url;
|
||||
}
|
||||
async function uploadBibTex(pdf){
|
||||
const data = await uploadFile(pdf);
|
||||
toPost.bibTexLocation = data.url;
|
||||
}
|
||||
|
||||
|
||||
async function postNewResearch(){
|
||||
toPost.releaseDate = new Date()
|
||||
toPost.author = props.researcher
|
||||
toPost.coAuthors = coAuthors.value
|
||||
//the Pdf and a title are required
|
||||
if (toPost.pdfLocation == null || toPost.title == null || toPost.title === "") {
|
||||
emit("modal-close")
|
||||
return;
|
||||
}
|
||||
await postResearch(toPost)
|
||||
toPost = Object.assign({}, {});
|
||||
coAuthors.value = []
|
||||
emit("modal-close")
|
||||
emit("posted")
|
||||
}
|
||||
|
||||
function cancelPost(){
|
||||
emit("modal-close")
|
||||
toPost = Object.assign({}, {});
|
||||
}
|
||||
const emit = defineEmits(["modal-close","posted"]);
|
||||
|
||||
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 ><ul>
|
||||
|
||||
<li>{{i18n("Title")}} : <input v-model="toPost.title"></li>
|
||||
<li>{{i18n("Summary")}} : <input v-model="toPost.summary"></li>
|
||||
<li>{{i18n("Language")}} : <input v-model="toPost.language"></li>
|
||||
<li>{{i18n("Domain")}} : <input v-model="toPost.domain"></li>
|
||||
<li>{{i18n("PaperType")}} : <select id="classed-select" v-model="toPost.paperType">
|
||||
<option value="Article">{{i18n("PaperType.Article")}}</option>
|
||||
<option value="Book">{{i18n("PaperType.Book")}}</option>
|
||||
<option value="BookChapter">{{i18n("PaperType.Book.Chapter")}}</option>
|
||||
<option value="Paper">{{i18n("PaperType.Paper")}}Paper</option>
|
||||
</select></li>
|
||||
<li>{{i18n("Access")}} : <select id="classed-select" v-model="toPost.access">
|
||||
<option value="OpenSource">{{i18n("Access.OpenSource")}}</option>
|
||||
<option value="Restricted">{{i18n("Access.Restricted")}}</option>
|
||||
<option value="Private">{{i18n("Access.Private")}}</option>
|
||||
</select></li>
|
||||
|
||||
|
||||
<li> {{i18n("Research.Pdf")}} :
|
||||
<form novalidate enctype="multipart/form-data" class="inputBox">
|
||||
<input type="file" @change="uploadResearchPdf($event.target.files);" accept="application/pdf">
|
||||
</form></li>
|
||||
<li> {{i18n("BibTex.Pdf")}}
|
||||
<form novalidate enctype="multipart/form-data" class="inputBox">
|
||||
<input type="file" @change="uploadBibTex($event.target.files);" accept=".bib">
|
||||
</form></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="CoAuthorList"> {{i18n("CoAuthors.List")}} :
|
||||
<ul style="list-style-type: none;" v-for="n in props.allResearcher">
|
||||
<li v-if="n.id !== props.researcher.id"> <input type="checkbox" :value=n v-model="coAuthors"> {{n.id}} : {{n.user.firstName}} {{n.user.lastName}}</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div></div>
|
||||
<div>
|
||||
<button id="confirmButton" @click="postNewResearch">{{i18n("Confirm.Publish")}}</button>
|
||||
<button id="cancelButton" @click="cancelPost">{{i18n("Cancel.Publish")}}</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 {
|
||||
display: grid;
|
||||
grid-template-columns: 40% 60%;
|
||||
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);
|
||||
}
|
||||
|
||||
.modal-container ul{
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
#downloads button:hover{
|
||||
background: rgba(191, 64, 191);
|
||||
}
|
||||
|
||||
|
||||
#cancelButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color:rgba(191, 64, 191,0.5);
|
||||
border-radius: 20px;
|
||||
}
|
||||
#cancelButton:hover{
|
||||
background:rgba(191,64,191)
|
||||
}
|
||||
|
||||
#confirmButton{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
font-size: x-large;
|
||||
background-color: #07bc0c;
|
||||
border-radius: 20px;
|
||||
}
|
||||
#confirmButton:hover{
|
||||
background: #4cd964;
|
||||
}
|
||||
</style>
|
171
frontend/src/Apps/ScientificPublications/ResearcherProfile.vue
Normal file
171
frontend/src/Apps/ScientificPublications/ResearcherProfile.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<!----------------------------------------------------
|
||||
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 {fetchResearcher, fetchResearches, fetchStats} from "@/rest/ScientificPublications/ResearcherProfile.js";
|
||||
import ListResearches from "@/Apps/ScientificPublications/ListResearches.vue";
|
||||
import i18n from "../../i18n.js";
|
||||
const input = ref("");
|
||||
const statsOf = ref("");
|
||||
const statsBy = ref("");
|
||||
let chart;
|
||||
|
||||
const researcherId = window.location.href.split("=")[1]
|
||||
|
||||
|
||||
function getPP(){
|
||||
if(researcher.value.user.profilePictureUrl === null){
|
||||
return "/Clyde.png"
|
||||
}
|
||||
return researcher.value.user.profilePictureUrl
|
||||
}
|
||||
const researchList = ref(await fetchResearches(researcherId));
|
||||
const researcher = ref(await fetchResearcher(researcherId));
|
||||
const stats = ref(await fetchStats(researcherId))
|
||||
|
||||
function downloadCoAuthors(){
|
||||
let coAuthors = []
|
||||
for (let i in researchList.value) {
|
||||
for (const j in researchList.value[i].coAuthors){
|
||||
const coAuthor = researchList.value[i].coAuthors[j]
|
||||
coAuthors.push(coAuthor)
|
||||
}
|
||||
}
|
||||
const data = JSON.stringify(coAuthors);
|
||||
const blob = new Blob([data], {type:"application/json"});
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
const options = reactive({
|
||||
backgroundColor:null,
|
||||
theme: "light2",
|
||||
animationEnabled: true,
|
||||
title: {
|
||||
fontColor: "white",
|
||||
text : i18n("Please.Select.Option"),
|
||||
},
|
||||
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,
|
||||
}
|
||||
let index = (statsOf.value === "views"?0:(statsOf.value === "researches"?3:6)) + (statsBy.value ==="years"?0:(statsBy.value==="months"?1:2))
|
||||
|
||||
if (statsOf.value !== "" && statsBy.value !== "")
|
||||
options.data[0].dataPoints = stats.value[index]
|
||||
|
||||
|
||||
options.title.text = i18n(statsOf.value) +" "+ i18n("By") +" " + i18n(statsBy.value);
|
||||
chart.render();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="main">
|
||||
<div id="profilePicture">
|
||||
<img :src=getPP() />
|
||||
</div>
|
||||
<div id="researcherInfos">
|
||||
<div class="surrounded">{{researcher.user.lastName}} {{researcher.user.firstName}}</div>
|
||||
<div class="surrounded">Orcid : {{researcher.orcidId}}</div>
|
||||
<div class="surrounded">Email : {{researcher.user.email}}</div>
|
||||
<div class="surrounded">
|
||||
Site : <a :href=researcher.site style="color: #007aff"> {{researcher.site}}</a>
|
||||
</div>
|
||||
<div class="surrounded">{{i18n("Domain")}} : {{researcher.domain}}</div>
|
||||
<div id="coAuthorList" class="surrounded">Co-authors list : <a :href=downloadCoAuthors() download="coAuthors.json">{{i18n("Here")}}</a></div>
|
||||
</div>
|
||||
<div id="stats">
|
||||
<div class="surrounded">
|
||||
{{i18n("Stat.Type")}} :
|
||||
<select @change="update()" id="stats-select" v-model="statsOf">
|
||||
<option value="Views">{{i18n("Views")}}</option>
|
||||
<option value="Researches">{{i18n("Researches")}}</option>
|
||||
<option value="Languages">{{i18n("Language")}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="surrounded">
|
||||
{{i18n("Class.By")}} :
|
||||
<select @change="update()" id="classed-select" v-model="statsBy">
|
||||
<option value="Years">{{i18n("Years")}}</option>
|
||||
<option value="Months">{{i18n("Months")}}</option>
|
||||
<option value="Topics">{{i18n("Domain")}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="statsPie">
|
||||
<CanvasJSChart :options="options" id=chart @chart-ref="c => chart = c "/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="researches"><list-researches :researchList="researchList"></list-researches></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;
|
||||
}
|
||||
|
||||
a{
|
||||
color:#007aff;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@ -1,20 +1,30 @@
|
||||
|
||||
<script setup>
|
||||
import i18n from "@/i18n.js"
|
||||
import { reactive } from 'vue'
|
||||
import { getAllUsers } from '../rest/Users.js'
|
||||
import {ref} from "vue";
|
||||
import AboutUser from "@/Apps/AboutUser.vue";
|
||||
const list = ref(true)
|
||||
const targetRegNo =ref()
|
||||
|
||||
|
||||
const users = await getAllUsers();
|
||||
|
||||
</script>
|
||||
<template style="margin-top:5%;">
|
||||
<div style="display:flex; justify-content:center; min-width:1140px;" v-for="item in users">
|
||||
<div class="bodu">
|
||||
<div v-if="list === false">
|
||||
<AboutUser :user=target />
|
||||
<button style="background-color:rgb(105,05,105);width:5%; margin-left: 10%;" @click="list = true;">Back</button>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:center; min-width:1140px;" v-for="item in users" v-if="list">
|
||||
<div class="body">
|
||||
<div class="container">
|
||||
<div class="role"><a style="margin-left:30px">{{i18n(item.role)}}</a></div>
|
||||
<div class="surname"><a>{{item.lastName}}</a></div>
|
||||
<div class="firstname"><a>{{item.firstName}}</a></div>
|
||||
<div class="infos"><button style="background-color:rgb(105,05,105);" >{{i18n("request.moreInfos")}} </button></div>
|
||||
<div class="infos">
|
||||
<button style="background-color:rgb(105,05,105);" @click="list = false; target = item;">{{i18n("request.moreInfos")}} </button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -70,7 +80,7 @@
|
||||
|
||||
}
|
||||
|
||||
.bodu {
|
||||
.body {
|
||||
margin-top:2%;
|
||||
width:66%;
|
||||
border:2px solid black;
|
||||
|
@ -4,5 +4,8 @@ import 'https://kit.fontawesome.com/fb3bbd0a95.js'
|
||||
|
||||
import { createApp } from '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');
|
||||
|
32
frontend/src/rest/ScientificPublications/ManageResearch.js
Normal file
32
frontend/src/rest/ScientificPublications/ManageResearch.js
Normal file
@ -0,0 +1,32 @@
|
||||
import {restGet, restPost, restDelete, restPatch, restPostFile} from '../restConsumer.js'
|
||||
|
||||
export async function deleteArticle(id){
|
||||
await restDelete("/research/" + id)
|
||||
}
|
||||
export async function patchArticle(id, data){
|
||||
await restPatch("/research/" + id, data)
|
||||
}
|
||||
export async function uploadFile(file){
|
||||
const formData = new FormData();
|
||||
formData.append("file", file[0]);
|
||||
|
||||
return restPostFile("/upload/Research", formData);
|
||||
}
|
||||
export async function postResearch(data){
|
||||
return restPost("/research", data)
|
||||
}
|
||||
|
||||
export async function fetchAllResearches(){
|
||||
return restGet("/researches")
|
||||
}
|
||||
|
||||
export async function getFile(url){
|
||||
const restURL = import.meta.env.VITE_CLYDE_MODE === 'container' ? "http://localhost:8000": import.meta.env.DEV ? "http://localhost:5173" : "https://clyde.herisson.ovh/api"
|
||||
return await fetch(restURL + "/" + url, {method: "GET"})
|
||||
}
|
||||
export async function addView(url){
|
||||
return restPost("/addview/" + url)
|
||||
}
|
||||
export async function fetchAllResearchers(){
|
||||
return await restGet("/researchers")
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { restGet, restPost, restDelete, restPatch } from '../restConsumer.js'
|
||||
|
||||
export async function getSelf(){
|
||||
return restGet("/researcher")
|
||||
}
|
||||
|
||||
export async function patchProfile(id, data){
|
||||
return restPatch("/researcher/" + id, data)
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { restGet, restPost, restDelete, restPatch } from '../restConsumer.js'
|
||||
|
||||
export async function fetchResearcher(id){
|
||||
return restGet("/researcher/" + id)
|
||||
}
|
||||
|
||||
export async function fetchResearches(id){
|
||||
return restGet("/researches/" + id)
|
||||
}
|
||||
|
||||
export async function fetchStats(id){
|
||||
return restGet("/stats/" +id)
|
||||
}
|
||||
|
||||
export async function fetchResearch(id){
|
||||
return restGet("/research/" +id)
|
||||
}
|
||||
|
||||
export async function deleteResearcher(id){
|
||||
return restDelete("/researcher/" + id)
|
||||
}
|
||||
|
||||
export async function postResearcher(data){
|
||||
return restPost("/researcher", data)
|
||||
}
|
@ -13,6 +13,10 @@ export function disconnect(){
|
||||
setCookie("session_token", ";expires= Thu, 01 Jan 1970 00:00:01 GMT")
|
||||
}
|
||||
|
||||
export async function patchUser(id,data){
|
||||
return restPatch("/user/" +id, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a user (tokenless)
|
||||
*
|
||||
@ -44,31 +48,8 @@ export async function register(firstname, lastname, birthDate, password, email,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a user (by secretary)
|
||||
*
|
||||
* @param firstname
|
||||
* @param lastname
|
||||
* @param birthdate
|
||||
* @param password
|
||||
* @param mail
|
||||
* @param address
|
||||
* @param country
|
||||
* @param imageId id of the image in database returned when uploaded
|
||||
*
|
||||
* PS: the password is not required as it is generated by the backend and sent to the user
|
||||
* by mail. it's up to the user to change it if he cares about security
|
||||
*/
|
||||
export async function createUser(firstname, lastname, birthDate, email, address, country, role, imageId){
|
||||
return restPost("/user", {
|
||||
firstname: firstname,
|
||||
lastname: lastname,
|
||||
birthDate: birthDate,
|
||||
password: password,
|
||||
email: email,
|
||||
address: address,
|
||||
country: country,
|
||||
});
|
||||
export async function postUser(data){
|
||||
return restPost("/user", data)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,10 @@ import Msg from "@/Apps/Msg.vue"
|
||||
import Forums from '@/Apps/Forums.vue'
|
||||
import Payments from "@/Apps/Inscription/PaymentInfo.vue";
|
||||
import ManageRequests from "@/Apps/Inscription/ManageRequests.vue";
|
||||
import ManageResearcherProfile from "@/Apps/ScientificPublications/ManageResearcherProfile.vue";
|
||||
import ListResearches from "@/Apps/ScientificPublications/ListResearches.vue";
|
||||
import ResearcherProfile from "@/Apps/ScientificPublications/ResearcherProfile.vue";
|
||||
import CreateUser from "@/Apps/CreateUser.vue";
|
||||
|
||||
const apps = {
|
||||
'/schedule': Schedule,
|
||||
@ -26,6 +30,10 @@ const apps = {
|
||||
'/manage-courses' : Courses,
|
||||
'/users-list' : Users,
|
||||
'/students-list' : Students,
|
||||
'/manage-researcher-profile' : ManageResearcherProfile,
|
||||
'/researches' : ListResearches,
|
||||
'/researcher-profile': ResearcherProfile,
|
||||
'/create-user': CreateUser,
|
||||
'/manage-owned-lessons': ManageOwnedLessons,
|
||||
'/manage-schedule-requests' : LessonRequests,
|
||||
'/msg' : Msg,
|
||||
@ -34,6 +42,7 @@ const apps = {
|
||||
}
|
||||
|
||||
const appsList = {
|
||||
'ListResearches': {path:'#/researches', icon:'fa-book-bookmark',text:i18n("app.list.researches")},
|
||||
'Msg': { path: '#/msg', icon: 'fa-comment', text: i18n("app.messages") },
|
||||
'Notification': { path: '#/notifs', icon: 'fa-bell', text: i18n("app.notifications") },
|
||||
'Forum': { path: '#/forums', icon: 'fa-envelope', text: i18n("app.forum") },
|
||||
@ -42,6 +51,8 @@ const appsList = {
|
||||
'ManageCourses': { path: '#/manage-courses', icon: 'fa-book', text: i18n("app.manage.courses") },
|
||||
'StudentsList':{ path: '#/students-list',icon: 'fa-users',text: i18n("app.studentList")},
|
||||
'UsersList':{ path: '#/users-list',icon: 'fa-users',text: i18n("app.users")},
|
||||
'ManageResearcherProfile':{path:'#/manage-researcher-profile',icon:'fa-book-bookmark',text:i18n("app.manage.researcherProfile")},
|
||||
'CreateUser':{path:'#/create-user',icon:'fa-plus', text:i18n("app.Create.User")},
|
||||
'ManageOwnedLessons':{path: '#/manage-owned-lessons',icon:'fa-calendar-days',text: i18n("app.manageOwnLessons")},
|
||||
'LessonRequests':{path: '#/manage-schedule-requests', icon:'fa-book', text: i18n("app.lessonRequests")},
|
||||
'Requests': { path: '#/requests', icon: 'fa-users', text: "Requests" },
|
||||
@ -51,7 +62,7 @@ const appsList = {
|
||||
const currentPath = ref(window.location.hash)
|
||||
|
||||
export const currentView = computed(() => {
|
||||
return apps[currentPath.value.slice(1) || '/']
|
||||
return apps[currentPath.value.split("?")[0].slice(1) || '/']
|
||||
})
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user