1
0
forked from PGL/Clyde

Merge pull request 'master' (#173) from Maxime/Clyde:master into master

Reviewed-on: PGL/Clyde#173
This commit is contained in:
Maxime 2024-04-22 00:06:59 +02:00
commit b382bf957f
41 changed files with 2870 additions and 112 deletions

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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);}

View File

@ -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");
@ -129,6 +136,7 @@ public class MockController {
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));
CurriculumCourseService.save(new CurriculumCourse(infoBab1, psycho1));
@ -136,13 +144,43 @@ 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);
///////////////////////////
// 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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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")

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -45,15 +45,18 @@ 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 (!target.getRegNo().equals(poster.getRegNo()) && !(poster.getRole() == Role.Secretary) &&
!(poster.getRole() == Role.Admin))
return null;
if (poster.getRegNo().equals(target.getRegNo())){
for (Map.Entry<String, Object> entry : updates.entrySet()){
System.out.println(entry.getValue());
switch (entry.getKey()){
case "firstName":
target.setFirstName((String) entry.getValue());
@ -79,27 +82,18 @@ public class UserService {
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);
}
}
}
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;
}
}
}
return false;
return target;
}

View File

@ -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,
// profile of a researcher
ResearcherProfile,
ManageResearcherProfile,
//the list of all researches (filterable)
ListResearches,
CreateUser,
StudentsList,
Payments
}

View File

@ -3,6 +3,8 @@ package ovh.herisson.Clyde.Tables;
public enum FileType {
ProfilePicture,
EducationCertificate,
Research,
ResearchBibTex,
JustificationDocument,
IdentityCard,
}

View File

@ -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
}

View File

@ -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,
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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",

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -169,7 +169,7 @@ window.addEventListener('hashchange', () => {
border-color:black;
height: 100%;
position: fixed;
overflow:;
overflow: scroll;
transition-duration: .3s;
}

View 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>

View 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>

View 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>

View 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>

View File

@ -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>

View 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>

View File

@ -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>

View 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>

View File

@ -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;

View File

@ -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');

View 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")
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}
/**

View File

@ -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) || '/']
})
/**