package com.mif13.authServer.controllers; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.mif13.authServer.dao.UsersDao; import com.mif13.authServer.exception.InvalidPasswordException; import com.mif13.authServer.exception.InvalidUsernameException; import com.mif13.authServer.exception.UserCreationException; import com.mif13.authServer.model.User; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import java.util.Optional; import java.util.regex.PatternSyntaxException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ResponseStatusException; import org.springframework.web.servlet.ModelAndView; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @RestController @RequestMapping(value = "users") public class UserRestController { private final UsersDao usersRepo; @Autowired public UserRestController(UsersDao usersRepo) { this.usersRepo = usersRepo; } @Operation(summary = "Get user informations by id") @ApiResponses(value = { @ApiResponse( responseCode = "200", description = "Found the user", content = { @Content( mediaType = "application/json", schema = @Schema(implementation = User.class) ), @Content( mediaType = "application/xml", schema = @Schema(implementation = User.class) ), @Content( mediaType = "text/html" ) }), @ApiResponse( responseCode = "404", description = "User not found", content = { @Content() } )} ) @GetMapping(value = "/{id}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}) //@CrossOrigin(origins = {"http://localhost", "http://192.168.75.68", "https://192.168.75.68"}) public ResponseEntity<User> getUserAsJsonOrXml(@PathVariable String id) { Optional<User> optionalUser = usersRepo.get(id); if (optionalUser.isPresent()) { User user = optionalUser.get(); return new ResponseEntity<>(user, HttpStatus.OK); } else { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"); } } @GetMapping(value = "/{id}", produces = MediaType.TEXT_HTML_VALUE) public ModelAndView getUserAsHtml(@PathVariable String id, Model model) { // "user" nom du template HTML (sans extension) ModelAndView modelAndView = new ModelAndView("user"); Optional<User> optionalUser = usersRepo.get(id); if (optionalUser.isPresent()) { User user = optionalUser.get(); // on initialise les variables du template model.addAttribute("user", user); modelAndView.setStatus(HttpStatus.OK); } else { model.addAttribute("id", id); modelAndView.setStatus(HttpStatus.NOT_FOUND); } return modelAndView; } private ResponseEntity<Void> createUserResponse(String login, String password) { try { User user = new User(login, password); try { HttpStatus statusCode; Optional<User> optionalUser = usersRepo.get(user.getLogin()); if (optionalUser.isEmpty()) { usersRepo.save(user); statusCode = HttpStatus.CREATED; } else { statusCode = HttpStatus.FORBIDDEN; } return new ResponseEntity<>(statusCode); } catch (PatternSyntaxException e) { // Si les patterns RegEx de validation sont pas valides e.printStackTrace(); throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR); } } catch (UserCreationException e) { e.printStackTrace(); String errMsg; if (e instanceof InvalidUsernameException) { errMsg = "Login does not match the requirements"; } else if (e instanceof InvalidPasswordException) { errMsg = "Password does not match the requirements"; } else { errMsg = "Failed to create a user"; } // Par defaut, pour des raisons de securite, // le message d'erreur n'est pas affiche a l'utilisateur throw new ResponseStatusException(HttpStatus.BAD_REQUEST, errMsg, e); } } @Operation(summary = "Create a new user") @ApiResponses(value = { @ApiResponse( responseCode = "201 Created", description = "User is correctely created", content = { @Content( mediaType = "application/json", schema = @Schema(implementation = User.class) ), @Content( mediaType = "application/xml", schema = @Schema(implementation = User.class) ), @Content( mediaType = "text/html" ) }), @ApiResponse( responseCode = "403 Forbidden", description = "User not created", content = { @Content() } ), @ApiResponse( responseCode = "500 Internal Server Error", description = "", content = { @Content() } ) }) @PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public ResponseEntity<Void> createUserFromUrlEncoded(@RequestParam("login") String login, @RequestParam("password") String password) { return createUserResponse(login, password); } /** * Cree un User a partir d'un JSON. * * @param json JSON contenant un login et un password * @return contenu vide **/ @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Void> createUserFromJson(@RequestBody String json) { try { ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonTree = objectMapper.readTree(json); String login = jsonTree.get("login").asText(); String password = jsonTree.get("password").asText(); return createUserResponse(login, password); } catch (JsonProcessingException e) { e.printStackTrace(); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to process JSON", e); } } @Operation(summary = "Modify password of a user by its id") @ApiResponses(value = { @ApiResponse( responseCode = "204 No Content", description = "Password is correctly modified", content = { @Content() } ), @ApiResponse( responseCode = "404 Not Found", description = "", content = { @Content() } ), @ApiResponse( responseCode = "500 Internal Server Error", description = "", content = { @Content() } ) }) @PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public ResponseEntity<Void> modifyUserPasswordFromUrlEncoded(@PathVariable String id, @RequestParam("newPassword") String newPassword) { return modifyUserPassword(id, newPassword); } @PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Void> modifyUserPasswordFromJson(@PathVariable String id, @RequestBody String json) { try { ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonTree = objectMapper.readTree(json); String newPassword = jsonTree.get("newPassword").asText(); return modifyUserPassword(id, newPassword); } catch (JsonProcessingException e) { e.printStackTrace(); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to process JSON", e); } } private ResponseEntity<Void> modifyUserPassword(String id, String newPassword) { Optional<User> optionalUser = usersRepo.get(id); if (optionalUser.isPresent()) { User user = optionalUser.get(); try { if (User.verifyPassword(newPassword)) { user.setPassword(newPassword); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } else { throw new InvalidPasswordException("Password does not match the requirements"); } } catch (InvalidPasswordException e) { e.printStackTrace(); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e); } } else { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"); } } @Operation(summary = "Delete a user on the database, by its id") @ApiResponses(value = { @ApiResponse( responseCode = "204 No Content", description = "User deleted with success", content = { @Content() } ), @ApiResponse( responseCode = "404 Not Found", description = "", content = { @Content() } ), @ApiResponse( responseCode = "500 Internal Server Error", description = "", content = { @Content() } ) }) @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable String id) { Optional<User> optionalUser = usersRepo.get(id); if (optionalUser.isPresent()) { User user = optionalUser.get(); usersRepo.delete(user); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } else { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"); } } }