From 48fbc434a42c5e65c7dfc8bde555034ea658d95d Mon Sep 17 00:00:00 2001 From: Mysaa Java Date: Wed, 15 Jul 2026 03:37:49 +0200 Subject: [PATCH] Code refactors --- README.md | 7 +- .../bernard/misael/auth/AuthController.java | 29 +- .../misael/auth/service/UserServiceImpl.java | 17 +- .../bernard/misael/quizz/APIException.java | 23 + .../misael/quizz/QuestionsController.java | 160 +++---- .../misael/quizz/service/QuizzManager.java | 12 +- .../quizz/service/QuizzManagerImpl.java | 436 ++++++++---------- .../bernard/misael/thecrew/TheCrewConfig.java | 3 +- .../misael/thecrew/TheCrewController.java | 3 +- src/main/resources/templates/form.html | 2 +- src/main/resources/templates/quizz-edit.html | 3 +- src/main/resources/templates/watchquizz.html | 5 +- 12 files changed, 363 insertions(+), 337 deletions(-) create mode 100644 src/main/java/com/bernard/misael/quizz/APIException.java diff --git a/README.md b/README.md index 7431859..49282ee 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,9 @@ spring: provider: bcom: issuer-uri: "https://auth.example.com/realms/bcom" -``` \ No newline at end of file +``` + + +## API +All API requests must be done with POST requests. They will always output a json object, with a boolean +filed `success`. If `success` is false, a field `message` can give more information on the error. \ No newline at end of file diff --git a/src/main/java/com/bernard/misael/auth/AuthController.java b/src/main/java/com/bernard/misael/auth/AuthController.java index 2ed40f4..baac19d 100644 --- a/src/main/java/com/bernard/misael/auth/AuthController.java +++ b/src/main/java/com/bernard/misael/auth/AuthController.java @@ -4,7 +4,6 @@ import java.security.Principal; import java.util.List; import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.annotation.Secured; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -26,13 +25,12 @@ import lombok.Getter; @Controller public class AuthController { - @Autowired - private UserService userService; - @Autowired - private UserRepository urepo; + private final UserService userService; + private final UserRepository urepo; - public AuthController(UserService userService) { + public AuthController(UserService userService, UserRepository urepo) { this.userService = userService; + this.urepo = urepo; } @GetMapping("/login") @@ -94,21 +92,40 @@ public class AuthController { return "redirect:/change-password?success"; } + public static String requiresLogin(String redirect) { + //TODO Make it so it really redirects after login + return "redirect:/login?restricted"; + } + @Getter public static class UserInfo implements Comparable { private long id; private String oidcId; private String pseudo; private String roles; + public UserInfo(User u){ this.id = u.getId(); this.oidcId = u.getOidcId(); this.pseudo = u.getName(); this.roles = u.getPrivileges().stream().map(Privilege::name).collect(Collectors.joining(";")); } + @Override public int compareTo(UserInfo other) { return this.pseudo.compareTo(other.pseudo); } + + @Override + public boolean equals(Object obj) { + if(obj instanceof UserInfo other) + return this.pseudo.equals(other.pseudo); + return false; + } + + @Override + public int hashCode() { + return this.pseudo.hashCode(); + } } } diff --git a/src/main/java/com/bernard/misael/auth/service/UserServiceImpl.java b/src/main/java/com/bernard/misael/auth/service/UserServiceImpl.java index 3bbf5db..15c503c 100644 --- a/src/main/java/com/bernard/misael/auth/service/UserServiceImpl.java +++ b/src/main/java/com/bernard/misael/auth/service/UserServiceImpl.java @@ -41,10 +41,11 @@ public class UserServiceImpl implements UserService { String id = oidcUser.getName(); Set privileges; try { - if(oidcUser.getAttribute("resource_access") != null) + Map>> resourceAccess = oidcUser + .>>>getAttribute("resource_access"); + if(resourceAccess == null) throw new RuntimeException("Oidc user has no 'resource_access'"); - privileges = oidcUser - .>>>getAttribute("resource_access") + privileges = resourceAccess .getOrDefault("misael",Map.of()) .getOrDefault("roles",List.of()) .stream() @@ -103,8 +104,8 @@ public class UserServiceImpl implements UserService { public List findAllUsers() { List users = userRepository.findAll(); return users.stream() - .map((user) -> mapToUserDto(user)) - .collect(Collectors.toList()); + .map(this::mapToUserDto) + .toList(); } private UserDto mapToUserDto(User user){ @@ -123,12 +124,10 @@ public class UserServiceImpl implements UserService { @Override public User ofPrincipal(Principal p) { User u = null; - if(p instanceof OAuth2AuthenticationToken) { - OAuth2AuthenticationToken o = (OAuth2AuthenticationToken) p; + if(p instanceof OAuth2AuthenticationToken o) { u = userRepository.findByOidcId(o.getName()).orElseThrow(() -> new RuntimeException("Oauth2 user was not in the database")); } - if(p instanceof UsernamePasswordAuthenticationToken) { - UsernamePasswordAuthenticationToken o = (UsernamePasswordAuthenticationToken) p; + if(p instanceof UsernamePasswordAuthenticationToken o) { u = userRepository.findByName(o.getName()); } return u; diff --git a/src/main/java/com/bernard/misael/quizz/APIException.java b/src/main/java/com/bernard/misael/quizz/APIException.java new file mode 100644 index 0000000..7e50bfb --- /dev/null +++ b/src/main/java/com/bernard/misael/quizz/APIException.java @@ -0,0 +1,23 @@ +package com.bernard.misael.quizz; + +import org.springframework.http.HttpStatus; +import org.springframework.lang.NonNull; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class APIException extends RuntimeException { + + private final String message; + + @NonNull + private final HttpStatus status; + + public APIException(String message) { + this.message = message; + this.status = HttpStatus.BAD_REQUEST; + } + +} diff --git a/src/main/java/com/bernard/misael/quizz/QuestionsController.java b/src/main/java/com/bernard/misael/quizz/QuestionsController.java index 149b585..1b27c9c 100644 --- a/src/main/java/com/bernard/misael/quizz/QuestionsController.java +++ b/src/main/java/com/bernard/misael/quizz/QuestionsController.java @@ -6,9 +6,7 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.annotation.Secured; @@ -18,7 +16,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.bernard.misael.auth.service.UserService; import com.bernard.misael.quizz.model.Quizz; -import com.bernard.misael.quizz.model.QuizzForm; +import com.bernard.misael.quizz.model.QuizzForm; +import com.bernard.misael.auth.AuthController; import com.bernard.misael.auth.model.User; import com.bernard.misael.quizz.questions.QTypes; import com.bernard.misael.quizz.repository.QuizzFormRepository; @@ -26,7 +25,11 @@ import com.bernard.misael.quizz.repository.QuizzRepository; import com.bernard.misael.quizz.service.QuizzManager; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.servlet.http.HttpServletRequest; + +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -36,18 +39,30 @@ import org.springframework.web.bind.annotation.RequestBody; @RequestMapping("/questions") public class QuestionsController { - @Autowired - UserService us; - - @Autowired - QuizzManager qm; - - @Autowired - QuizzRepository qrepo; - - @Autowired - QuizzFormRepository qfrepo; + private final UserService us; + private final QuizzManager qm; + private final QuizzRepository qrepo; + private final QuizzFormRepository qfrepo; + public QuestionsController(UserService us, QuizzManager qm, QuizzRepository qrepo, QuizzFormRepository qfrepo) { + this.us = us; + this.qm = qm; + this.qrepo = qrepo; + this.qfrepo = qfrepo; + } + + @ExceptionHandler(APIException.class) + public Object apiException(HttpServletRequest request, APIException e) { + if(request.getMethod().equals(HttpMethod.GET.toString())) + return new ResponseEntity<>(e.getMessage(), e.getStatus()); + else { + ObjectNode out = JsonNodeFactory.instance.objectNode(); + out.set("success", JsonNodeFactory.instance.booleanNode(false)); + out.set("message", JsonNodeFactory.instance.textNode(e.getMessage())); + return new ResponseEntity<>(out, e.getStatus()); + } + } + /* * List all quizz */ @@ -80,16 +95,10 @@ public class QuestionsController { * Show one (completed) form of one user */ @GetMapping("/showform/{id}") - public Object showForm(@PathVariable("id") long id, Model m, Principal p) { + public Object showForm(@PathVariable("id") long id, Model m, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); - if(u==null) - return "redirect:/login?restricted"; - Optional oqf = qm.canViewQuizzForm(u, id); - if (oqf.isEmpty()) - //TODO Faire un mesasge d'erreur dépendant des circonstances (unatuhorized, not found, not complete ...) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); - - m.addAttribute("formId", id); + QuizzForm qf = qm.getQuizzForm(u, id); + m.addAttribute("formId", qf.getId()); return "showform.html"; } @@ -97,16 +106,10 @@ public class QuestionsController { * Watch advancements of all forms for a specific quizz id */ @GetMapping("/watch/{id}") - public Object showFormsAdvancements(@PathVariable("id") long id, Model m, Principal p) { + public Object showFormsAdvancements(@PathVariable("id") long id, Model m, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); - if(u==null) - return "redirect:/login?restricted"; - Optional oq = qm.canViewQuizzFormsOfQuizz(u, id); - if (oq.isEmpty()) - //TODO Faire un message d'erreur dépendant des circonstances (unatuhorized, not found, not complete ...) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); - - m.addAttribute("quizzId", id); + Quizz q = qm.getQuizz4Watch(u, id); + m.addAttribute("quizzId", q.getId()); return "watchquizz.html"; } @@ -114,10 +117,10 @@ public class QuestionsController { * API get the form */ @PostMapping("/getformdata/{id}") - public Object showFormApi(@PathVariable("id") long id, Principal p) { + public Object showFormApi(@PathVariable("id") long id, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return "redirect:/login?restricted"; + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.getQuizzFormData(u, id); return new ResponseEntity<>(out, HttpStatus.OK); } @@ -125,11 +128,11 @@ public class QuestionsController { /* * API get the forms for a specific quizz */ - @GetMapping("/getallformsdata/{id}") - public Object getAllFormsData(@PathVariable("id") long id, Principal p) { + @PostMapping("/getallformsdata/{id}") + public Object getAllFormsData(@PathVariable("id") long id, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return "redirect:/login?restricted"; + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.getAllFormsData(u, id); return new ResponseEntity<>(out, HttpStatus.OK); } @@ -138,10 +141,10 @@ public class QuestionsController { * API get the form advancement for every form of a quizz */ @PostMapping("/watchdata/{id}") - public Object watchData(@PathVariable("id") long id, Principal p) { + public Object watchData(@PathVariable("id") long id, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return "redirect:/login?restricted"; + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.getQuizzFormAdvancments(u, id); return new ResponseEntity<>(out, HttpStatus.OK); } @@ -149,11 +152,11 @@ public class QuestionsController { /* * API get the form */ - @GetMapping("/duplicate-quizz/{id}") - public Object duplicateQuizz(@PathVariable("id") long id, Principal p) { + @PostMapping("/duplicate-quizz/{id}") + public Object duplicateQuizz(@PathVariable("id") long id, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return "redirect:/login?restricted"; + return AuthController.requiresLogin(request.getRequestURI()); Quizz q = qm.duplicateQuizz(u, id); if(q == null) return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); @@ -163,11 +166,11 @@ public class QuestionsController { /* * API get the form */ - @GetMapping("/mark-complete/{id}") - public Object markComplete(@PathVariable("id") long id, Principal p) { + @PostMapping("/mark-complete/{id}") + public Object markComplete(@PathVariable("id") long id, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return "redirect:/login?restricted"; + return AuthController.requiresLogin(request.getRequestURI()); if(!qm.markComplete(u, id)) return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); return new ResponseEntity<>(HttpStatus.OK); @@ -176,10 +179,10 @@ public class QuestionsController { * API set the last public question */ @PostMapping("/set-public-question-count/{id}") - public Object setPublicQuestionCount(@PathVariable("id") long id, @RequestBody JsonNode data, Principal p) { + public Object setPublicQuestionCount(@PathVariable("id") long id, @RequestBody JsonNode data, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return "redirect:/login?restricted"; + return AuthController.requiresLogin(request.getRequestURI()); JsonNode pqc = data.get("publicQuestionCount"); Integer pqcI = pqc.isNull() ? null : pqc.asInt(); if(!qm.setPublicQuestionCount(u, id, pqcI)) @@ -188,10 +191,10 @@ public class QuestionsController { } @GetMapping("/form/{q}") - public String formpage(@PathVariable("q") long quizzId, Principal p, Model m) { + public String formpage(@PathVariable("q") long quizzId, Principal p, Model m, HttpServletRequest request) { User u = us.ofPrincipal(p); if (u==null) - return "redirect:/login?restricted"; + return AuthController.requiresLogin(request.getRequestURI()); m.addAttribute("formid", quizzId); Quizz q = qrepo.getReferenceById(quizzId); m.addAttribute("quizzLength",q.getQuestionCount()); @@ -199,85 +202,84 @@ public class QuestionsController { return "form"; } - @GetMapping("/question/{q}") - public ResponseEntity question(@PathVariable("q") long quizzId, Principal p) { + @PostMapping("/question/{q}") + public Object question(@PathVariable("q") long quizzId, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.next(u, quizzId); return new ResponseEntity<>(out, HttpStatus.OK); } @PostMapping("/answer/{q}") - public ResponseEntity answer(@PathVariable("q") long quizzId, @RequestBody JsonNode data, Principal p) { + public Object answer(@PathVariable("q") long quizzId, @RequestBody JsonNode data, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); + if(u==null) + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.answer(u, quizzId, data); return new ResponseEntity<>(out, HttpStatus.OK); } @GetMapping("/new-quizz") @Secured("CREATE_QUIZZ") - public Object newQuizz(Principal p, Model m) { + public Object newQuizz(Principal p, Model m, HttpServletRequest request) { User u = us.ofPrincipal(p); if (u==null) - return new ResponseEntity<>(HttpStatus.FORBIDDEN); + return AuthController.requiresLogin(request.getRequestURI()); Quizz q = qm.newQuizz(u); return "redirect:/questions/quizz-edit/"+Long.toString(q.getId()); } - Logger logger = LoggerFactory.getLogger(QuestionsController.class); @GetMapping("/quizz-edit/{q}") - public Object quizzEdit(@PathVariable("q") long quizzId, Principal p, Model m) { + public Object quizzEdit(@PathVariable("q") long quizzId, Principal p, Model m, HttpServletRequest request) { User u = us.ofPrincipal(p); - if (u==null || !qm.canEditQuizz(u, quizzId)) - return new ResponseEntity<>(HttpStatus.FORBIDDEN); - m.addAttribute("quizzId", quizzId); - + Quizz q = qm.getQuizz4Edit(u, quizzId); + m.addAttribute("quizzId", q.getId()); return "quizz-edit"; } @PostMapping("/quizz-edit/{q}/get") - public ResponseEntity quizzSetName(@PathVariable("q") long quizzId, Principal p) { + public Object quizzSetName(@PathVariable("q") long quizzId, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.getQuizzInfo(u, quizzId); return new ResponseEntity<>(out, HttpStatus.OK); } @PostMapping("/quizz-edit/{q}/set-name") - public ResponseEntity quizzSetName(@PathVariable("q") long quizzId, @RequestBody String data, Principal p) { + public Object quizzSetName(@PathVariable("q") long quizzId, @RequestBody String data, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.setQuizzName(u, quizzId, data); return new ResponseEntity<>(out, HttpStatus.OK); } @PostMapping("/quizz-edit/{q}/add-question") - public ResponseEntity quizzAddQuestion(@PathVariable("q") long quizzId, Principal p) { + public Object quizzAddQuestion(@PathVariable("q") long quizzId, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.addQuestion(u, quizzId); return new ResponseEntity<>(out, HttpStatus.OK); } @PostMapping("/quizz-edit/{q}/remove-question/{qi}") - public ResponseEntity quizzSetName(@PathVariable("q") long quizzId, @PathVariable("qi") long questionId, Principal p) { + public Object quizzSetName(@PathVariable("q") long quizzId, @PathVariable("qi") long questionId, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.removeQuestion(u, quizzId, questionId); return new ResponseEntity<>(out, HttpStatus.OK); } @PostMapping("/quizz-edit/{q}/reorder-questions") - public ResponseEntity quizzReorderQuestions(@PathVariable("q") long quizzId, @RequestBody JsonNode data, Principal p) { + public Object quizzReorderQuestions(@PathVariable("q") long quizzId, @RequestBody JsonNode data, Principal p, HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); if(!data.isArray()) return new ResponseEntity<>( JsonNodeFactory.instance.textNode("Data should be an array"), @@ -295,22 +297,24 @@ public class QuestionsController { } @PostMapping("/quizz-edit/{q}/edit-question/{qi}") - public ResponseEntity quizzEditQuestion(@PathVariable("q") long quizzId, - @PathVariable("qi") long questionId, @RequestBody JsonNode data, Principal p) { + public Object quizzEditQuestion(@PathVariable("q") long quizzId, + @PathVariable("qi") long questionId, @RequestBody JsonNode data, Principal p, + HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); JsonNode out = qm.editQuestion(u, quizzId, questionId, data); return new ResponseEntity<>(out, HttpStatus.OK); } @PostMapping("/quizz-edit/{q}/set-question-type/{qi}") - public ResponseEntity quizzSetQuestionType(@PathVariable("q") long quizzId, - @PathVariable("qi") long questionId, @RequestBody JsonNode data, Principal p) { + public Object quizzSetQuestionType(@PathVariable("q") long quizzId, + @PathVariable("qi") long questionId, @RequestBody JsonNode data, Principal p, + HttpServletRequest request) { User u = us.ofPrincipal(p); if(u==null) - return new ResponseEntity<>(JsonNodeFactory.instance.objectNode(),HttpStatus.UNAUTHORIZED); + return AuthController.requiresLogin(request.getRequestURI()); if(!data.isTextual()) return new ResponseEntity<>( JsonNodeFactory.instance.textNode("Data should be a string"), diff --git a/src/main/java/com/bernard/misael/quizz/service/QuizzManager.java b/src/main/java/com/bernard/misael/quizz/service/QuizzManager.java index 1a267e9..b14f9a5 100644 --- a/src/main/java/com/bernard/misael/quizz/service/QuizzManager.java +++ b/src/main/java/com/bernard/misael/quizz/service/QuizzManager.java @@ -1,9 +1,9 @@ package com.bernard.misael.quizz.service; import java.util.List; -import java.util.Optional; import com.bernard.misael.auth.model.User; +import com.bernard.misael.quizz.APIException; import com.bernard.misael.quizz.model.Quizz; import com.bernard.misael.quizz.model.QuizzForm; import com.bernard.misael.quizz.questions.QTypes; @@ -11,19 +11,19 @@ import com.fasterxml.jackson.databind.JsonNode; public interface QuizzManager { - public JsonNode answer(User user, long quizzId,JsonNode data); + public JsonNode answer(User user, long quizzId, JsonNode data); public JsonNode next(User user, long quizzId); public Quizz newQuizz(User user); - public boolean canAccessQuizz(User user, long quizzId); public List editableQuizz(User user); public List completedQuizz(User user); public List answerableQuizz(User user); - public boolean canEditQuizz(User user, long quizzId); - public Optional canViewQuizzForm(User user, long quizzFormId); - public Optional canViewQuizzFormsOfQuizz(User user, long quizzId); + public Quizz getQuizz4Edit(User user, long quizzId) throws APIException; + public QuizzForm getQuizzForm(User user, long quizzFormId) throws APIException; + public Quizz getQuizz4Watch(User user, long quizzId) throws APIException; + public Quizz getQuizz4Answer(User user, long quizzId) throws APIException; public JsonNode getQuizzInfo(User user, long quizzId); public JsonNode setQuizzName(User user, long quizzId, String newName); diff --git a/src/main/java/com/bernard/misael/quizz/service/QuizzManagerImpl.java b/src/main/java/com/bernard/misael/quizz/service/QuizzManagerImpl.java index 9cbe9b7..36de710 100644 --- a/src/main/java/com/bernard/misael/quizz/service/QuizzManagerImpl.java +++ b/src/main/java/com/bernard/misael/quizz/service/QuizzManagerImpl.java @@ -6,27 +6,26 @@ import java.util.List; import java.util.Optional; import java.util.Random; import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; -import com.bernard.misael.auth.repository.UserRepository; -import com.bernard.misael.auth.service.UserService; -import com.bernard.misael.quizz.model.Answer; import com.bernard.misael.auth.model.Privilege; +import com.bernard.misael.auth.model.User; +import com.bernard.misael.auth.service.UserService; +import com.bernard.misael.quizz.APIException; +import com.bernard.misael.quizz.model.Answer; import com.bernard.misael.quizz.model.Question; import com.bernard.misael.quizz.model.Quizz; import com.bernard.misael.quizz.model.QuizzForm; -import com.bernard.misael.auth.model.User; import com.bernard.misael.quizz.questions.QTypes; import com.bernard.misael.quizz.questions.QuestionType.AnswerResult; -import com.bernard.misael.quizz.QuestionsController; -import com.bernard.misael.quizz.repository.*; +import com.bernard.misael.quizz.repository.AnswerRepository; +import com.bernard.misael.quizz.repository.QuestionRepository; +import com.bernard.misael.quizz.repository.QuizzFormRepository; +import com.bernard.misael.quizz.repository.QuizzRepository; import com.bernard.misael.quizz.service.exception.MalformedAnswerException; import com.bernard.misael.quizz.service.exception.MalformedClientAnswerException; import com.bernard.misael.quizz.service.exception.QuestionTypeException; @@ -35,82 +34,80 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; -import jakarta.persistence.EntityNotFoundException; +import jakarta.validation.constraints.NotNull; @Service public class QuizzManagerImpl implements QuizzManager { - @Autowired - UserRepository uRepository; + private final QuizzFormRepository qfRepository; + private final QuizzRepository qRepository; + private final QuestionRepository questionRepository; + private final AnswerRepository answerRepository; + private final UserService uService; - @Autowired - QuizzFormRepository qfRepository; + public QuizzManagerImpl( + QuizzFormRepository qfRepository, + QuizzRepository qRepository, + QuestionRepository questionRepository, + AnswerRepository answerRepository, + UserService uService + ) { + this.qfRepository = qfRepository; + this.qRepository = qRepository; + this.questionRepository = questionRepository; + this.answerRepository = answerRepository; + this.uService = uService; + } - @Autowired - QuizzRepository qRepository; - - @Autowired - QuestionRepository questionRepository; - - @Autowired - AnswerRepository answerRepository; - - @Autowired - UserService uService; - - + private static final APIException LOGIN_REQUIRED_EXCEPTION = + new APIException("Must be logged in to do this action", HttpStatus.UNAUTHORIZED); @Override public JsonNode answer(User user, long quizzId, JsonNode data) { + Quizz quizz = getQuizz4Answer(user, quizzId); if(!data.has("index") || !data.get("index").isInt()) - return errorNode("Request should contain the question index"); + throw new APIException("Request should contain the question index"); if(!data.has("step") || !data.get("step").isInt()) - return errorNode("Request should contain the answer step"); + throw new APIException("Request should contain the answer step"); if(!data.has("data")) - return errorNode("Request should contain the answer data"); - if(user == null) - return errorNode("You must be logged in to answer"); - Optional oquizz = qRepository.findById(quizzId); - if(!oquizz.isPresent()) - return errorNode("Could not find the quizz with id "+quizzId); - if(!oquizz.get().isComplete()) - return errorNode("Quizz is not complete"); - Quizz quizz = oquizz.get(); + throw new APIException("Request should contain the answer data"); QuizzForm qf = qfRepository.findByUserAndQuizz(user, quizz); if(qf == null) - return errorNode("The quizzform does not exist, ask the question first"); + throw new APIException("The quizzform does not exist, ask the question first", HttpStatus.NOT_FOUND); if(qf.isDone()) - return errorNode("You're done with the quizz, you cannot answer anymore"); + throw new APIException("You're done with the quizz, you cannot answer anymore", HttpStatus.CONFLICT); int qindex = qf.getCurrentQuestion(); if(qindex != data.get("index").intValue()) - return errorNode("You are not answering the right question (you answer question "+data.get("index").intValue() - +" where you should answer question "+qindex+")"); + throw new APIException( + "You are not answering the right question (you answer question %d, but you should answer question %d)" + .formatted(data.get("index").intValue(), qindex), HttpStatus.CONFLICT); if(qindex >= Optional.ofNullable(quizz.getPublicQuestionCount()).orElse(Integer.MAX_VALUE)) - return errorNode("La question suivante est encore bloquée"); + throw new APIException("La question suivante est encore bloquée", HttpStatus.CONFLICT); Question q = questionRepository.findByQuizzAndIndex(quizz,qindex); if(q == null) - return errorNode("Could not find question "+qindex); + throw new APIException("Could not find question %d".formatted(qindex), HttpStatus.NOT_FOUND); int step = qf.getAnswerStep(); if(step != data.get("step").intValue()) - return errorNode("You are not answering the right step of the question (you answer step "+data.get("step").intValue() - +" where you should step question "+step+")"); + throw new APIException( + "You are not answering the right step of the question (you answer step %d where you should be answering step %d)" + .formatted(data.get("step").intValue(),step)); Answer answer = answerRepository.findByFormAndQuestion(qf, q); if(answer == null) - return errorNode("The database answer object does not exist, ask the question first"); + throw new APIException("The database answer object does not exist, ask the question first", HttpStatus.CONFLICT); JsonNode answerData = answer.getValue(); AnswerResult result; try { result = q.getQT().clientAnswers(step, answerData, data.get("data")); } catch (MalformedAnswerException e) { - return errorNode("The previous answer stored in database is invalid"); + throw new APIException("The previous answer stored in database is invalid", HttpStatus.INTERNAL_SERVER_ERROR); } catch (MalformedClientAnswerException e) { - return errorNode("This answer is not valid here"); + throw new APIException("This answer is not valid here"); } catch (QuestionTypeException e) { - return errorNode("Unknown error from the QuestionType"); + throw new APIException("Unknown error from the QuestionType", HttpStatus.INTERNAL_SERVER_ERROR); } catch (IllegalArgumentException e) { - return errorNode("The QuestionType did not recognize the step of the question"); + throw new APIException("The QuestionType did not recognize the step of the question"); } if(result.isNextQuestion()) { qf.setCurrentQuestion(qindex+1); @@ -131,27 +128,20 @@ public class QuizzManagerImpl implements QuizzManager { @Override public JsonNode next(User user, long quizzId) { - if(user == null) - return errorNode("You need to be logged in to discover the questions"); - Optional oquizz = qRepository.findById(quizzId); - if(!oquizz.isPresent()) - return errorNode("Could not find quizz with id "+quizzId); - if(!oquizz.get().isComplete()) - return errorNode("Quizz is not complete"); - Quizz quizz = oquizz.get(); + Quizz quizz = getQuizz4Answer(user, quizzId); QuizzForm qf = qfRepository.findByUserAndQuizz(user, quizz); if(qf == null){ // We should create the quizzform qf = newQuizzForm(user, quizz); } if(qf.isDone()) - return errorNode("No more questions"); + throw new APIException("No more questions", HttpStatus.OK); int qindex = qf.getCurrentQuestion(); if(qindex >= Optional.ofNullable(quizz.getPublicQuestionCount()).orElse(Integer.MAX_VALUE)) - return errorNode("La question suivante est encore bloquée"); + throw new APIException("La question suivante est encore bloquée", HttpStatus.OK); Question q = questionRepository.findByQuizzAndIndex(quizz,qindex); if(q == null) - return errorNode("Could not find question "+qindex); + throw new APIException("Could not find question %d".formatted(qindex), HttpStatus.NOT_FOUND); int step = qf.getAnswerStep(); Answer answer = answerRepository.findByFormAndQuestion(qf, q); if(answer==null){ @@ -166,11 +156,11 @@ public class QuizzManagerImpl implements QuizzManager { try { qdata = q.getQT().clientQuestionData(step, answerData); } catch (MalformedAnswerException e) { - return errorNode("The previous answer stored in database is invalid"); + throw new APIException("The previous answer stored in database is invalid", HttpStatus.CONFLICT); } catch (QuestionTypeException e) { - return errorNode("Unknown error from the QuestionType"); + throw new APIException("Unknown error from the QuestionType", HttpStatus.INTERNAL_SERVER_ERROR); } catch (IllegalArgumentException e) { - return errorNode("The QuestionType did not recognize the step of the question"); + throw new APIException("The QuestionType did not recognize the step of the question"); } ObjectNode out = JsonNodeFactory.instance.objectNode(); @@ -181,7 +171,7 @@ public class QuizzManagerImpl implements QuizzManager { return out; } - private QuizzForm newQuizzForm(User user, Quizz quizz) { + private QuizzForm newQuizzForm(@NonNull User user, Quizz quizz) { QuizzForm qf = new QuizzForm(); qf.setUser(user); qf.setQuizz(quizz); @@ -196,29 +186,12 @@ public class QuizzManagerImpl implements QuizzManager { @Override public Quizz newQuizz(User user) { Quizz q = new Quizz(); - q.setName("Super questions de "+user.getName()+" ("+Integer.toHexString(rand.nextInt(0xFFFFFFF))+")"); + q.setName("Super questions de %s (%X)".formatted(user.getName(),rand.nextInt(0xFFFFFFF))); q.setOwner(user); q = qRepository.save(q); return q; } - private static final JsonNode errorNode(String err){ - ObjectNode out = JsonNodeFactory.instance.objectNode(); - out.set("success", JsonNodeFactory.instance.booleanNode(false)); - out.set("message", JsonNodeFactory.instance.textNode(err)); - return out; - } - - @Override - public boolean canAccessQuizz(User user, long quizzId) { - try{ - Quizz quizz = qRepository.getReferenceById(quizzId); - return quizz.getPublicQuestionCount()!=null || quizz.getOwner().equals(user); - } catch (EntityNotFoundException e) { - return false; - } - } - @Override public List answerableQuizz(User user) { Set ownQuizz = qRepository.findByOwnerAndIsCompleteTrue(user); @@ -249,38 +222,130 @@ public class QuizzManagerImpl implements QuizzManager { .toList(); } - Logger logger = LoggerFactory.getLogger(QuizzManagerImpl.class); - @Override - public boolean canEditQuizz(User user, long quizzId) { - try { - Quizz quizz = qRepository.getReferenceById(quizzId); - return quizz.getOwner().equals(user); - } catch (EntityNotFoundException e) { - logger.info("Could not find quizz of id {}",quizzId); - return false; - } - } - - private Optional checkEditQuizz(User user, long quizzId) { - if(user == null) - return Optional.of(errorNode("You need to be logged in to edit the quizz")); - if(!canEditQuizz(user, quizzId)) - return Optional.of(errorNode("User has no right to edit quizz")); + /** + * Checks that the given user can edit the quizz whose id is provided. + * If not, throws an APIException + * @param user The user that makes the request + * @param quizzId The ID of the quizz we want to get + * @return The Quizz database object + * @throws APIException If something isn't right + */ + @NotNull + public Quizz getQuizz4Edit(User user, long quizzId) throws APIException { + if (user == null) + throw LOGIN_REQUIRED_EXCEPTION; Optional oquizz = qRepository.findById(quizzId); - if(!oquizz.isPresent()) - return Optional.of(errorNode("Could not find quizz with id "+quizzId)); - if(oquizz.get().isComplete()) - return Optional.of(errorNode("Quizz is complete, cannot edit, answers might have already been cast")); - return Optional.empty(); + if (!oquizz.isPresent()) + throw new APIException("Could not find quizz with id %d".formatted(quizzId), HttpStatus.NOT_FOUND); + Quizz q = oquizz.get(); + if (!q.getOwner().equals(user)) + throw new APIException("User has no right to edit quizz (must be author)", HttpStatus.FORBIDDEN); + if (q.isComplete()) + throw new APIException("Quizz is complete, cannot edit, answers might have already been cast", HttpStatus.CONFLICT); + return q; } + /** + * Checks that the given user can answer the quizz whose id is provided. + * If not, throws an APIException + * @param user The user that makes the request + * @param quizzId The ID of the quizz we want to get + * @return The Quizz database object + * @throws APIException If something isn't right + */ + @NotNull + public Quizz getQuizz4Answer(User user, long quizzId) throws APIException { + if (user == null) + throw LOGIN_REQUIRED_EXCEPTION; + Optional oquizz = qRepository.findById(quizzId); + if (!oquizz.isPresent()) + throw new APIException("Could not find quizz with id %d".formatted(quizzId), HttpStatus.NOT_FOUND); + Quizz q = oquizz.get(); + if(!q.isComplete()) + throw new APIException("Cannot answer a quizz that is not marked as complete", HttpStatus.CONFLICT); + if (!( + q.getOwner().equals(user) || + q.getPublicQuestionCount() != null + )) + throw new APIException("User has no right to answer quizz (must be author, or quizz must be public)", HttpStatus.FORBIDDEN); + return q; + } + + /** + * Gets the specified quizz if user has the right to access all of its forms + * @param user The requesting user + * @param quizzFormId The ID of the quizz we want to get + * @return The Quizz database object + * @throws APIException If something isn't right + */ + @NotNull + public Quizz getQuizz4Watch(User user, long quizzId) throws APIException { + if (user == null) + throw LOGIN_REQUIRED_EXCEPTION; + Optional oquizz = qRepository.findById(quizzId); + if (!oquizz.isPresent()) + throw new APIException("Could not find quizz with id %d".formatted(quizzId), HttpStatus.NOT_FOUND); + Quizz q = oquizz.get(); + if (!(q.getOwner().equals(user) || uService.hasPrivilege(user, Privilege.VIEW_ALL_FORMS))) + throw new APIException(( + "User %s cannot access all forms of quizz %d." + + "Must be either author of the quizz, or have VIEW_ALL_FORMS privilege") + .formatted(user.getName(), q.getId())); + return q; + } + + /** + * Gets the specified quizz form if user has right to access it and if the quizz form is complete + * @param user The requesting user + * @param quizzFormId The ID of the quizz form we want to get + * @return The QuizzForm database object + * @throws APIException If something isn't right + */ + @NotNull + public QuizzForm getQuizzForm(User user, long quizzFormId) throws APIException { + if (user == null) + throw LOGIN_REQUIRED_EXCEPTION; + Optional oqf = qfRepository.findById(quizzFormId); + if(oqf.isEmpty()) + throw new APIException("Could not find quizz form with id %d".formatted(quizzFormId), HttpStatus.NOT_FOUND); + QuizzForm qf = oqf.get(); + if(!qf.isDone()) + throw new APIException("Cannot access a quizz form that is not done"); + if(!( + qf.getUser().equals(user) || + qf.getQuizz().getOwner().equals(user) || + uService.hasPrivilege(user, Privilege.VIEW_ALL_FORMS) + )) throw new APIException(( + "User %s cannot access quizz form %d." + + "Must be either author of the form or author of the quizz, or have VIEW_ALL_FORMS privilege") + .formatted(user.getName(), qf.getId())); + return qf; + } + + /** + * Gets the question and checks it is associated with the given quizz + * @param quizz The given quizz to check the question against + * @param questionId The ID of the question we want to get + * @return The Question database object + * @throws APIException If something isn't right + */ + @NotNull + private Question getQuestion(Quizz quizz, long questionId) throws APIException{ + Optional oq = questionRepository.findById(questionId); + if(oq.isEmpty()) + throw new APIException("Could not find question with id %d".formatted(questionId)); + Question q = oq.get(); + if(!q.getQuizz().equals(quizz)) + throw new APIException("Question is not associated with the right quizzId (got %d, expected %d)" + .formatted(q.getQuizz().getId(), quizz.getId())); + return q; + } @Override - public JsonNode getQuizzInfo(User user, long quizzId) { - Optional authCheck = checkEditQuizz(user, quizzId); - if(authCheck.isPresent()) return authCheck.get(); - - Quizz quizz = qRepository.findById(quizzId).get(); + public JsonNode getQuizzInfo(User user, long quizzId) throws APIException{ + if(user == null) + throw LOGIN_REQUIRED_EXCEPTION; + Quizz quizz = getQuizz4Edit(user, quizzId); ArrayNode n = JsonNodeFactory.instance.arrayNode(quizz.getQuestionCount()); for(int i = 0;i authCheck = checkEditQuizz(user, quizzId); - if(authCheck.isPresent()) return authCheck.get(); + + Quizz quizz = getQuizz4Edit(user, quizzId); if(newName.isBlank() || newName.length()>255) - return errorNode("Le nom est invalide"); - - Quizz quizz = qRepository.findById(quizzId).get(); + throw new APIException("Le nom est invalide"); quizz.setName(newName); ObjectNode out = JsonNodeFactory.instance.objectNode(); @@ -318,11 +381,8 @@ public class QuizzManagerImpl implements QuizzManager { public static final QTypes DEFAULT_QTYPE = QTypes.DCC; @Override - public JsonNode addQuestion(User user, long quizzId) { - Optional authCheck = checkEditQuizz(user, quizzId); - if(authCheck.isPresent()) return authCheck.get(); - - Quizz quizz = qRepository.findById(quizzId).get(); + public JsonNode addQuestion(User user, long quizzId) throws APIException { + Quizz quizz = getQuizz4Edit(user, quizzId); Question q = new Question(); q.setType(DEFAULT_QTYPE); @@ -342,18 +402,9 @@ public class QuizzManagerImpl implements QuizzManager { } @Override - public JsonNode removeQuestion(User user, long quizzId, long questionId) { - Optional authCheck = checkEditQuizz(user, quizzId); - if(authCheck.isPresent()) return authCheck.get(); - - Quizz quizz = qRepository.findById(quizzId).get(); - - final Question q; - try { - q = questionRepository.getReferenceById(questionId); - } catch (EntityNotFoundException e){ - return errorNode("Could not find question with id "+questionId); - } + public JsonNode removeQuestion(User user, long quizzId, long questionId) throws APIException { + Quizz quizz = getQuizz4Edit(user, quizzId); + Question q = getQuestion(quizz, questionId); questionRepository.findByQuizz(quizz).forEach(qq -> { if(qq.getIndex()>q.getIndex()) @@ -368,30 +419,21 @@ public class QuizzManagerImpl implements QuizzManager { } @Override - public JsonNode reorderQuestions(User user, long quizzId, List newOrder) { - Optional authCheck = checkEditQuizz(user, quizzId); - if(authCheck.isPresent()) return authCheck.get(); - - Quizz quizz = qRepository.findById(quizzId).get(); + public JsonNode reorderQuestions(User user, long quizzId, List newOrder) throws APIException { + Quizz quizz = getQuizz4Edit(user, quizzId); // We need that the base set of neworder is the list of ids // 1) The length is right if(quizz.getQuestionCount() != newOrder.size()) - return errorNode("You must put every question in order"); + throw new APIException("You must put every question in order"); // 2) There is no duplicates if(new HashSet(newOrder).size() != newOrder.size()) - return errorNode("You shouldn't put duplicates in the new order"); + throw new APIException("You shouldn't put duplicates in the new order"); // 3) All ids correspond to an actual question of the right quizz List questions = new ArrayList<>(newOrder.size()); for(int i = 0;i authCheck = checkEditQuizz(user, quizzId); - if(authCheck.isPresent()) return authCheck.get(); - - Quizz quizz = qRepository.findById(quizzId).get(); - - final Question q; - try { - q = questionRepository.getReferenceById(questionId); - } catch (EntityNotFoundException e){ - return errorNode("Could not find question with id "+questionId); - } - - if(!q.getQuizz().equals(quizz)) - return errorNode("Question is not associated with the right quizzId"); + Quizz quizz = getQuizz4Edit(user, quizzId); + Question q = getQuestion(quizz, questionId); if(!q.getType().validate(value)) - return errorNode("Invalid question value"); + throw new APIException("Invalid question value"); q.setValue(value); ObjectNode out = JsonNodeFactory.instance.objectNode(); @@ -432,20 +462,8 @@ public class QuizzManagerImpl implements QuizzManager { @Override public JsonNode setQuestionType(User user, long quizzId, long questionId, QTypes type) { - Optional authCheck = checkEditQuizz(user, quizzId); - if(authCheck.isPresent()) return authCheck.get(); - - Quizz quizz = qRepository.findById(quizzId).get(); - - final Question q; - try { - q = questionRepository.getReferenceById(questionId); - } catch (EntityNotFoundException e){ - return errorNode("Could not find question with id "+questionId); - } - - if(!q.getQuizz().equals(quizz)) - return errorNode("Question is not associated with the right quizzId"); + Quizz quizz = getQuizz4Edit(user, quizzId); + Question q = getQuestion(quizz, questionId); // If type is the same, we don't change (and dont reset the value) JsonNode n; @@ -464,33 +482,9 @@ public class QuizzManagerImpl implements QuizzManager { return out; } - @Override - public Optional canViewQuizzForm(User user, long quizzFormId) { - Optional oqf = qfRepository.findById(quizzFormId); - if(oqf.isEmpty()) return oqf; - QuizzForm qf = oqf.get(); - if(!qf.isDone()) return Optional.empty(); - if(qf.getUser().equals(user)) return oqf; - if(uService.hasPrivilege(user, Privilege.VIEW_ALL_FORMS)) return oqf; - return Optional.empty(); - } - - @Override - public Optional canViewQuizzFormsOfQuizz(User user, long quizzId) { - Optional oq = qRepository.findById(quizzId); - if(oq.isEmpty()) return oq; - Quizz q = oq.get(); - if(q.getOwner().equals(user)) return oq; - if(uService.hasPrivilege(user, Privilege.VIEW_ALL_FORMS)) return oq; - return Optional.empty(); - } - @Override public JsonNode getQuizzFormData(User user, long quizzFormId) { - Optional oqf = canViewQuizzForm(user, quizzFormId); - if(oqf.isEmpty()) - return errorNode("Could not access the quizzform"); //TODO more precise error node - QuizzForm form = oqf.get(); + QuizzForm form = getQuizzForm(user, quizzFormId); List questions = questionRepository.findByQuizzOrderByIndexAsc(form.getQuizz()); List answers = answerRepository.findByFormAndQuestionIn(form, questions); assert questions.size() == answers.size(); @@ -512,16 +506,14 @@ public class QuizzManagerImpl implements QuizzManager { @Override public JsonNode getAllFormsData(User u, long quizzId) { - Optional oq = canViewQuizzFormsOfQuizz(u, quizzId); - if(oq.isEmpty()) - return errorNode("Could not access the quizzform"); //TODO more precise error node - Quizz quizz = oq.get(); + Quizz quizz = getQuizz4Watch(u, quizzId); + ObjectNode out = JsonNodeFactory.instance.objectNode(); out.set("id",JsonNodeFactory.instance.numberNode(quizz.getId())); out.set("name",JsonNodeFactory.instance.textNode(quizz.getName())); ArrayNode questionNode = JsonNodeFactory.instance.arrayNode(quizz.getQuestionCount()); - List questions = quizz.getQuestions().stream().sorted((p,q) -> Integer.valueOf(p.getIndex()).compareTo(q.getIndex())).toList(); + List questions = quizz.getQuestions().stream().sorted((p,q) -> Integer.compare(p.getIndex(),q.getIndex())).toList(); for(int i=0;i oq = canViewQuizzFormsOfQuizz(user, quizzId); - if(oq.isEmpty()) - return errorNode("Could not access the forms for this quizz"); //TODO more precise error node - Quizz quizz = oq.get(); + Quizz quizz = getQuizz4Watch(user, quizzId); List quizzForms = qfRepository.findByQuizz(quizz); quizzForms.sort((qfa,qfb) -> qfa.getUser().getName().compareTo(qfb.getUser().getName())); @@ -585,15 +574,10 @@ public class QuizzManagerImpl implements QuizzManager { @Override public Quizz duplicateQuizz(User u, long quizzId) { - if (!canEditQuizz(u, quizzId)) - return null; - Optional oq = qRepository.findById(quizzId); - // CHECKED BEFORE if (oq.isEmpty()) return null; - Quizz q = oq.get(); - + Quizz q = getQuizz4Edit(u, quizzId); Quizz nq = new Quizz(); - nq.setName(q.getName() + "("+ Integer.toHexString((int)(Math.random()*0xFFFFFFF)) +")"); + nq.setName(q.getName() + "("+ Integer.toHexString(rand.nextInt(0xFFFFFFF)) +")"); nq.setOwner(q.getOwner()); nq.setQuestionCount(q.getQuestionCount()); nq.setPublicQuestionCount(q.getPublicQuestionCount()); @@ -615,12 +599,7 @@ public class QuizzManagerImpl implements QuizzManager { @Override public boolean markComplete(User u, long quizzId) { - if (!canEditQuizz(u, quizzId)) - return false; - Optional oq = qRepository.findById(quizzId); - if(oq.isEmpty()) - return false; - Quizz q = oq.get(); + Quizz q = getQuizz4Edit(u, quizzId); q.setPublicQuestionCount(null); q.setComplete(true); @@ -631,12 +610,7 @@ public class QuizzManagerImpl implements QuizzManager { @Override public boolean setPublicQuestionCount(User u, long quizzId, Integer publicQuestionCount) { - if (!canEditQuizz(u, quizzId)) - return false; - Optional oq = qRepository.findById(quizzId); - if(oq.isEmpty()) - return false; - Quizz q = oq.get(); + Quizz q = getQuizz4Watch(u, quizzId); if(!q.isComplete()) return false; if(publicQuestionCount != null && (publicQuestionCount > q.getQuestionCount() || publicQuestionCount < 0)) diff --git a/src/main/java/com/bernard/misael/thecrew/TheCrewConfig.java b/src/main/java/com/bernard/misael/thecrew/TheCrewConfig.java index a495046..259589a 100644 --- a/src/main/java/com/bernard/misael/thecrew/TheCrewConfig.java +++ b/src/main/java/com/bernard/misael/thecrew/TheCrewConfig.java @@ -1,13 +1,14 @@ package com.bernard.misael.thecrew; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.NonNull; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class TheCrewConfig implements WebMvcConfigurer { @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { + public void addResourceHandlers(@NonNull ResourceHandlerRegistry registry) { String imgFolder = System.getenv("THECREW_IMAGES_FOLDER"); registry.addResourceHandler("/thecrew/**") diff --git a/src/main/java/com/bernard/misael/thecrew/TheCrewController.java b/src/main/java/com/bernard/misael/thecrew/TheCrewController.java index b48d9b5..0743025 100644 --- a/src/main/java/com/bernard/misael/thecrew/TheCrewController.java +++ b/src/main/java/com/bernard/misael/thecrew/TheCrewController.java @@ -1,10 +1,9 @@ package com.bernard.misael.thecrew; import java.io.File; -import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; -import org.springframework.core.io.InputStreamResource; + import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; diff --git a/src/main/resources/templates/form.html b/src/main/resources/templates/form.html index 39bbba9..d64eb01 100644 --- a/src/main/resources/templates/form.html +++ b/src/main/resources/templates/form.html @@ -53,7 +53,7 @@ function next() { $.ajax({ url: "/questions/question/"+qid, - type: "GET", + type: "POST", dataType: "json", success: function(res) { console.log(res) diff --git a/src/main/resources/templates/quizz-edit.html b/src/main/resources/templates/quizz-edit.html index d77c53d..3efc818 100644 --- a/src/main/resources/templates/quizz-edit.html +++ b/src/main/resources/templates/quizz-edit.html @@ -421,9 +421,10 @@ if (confirm("Voulez-vous vraiment marquer ce quizz comme terminé ? Vous ne pourrez plus l'éditer !")) { $.ajax({ url: "/questions/mark-complete/"+quizzid, - type: "GET", + type: "POST", success: function(res) { console.log("SUPER") + //TODO redirect to the right page } }) } diff --git a/src/main/resources/templates/watchquizz.html b/src/main/resources/templates/watchquizz.html index 65c3ca4..b8cf3db 100644 --- a/src/main/resources/templates/watchquizz.html +++ b/src/main/resources/templates/watchquizz.html @@ -153,6 +153,9 @@ function setPublicQuestionCount(n) { return function (e) { setPQC(n) } } + function setPublicQuestionCountLast(n) { + return function (e) { setPQC(qCount) } + } function setPublicQuestionCountRelative(n) { return function (e) { setPQC(pqc + n) } @@ -164,7 +167,7 @@ $('#set-question-begin').on('click',setPublicQuestionCount(0)) $('#set-question-decrement').on('click',setPublicQuestionCountRelative(-1)) $('#set-question-increment').on('click',setPublicQuestionCountRelative(+1)) - $('#set-question-end').on('click',setPublicQuestionCount(qCount)) + $('#set-question-last').on('click',setPublicQuestionCountLast()) getdata()