diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index f105250..6557b82 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -41,3 +41,4 @@ tasks.register("run") { tasks.withType { useJUnitPlatform() } + diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java index 5b1306c..e254b8c 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java @@ -1,10 +1,7 @@ package ovh.herisson.Clyde.EndPoints; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import ovh.herisson.Clyde.Repositories.TokenRepository; import ovh.herisson.Clyde.Repositories.UserRepository; import ovh.herisson.Clyde.Services.*; @@ -12,11 +9,10 @@ import ovh.herisson.Clyde.Tables.*; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Date; @RestController -@CrossOrigin(origins = "http://localhost:5173") +@CrossOrigin(originPatterns = "*", allowCredentials = "true") public class MockController { private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); @@ -24,11 +20,8 @@ public class MockController { public final UserRepository userRepo; public final TokenRepository tokenRepo; public final TokenService tokenService; - public final CursusCourseService cursusCourseService; - public final CursusService cursusService; - public final CourseService courseService; ArrayList mockUsers; @@ -58,7 +51,6 @@ public class MockController { User joe = new User("Mama","Joe","student@student.com","roundabout","DaWarudo",new Date(0), null,Role.Student,passwordEncoder.encode("student")); User meh = new User("Inspiration","lackOf","secretary@secretary.com","a Box","the street",new Date(0), null,Role.Teacher,passwordEncoder.encode("secretary")); User joke = new User("CthemBalls","Lemme","teacher@teacher.com","lab","faculty",new Date(0), null,Role.Teacher,passwordEncoder.encode("teacher")); - mockUsers = new ArrayList(Arrays.asList(herobrine,joe,meh,joke)); userRepo.saveAll(mockUsers); @@ -108,3 +100,4 @@ public class MockController { userRepo.deleteAll(mockUsers); } } + diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/PingController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/PingController.java index f0f26d3..b1148bf 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/PingController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/PingController.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RestController; import ovh.herisson.Clyde.Responses.PingResponse; @RestController -@CrossOrigin(origins = "http://localhost:5173") +@CrossOrigin(originPatterns = "*", allowCredentials = "true") public class PingController { @GetMapping("/ping") diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/StorageController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/StorageController.java index 2a36657..724ae10 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/StorageController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/StorageController.java @@ -1,16 +1,15 @@ package ovh.herisson.Clyde.EndPoints; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import ovh.herisson.Clyde.Services.StorageService; -import org.springframework.core.io.Resource; import ovh.herisson.Clyde.Tables.FileType; +import ovh.herisson.Clyde.Tables.StorageFile; @RestController -@CrossOrigin(origins = "http://localhost:5173") +@CrossOrigin(originPatterns = "*", allowCredentials = "true") public class StorageController { private final StorageService storageServ; @@ -21,12 +20,17 @@ public class StorageController { @PostMapping("/upload/{fileType}") - public ResponseEntity handleFileUpload(@RequestParam("file") MultipartFile file, @PathVariable FileType fileType) { + public ResponseEntity handleFileUpload(@RequestParam("file") MultipartFile file, @PathVariable FileType fileType) { - String path = storageServ.store(file,fileType); + StorageFile fileEntry = null; + try { + fileEntry = storageServ.store(file,fileType); + + } catch(Exception e){ + e.printStackTrace(); + } - if (path == null) return new ResponseEntity<>("issue with the file storage", HttpStatus.BAD_REQUEST); - return new ResponseEntity<>(path, HttpStatus.OK); + return new ResponseEntity<>(fileEntry, HttpStatus.OK); } } diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/TokenController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/TokenController.java index 793e61b..ba07fca 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/TokenController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/TokenController.java @@ -9,7 +9,7 @@ import ovh.herisson.Clyde.Services.TokenService; import ovh.herisson.Clyde.Tables.Token; @RestController -@CrossOrigin(origins = "http://localhost:5173") +@CrossOrigin(originPatterns = "*", allowCredentials = "true") public class TokenController { private final TokenService tokenServ; diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/UserController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/UserController.java index 996905a..d936b47 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/UserController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/UserController.java @@ -2,17 +2,20 @@ package ovh.herisson.Clyde.EndPoints; import org.springframework.http.HttpStatus; - import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import ovh.herisson.Clyde.Responses.UnauthorizedResponse; import ovh.herisson.Clyde.Services.AuthenticatorService; import ovh.herisson.Clyde.Services.UserService; +import ovh.herisson.Clyde.Tables.Role; import ovh.herisson.Clyde.Tables.User; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; @RestController -@CrossOrigin(origins = "http://localhost:5173") +@CrossOrigin(originPatterns = "*", allowCredentials = "true") public class UserController { private final UserService userService; @@ -23,23 +26,78 @@ public class UserController { } @GetMapping("/user") - public ResponseEntity getUser(@RequestHeader("Cookie") String authorization){ + public ResponseEntity> getUser(@RequestHeader("Authorization") String authorization){ if (authorization == null) return new UnauthorizedResponse<>(null); User user = authServ.getUserFromToken(authorization); if (user == null) return new UnauthorizedResponse<>(null); - return new ResponseEntity<>(user, HttpStatus.OK); + + return new ResponseEntity<>(userWithoutPassword(user), HttpStatus.OK); } - @PostMapping("/user") //todo check role - public ResponseEntity postUser(@RequestBody User user){ + @PostMapping("/user") + public ResponseEntity postUser(@RequestBody User user,@RequestHeader("Authorization") String authorization){ + + if (!isSecretaryOrAdmin(authorization)) + return new UnauthorizedResponse<>(null); + userService.save(user); return new ResponseEntity<>(String.format("Account created with ID:%s",user.getRegNo()),HttpStatus.CREATED); } @GetMapping("/users") - public Iterable getAllUsers(){ - return userService.getAll(); + public ResponseEntity>> getAllUsers(@RequestHeader("Authorization") String authorization){ + + if (!isSecretaryOrAdmin(authorization)) + return new UnauthorizedResponse<>(null); + + Iterable users = userService.getAll(); + ArrayList> withoutPassword = new ArrayList<>(); + + for (User u :users){ + withoutPassword.add(userWithoutPassword(u)); + } + return new ResponseEntity<>(withoutPassword, HttpStatus.OK); + } + @PatchMapping("/user") + public ResponseEntity patchUser(@RequestBody Map updates, @RequestHeader("Authorization") String authorization) { + + if (authorization == null) return new UnauthorizedResponse<>(null); + + User poster = authServ.getUserFromToken(authorization); + if (poster == null) {return new UnauthorizedResponse<>("bad authorization");} + + if (!userService.modifyData(poster, updates, poster)) + return new UnauthorizedResponse<>("there was an issue with the updates requested"); + + return new ResponseEntity<>("data modified", HttpStatus.OK); + } + /** return user's data except password + * @param user the user to return + * @return all the user data without the password + */ + private HashMap userWithoutPassword(User user){ + HashMap toReturn = new HashMap<>(); + + toReturn.put("regNo",user.getRegNo()); + toReturn.put("firstName",user.getFirstName()); + toReturn.put("lastName",user.getLastName()); + toReturn.put("birthDate",user.getBirthDate()); + toReturn.put("country",user.getCountry()); + toReturn.put("address",user.getAddress()); + toReturn.put("role",user.getRole()); + + return toReturn; + } + + private boolean isSecretaryOrAdmin(String authorization){ + if (authorization ==null) + return false; + + User poster = authServ.getUserFromToken(authorization); + if (poster == null) return false; + + return poster.getRole() == Role.Secretary && poster.getRole() == Role.Admin; } } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Services/StorageService.java b/backend/src/main/java/ovh/herisson/Clyde/Services/StorageService.java index 77dff70..c7f8d1b 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Services/StorageService.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Services/StorageService.java @@ -1,13 +1,13 @@ package ovh.herisson.Clyde.Services; -import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import ovh.herisson.Clyde.Repositories.FileRepository; -import ovh.herisson.Clyde.Tables.FileType; -import ovh.herisson.Clyde.Tables.StorageFile; +import ovh.herisson.Clyde.Tables.*; + +import java.io.File; import java.io.IOException; -import org.springframework.core.io.Resource; + import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -24,10 +24,18 @@ public class StorageService { public StorageService(FileRepository filerepo){ this.fileRepo = filerepo; + + if(!Files.exists(rootLocation)){ + try { + Files.createDirectories(rootLocation); + } catch(IOException e){ + e.printStackTrace(); + } + } } - public String store(MultipartFile file, FileType fileType) { + public StorageFile store(MultipartFile file, FileType fileType) { if (file.getOriginalFilename().isEmpty()){return null;} @@ -49,8 +57,14 @@ public class StorageService { String url = this.rootLocation.resolve(Paths.get(Objects.requireNonNull(stringUuid))) .normalize().toString(); - fileRepo.save(new StorageFile(file.getName(),url, fileType)); + return fileRepo.save(new StorageFile(file.getName(),url, fileType)); + } - return url; + public void delete(StorageFile file) throws SecurityException { + File f = new File(file.getUrl()); + f.delete(); + + //Delete l'entité + fileRepo.delete(file); } } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java b/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java index f16c68f..55a2f92 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java @@ -5,16 +5,10 @@ import org.springframework.stereotype.Service; import ovh.herisson.Clyde.Repositories.UserRepository; import ovh.herisson.Clyde.Tables.Role; import ovh.herisson.Clyde.Tables.User; - -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; +import java.util.*; @Service public class UserService { - private final UserRepository userRepo; private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); @@ -34,17 +28,79 @@ public class UserService { } } + /** modify the target data + * verify the permission of modifying from the poster + * + * @param poster the user wanting to modify target's data + * @param updates the changes to be made + * @param target the user to update + * @return if the changes were done or not + */ + public boolean modifyData(User poster, Map updates, User target){ + + if (poster.getRegNo().equals(target.getRegNo())){ + for (Map.Entry entry : updates.entrySet()){ + + if ( entry.getKey().equals("regNo") || entry.getKey().equals("role")) {return false;} + + switch (entry.getKey()){ + case "firstName": + target.setFirstName((String) entry.getValue()); + break; + case "lastName": + target.setLastName((String) entry.getValue()); + break; + case "email": + target.setEmail((String) entry.getValue()); + break; + case "address": + target.setAddress((String) entry.getValue()); + break; + case "country": + target.setCountry((String) entry.getValue()); + break; + case "birthDate": + target.setBirthDate((Date) entry.getValue()); + break; + case "profilePictureUrl": + target.setProfilePictureUrl((String) entry.getValue()); + break; + case "password": + target.setPassword(passwordEncoder.encode((String) entry.getValue())); + break; + } + } + userRepo.save(target); + return true; + } + // the secretary can change roles (for example if a student becomes a teacher) + else if (poster.getRole() == Role.Secretary) + { + for (Map.Entry entry : updates.entrySet()){ + + if ( !entry.getKey().equals("role")) {return false;} + + if (entry.getValue() == Role.Admin){return false;} + + target.setRole((Role) entry.getValue()); + userRepo.save(target); + return true; + } + } + return false; + } + public boolean checkPassword(User user, String tryingPassword){ return passwordEncoder.matches(tryingPassword, user.getPassword()); } public void save(User user){ + user.setPassword(passwordEncoder.encode(user.getPassword())); userRepo.save(user); } public Iterable getAll(){ return userRepo.findAll(); } - } \ No newline at end of file diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/ReinscriptionRequest.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/ReinscriptionRequest.java index 9369c80..69c80e6 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/ReinscriptionRequest.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/ReinscriptionRequest.java @@ -19,7 +19,7 @@ public class ReinscriptionRequest { //Permet de différencier les demandes de changement et une réinscription dans le même cursus //Pour la réinscription on va le mettre a 0 - private boolean type; + private boolean type = false; public ReinscriptionRequest(){} @@ -30,6 +30,12 @@ public class ReinscriptionRequest { this.type = type; } + public ReinscriptionRequest(User user, Cursus newCursus, RequestState state){ + this.user = user; + this.newCursus = newCursus; + this.state = state; + } + public int getId() { return id; } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/StorageFile.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/StorageFile.java index a96d0ec..afa7985 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/StorageFile.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/StorageFile.java @@ -1,9 +1,6 @@ package ovh.herisson.Clyde.Tables; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; @Entity @@ -19,7 +16,6 @@ public class StorageFile { private FileType fileType; - public StorageFile(String name, String url, FileType fileType){ this.name = name; this.url = url; @@ -60,4 +56,5 @@ public class StorageFile { public void setFileType(FileType fileType) { this.fileType = fileType; } + } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java index 55c5be2..1f6aa3b 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java @@ -8,12 +8,11 @@ import java.util.Date; //et l'attribut tokenApi doit encore être ajouté vu qu'il faut en discuter @Entity -//Je rajoute un s au nom de la table pour éviter les conflits avec les mots réservés @Table(name = "Users") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) - private int regNo; + private Long regNo; private String lastName; private String firstName; @Column(unique = true) @@ -38,9 +37,34 @@ public class User { this.password = password; } + + /** Constructor for the first registration request from a student (can't specify a Role) + * + * @param lastName + * @param firstName + * @param email + * @param address + * @param country + * @param birthDate + * @param profilePictureUrl + * @param password + */ + public User(String lastName, String firstName, String email, String address, + String country, Date birthDate, String profilePictureUrl, String password) + { + this.lastName = lastName; + this.firstName = firstName; + this.email = email; + this.address = address; + this.country = country; + this.birthDate = birthDate; + this.profilePictureUrl = profilePictureUrl; + this.password = password; + this.role = Role.Student; + } public User() {} - public int getRegNo(){ + public Long getRegNo(){ return this.regNo; } public String getLastName() { diff --git a/frontend/public/i18n/EN.txt b/frontend/public/i18n/EN.txt index bc4eb40..90a001d 100644 --- a/frontend/public/i18n/EN.txt +++ b/frontend/public/i18n/EN.txt @@ -1,11 +1,9 @@ -# English translations (some examples to remove) - login.guest.signin=Sign in login.guest.register=Register login.guest.alregister=Already Registered login.guest.welcome=WELCOME TO THE UNIVERSITY login.guest.email=E-MAIL -login.guest.firstname= FIRSTNAME +login.guest.firstname=FIRSTNAME login.guest.surname=SURNAME login.guest.country=COUNTRY login.guest.address=ADDRESS @@ -15,6 +13,8 @@ login.guest.lastpage=Last Page login.guest.submit=Submit login.guest.birthday=BIRTHDAY login.guest.confirm=CONFIRM +login.cPassword=Confirm Password +login.password=Password app.home=Home app.login=Login app.notifications=Notifications @@ -23,8 +23,28 @@ app.messages=Messages app.forum=Forum app.schedules=Schedules app.inscription.requests=Inscription Requests +app.manage.courses=Manage Courses +app.language=Language +app.manage.profile=Manage profile request.moreInfos=More Infos request.accept=Accept request.refuse=Refuse -#===================================================== - +courses.createCourse=Create course +courses.deleteCourse=Delete course +courses.modify=Modify +courses.toDelete=Course to Delete +courses.confirm=Confirm +courses.back=Back +profile.modify.data=Modify personnal data +profile.reRegister=Re-register +profile.unRegister=Unregister +profile.course.list=Courses list +profile.address=Address +profile.picture=Profile picture +name=Name +teacher=Teacher +student=Student +secretary=Secretary +curriculum=curriculum +credits=Credits +faculty=Faculty diff --git a/frontend/public/i18n/FR.txt b/frontend/public/i18n/FR.txt index 42ab8bf..c2f7689 100644 --- a/frontend/public/i18n/FR.txt +++ b/frontend/public/i18n/FR.txt @@ -1,20 +1,20 @@ -# Traductions françaises (Quelques examples a enlever) - login.guest.signin=SE CONNECTER login.guest.register=S'enregistrer login.guest.alregister=Déjà Enregistré login.guest.welcome=BIENVENUE A L'UNIVERSITE login.guest.email=E-MAIL -login.guest.firstname= PRENOM -login.guest.surname= NOM -login.guest.country= PAYS +login.guest.firstname=PRENOM +login.guest.surname=NOM +login.guest.country=PAYS login.guest.address=ADRESSE -login.guest.password= MOT DE PASSE +login.guest.password=MOT DE PASSE login.guest.nextpage=Prochaine Page login.guest.lastpage=Derniere Page login.guest.submit=Envoyer login.guest.birthday=DATE DE NAISSANCE login.guest.confirm=CONFIRMER +login.cPassword=Confirmer mot de passe +login.password=Mot de passe app.home=Home app.login=Se connecter app.notifications=Notifications @@ -23,7 +23,28 @@ app.messages=Messages app.forum=Forum app.schedules=Horaires app.inscription.requests=Demandes d'Inscription +app.manage.courses=Gérer les cours +app.language=Langue +app.manage.profile=Gérer le profil request.moreInfos=Plus d'Infos request.accept=Accepter request.refuse=Refuser -#===================================================== +courses.createCourse=Créer un cours +courses.deleteCourse=Supprimer un cours +courses.modify=Modifier +courses.toDelete=Cours à supprimer +courses.confirm=Confirmer +courses.back=Retour +profile.modify.data=Modifier données personnelles +profile.reRegister=Réinsciption +profile.unRegister=Désinscription +profile.course.list=Liste des cours +profile.address=Adresse +profile.picture=Photo de profil +name=Nom +teacher=Enseignant +student=Etudiant +secretary=Secrétaire +curriculum=Cursus +credits=Credits +faculty=Faculté diff --git a/frontend/src/App.vue b/frontend/src/App.vue index ef68173..7b944de 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -8,11 +8,13 @@ import LoginPage from './Apps/Login.vue' import Inscription from "./Apps/Inscription.vue" import Profil from "./Apps/Profil.vue" + import Courses from "./Apps/ManageCourses.vue" const apps = { '/login': LoginPage, '/inscription': Inscription, - '/profil': Profil + '/profil': Profil, + '/manage-courses' : Courses, } const currentPath = ref(window.location.hash) @@ -39,7 +41,7 @@ @@ -246,7 +252,6 @@ } .text { - position: absolute; right: 0%; width: 0%; opacity: 0; @@ -258,9 +263,13 @@ ul.vertical:hover .text { opacity: 1; - width: 70%; + width: 60%; transition-duration: .3s; - padding-left: 5px; + padding-left: 15px; + } + + .clyde:hover{ + content: url("./assets/angry_clyde.png") } diff --git a/frontend/src/Apps/Inscription.vue b/frontend/src/Apps/Inscription.vue index 0ba7fce..511a403 100644 --- a/frontend/src/Apps/Inscription.vue +++ b/frontend/src/Apps/Inscription.vue @@ -1,32 +1,10 @@ diff --git a/frontend/src/Apps/Login.vue b/frontend/src/Apps/Login.vue index 786c786..a5043e8 100644 --- a/frontend/src/Apps/Login.vue +++ b/frontend/src/Apps/Login.vue @@ -1,28 +1,25 @@ @@ -30,17 +27,17 @@
-
+

{{i18n("login.guest.signin")}}

ID / {{i18n("login.guest.email")}}

- +

{{i18n("login.guest.password")}}

- +
- +

{{i18n("login.guest.welcome")}}

@@ -71,11 +68,12 @@

{{i18n("login.guest.password")}}

- +

{{i18n("login.guest.confirm")}} {{i18n("login.guest.password")}}

+
@@ -89,7 +87,7 @@

{{i18n("login.guest.email")}}

- +

{{i18n("login.guest.address")}}

@@ -99,8 +97,12 @@

{{i18n("login.guest.country")}}

+ +

ProfilePicture

+ +
-

CURSUS

+

{{i18n("curriculum").toUpperCase()}}