diff --git a/ERD-Misael.erd b/ERD-Misael.erd
new file mode 100644
index 0000000..bc51315
--- /dev/null
+++ b/ERD-Misael.erd
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/bernard/misael/SpringSecurity.java b/src/main/java/com/bernard/misael/SpringSecurity.java
index be5dd07..fb1b0f5 100644
--- a/src/main/java/com/bernard/misael/SpringSecurity.java
+++ b/src/main/java/com/bernard/misael/SpringSecurity.java
@@ -1,6 +1,10 @@
package com.bernard.misael;
import java.security.Principal;
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -21,10 +25,14 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import com.bernard.misael.model.User;
import com.bernard.misael.service.UserService;
+import jakarta.annotation.PostConstruct;
+
@Configuration
@EnableWebSecurity
public class SpringSecurity {
+ public static final Logger LOG = Logger.getLogger(SpringSecurity.class.getName());
+
@Autowired
private UserDetailsService userDetailsService;
diff --git a/src/main/java/com/bernard/misael/model/Answer.java b/src/main/java/com/bernard/misael/model/Answer.java
index f8d6f92..567b3c3 100644
--- a/src/main/java/com/bernard/misael/model/Answer.java
+++ b/src/main/java/com/bernard/misael/model/Answer.java
@@ -31,7 +31,10 @@ public class Answer {
@JoinColumn(name = "question",nullable = false)
private Question question;
- @Lob
+ @ManyToOne
+ @JoinColumn(name = "form",nullable = false)
+ private QuizzForm form;
+
private String value;
}
diff --git a/src/main/java/com/bernard/misael/model/Question.java b/src/main/java/com/bernard/misael/model/Question.java
index 69ad951..fe8d1fe 100644
--- a/src/main/java/com/bernard/misael/model/Question.java
+++ b/src/main/java/com/bernard/misael/model/Question.java
@@ -1,5 +1,11 @@
package com.bernard.misael.model;
+import com.bernard.misael.questions.QTypes;
+import com.bernard.misael.questions.QuestionType;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -19,6 +25,9 @@ public class Question {
@Column(name="id")
private long id;
+ @Column(nullable=false)
+ QTypes type;
+
@Column(nullable=false)
private int index;
@@ -26,7 +35,21 @@ public class Question {
@JoinColumn(name = "quizz",nullable = false)
private Quizz quizz;
- @Lob
private String value;
+ transient QuestionType qtype = null;
+ public QuestionType getQT() {
+ if(qtype==null){
+ ObjectMapper om = new ObjectMapper();
+ JsonNode jsNode;
+ try {
+ jsNode = om.readTree(value);
+ qtype = type.getConstructor().apply(jsNode);
+ } catch (JsonProcessingException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return qtype;
+ }
+
}
diff --git a/src/main/java/com/bernard/misael/questions/DccQuestion.java b/src/main/java/com/bernard/misael/questions/DccQuestion.java
new file mode 100644
index 0000000..9c48658
--- /dev/null
+++ b/src/main/java/com/bernard/misael/questions/DccQuestion.java
@@ -0,0 +1,79 @@
+package com.bernard.misael.questions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class DccQuestion implements QuestionType{
+
+ String text;
+ String goodAnswer;
+ String[] wrongAnswers;
+
+ public DccQuestion(JsonNode data){
+ text = data.get("text").asText();
+ goodAnswer = data.get("good").asText();
+ JsonNode wrong = data.get("wrong");
+ wrongAnswers = new String[wrong.size()];
+ for(int i = 0; i answers = new ArrayList<>(k);
+ answers.add(goodAnswer);
+ for(int i = 0;i type;
+ private Function constructor;
+
+ public static QTypes findById(final int id) {
+ for(QTypes value : QTypes.values())
+ if (value.id == id)
+ return value;
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/bernard/misael/questions/QuestionType.java b/src/main/java/com/bernard/misael/questions/QuestionType.java
new file mode 100644
index 0000000..0d5cf58
--- /dev/null
+++ b/src/main/java/com/bernard/misael/questions/QuestionType.java
@@ -0,0 +1,22 @@
+package com.bernard.misael.questions;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+public interface QuestionType {
+
+ JsonNode clientQuestionData(int step, JsonNode answer);
+
+ AnswerResult clientAnswers(int step, JsonNode oldAnswer, JsonNode clientAnswer);
+
+ @AllArgsConstructor
+ @Getter
+ public static class AnswerResult {
+ private JsonNode newAnswer;
+ private boolean nextQuestion;
+ private int nextStep;
+ }
+
+}
diff --git a/src/main/java/com/bernard/misael/repository/AnswerRepository.java b/src/main/java/com/bernard/misael/repository/AnswerRepository.java
new file mode 100644
index 0000000..a79db2e
--- /dev/null
+++ b/src/main/java/com/bernard/misael/repository/AnswerRepository.java
@@ -0,0 +1,13 @@
+package com.bernard.misael.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.bernard.misael.model.Answer;
+import com.bernard.misael.model.Question;
+import com.bernard.misael.model.QuizzForm;
+
+public interface AnswerRepository extends JpaRepository {
+
+ public Answer findByFormAndQuestion(QuizzForm qf, Question q);
+
+}
diff --git a/src/main/java/com/bernard/misael/repository/QuestionRepository.java b/src/main/java/com/bernard/misael/repository/QuestionRepository.java
new file mode 100644
index 0000000..fa6041d
--- /dev/null
+++ b/src/main/java/com/bernard/misael/repository/QuestionRepository.java
@@ -0,0 +1,13 @@
+package com.bernard.misael.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.bernard.misael.model.Question;
+import com.bernard.misael.model.Quizz;
+
+
+public interface QuestionRepository extends JpaRepository {
+
+ public Question findByQuizzAndIndex(Quizz quizz, int index);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/bernard/misael/repository/QuizzFormRepository.java b/src/main/java/com/bernard/misael/repository/QuizzFormRepository.java
new file mode 100644
index 0000000..f19e851
--- /dev/null
+++ b/src/main/java/com/bernard/misael/repository/QuizzFormRepository.java
@@ -0,0 +1,13 @@
+package com.bernard.misael.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.bernard.misael.model.Quizz;
+import com.bernard.misael.model.QuizzForm;
+import com.bernard.misael.model.User;
+
+public interface QuizzFormRepository extends JpaRepository {
+
+ public QuizzForm findByUserAndQuizz(User u, Quizz q);
+
+}
diff --git a/src/main/java/com/bernard/misael/repository/QuizzRepository.java b/src/main/java/com/bernard/misael/repository/QuizzRepository.java
new file mode 100644
index 0000000..1066699
--- /dev/null
+++ b/src/main/java/com/bernard/misael/repository/QuizzRepository.java
@@ -0,0 +1,14 @@
+package com.bernard.misael.repository;
+
+import java.util.Optional;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.lang.NonNull;
+
+import com.bernard.misael.model.Quizz;
+
+public interface QuizzRepository extends JpaRepository {
+
+ public @NonNull Optional findById(@NonNull Long id);
+
+}
diff --git a/src/main/java/com/bernard/misael/service/QuizzManager.java b/src/main/java/com/bernard/misael/service/QuizzManager.java
new file mode 100644
index 0000000..94028ea
--- /dev/null
+++ b/src/main/java/com/bernard/misael/service/QuizzManager.java
@@ -0,0 +1,11 @@
+package com.bernard.misael.service;
+
+import com.bernard.misael.model.User;
+import com.fasterxml.jackson.databind.JsonNode;
+
+public interface QuizzManager {
+
+ public JsonNode answer(User user, long quizzId,JsonNode data);
+ public JsonNode next(User user, long quizzId);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/bernard/misael/service/QuizzManagerImpl.java b/src/main/java/com/bernard/misael/service/QuizzManagerImpl.java
new file mode 100644
index 0000000..31a5c93
--- /dev/null
+++ b/src/main/java/com/bernard/misael/service/QuizzManagerImpl.java
@@ -0,0 +1,115 @@
+package com.bernard.misael.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.bernard.misael.model.Answer;
+import com.bernard.misael.model.Question;
+import com.bernard.misael.model.Quizz;
+import com.bernard.misael.model.QuizzForm;
+import com.bernard.misael.model.User;
+import com.bernard.misael.questions.QuestionType.AnswerResult;
+import com.bernard.misael.repository.AnswerRepository;
+import com.bernard.misael.repository.QuestionRepository;
+import com.bernard.misael.repository.QuizzFormRepository;
+import com.bernard.misael.repository.QuizzRepository;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+@Service
+public class QuizzManagerImpl implements QuizzManager {
+
+ @Autowired
+ QuizzFormRepository qfRepository;
+
+ @Autowired
+ QuizzRepository qRepository;
+
+ @Autowired
+ QuestionRepository questionRepository;
+
+ @Autowired
+ AnswerRepository answerRepository;
+
+ @Override
+ public JsonNode answer(User user, long quizzId, JsonNode data) {
+ //TODO replace conversions String <-> JsonNode to Answer type
+ Quizz quizz = qRepository.findById(quizzId).get();
+ QuizzForm qf = qfRepository.findByUserAndQuizz(user, quizz);
+
+ if(qf.isDone())
+ throw new UnsupportedOperationException();//TODO add more precise exceptions here
+ int qindex = qf.getCurrentQuestion();
+ Question q = questionRepository.findByQuizzAndIndex(quizz,qindex);
+ int step = qf.getAnswerStep();
+ Answer answer = answerRepository.findByFormAndQuestion(qf, q);
+
+ ObjectMapper om = new ObjectMapper();
+ JsonNode answerData;
+ try {
+ answerData = om.readTree(answer.getValue());
+ AnswerResult result = q.getQT().clientAnswers(step, answerData, data);
+ if(result.isNextQuestion()) {
+ qf.setCurrentQuestion(qindex+1);
+ } else {
+ qf.setAnswerStep(result.getNextStep());
+ }
+ answer.setValue(om.writeValueAsString(result.getNewAnswer()));
+ //XXX Persist QF ?
+ ObjectNode out = JsonNodeFactory.instance.objectNode();
+ out.set("result", JsonNodeFactory.instance.textNode("ok"));
+ return out;
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ //TODO autogenerated
+ return null;
+ }
+ }
+
+ @Override
+ public JsonNode next(User user, long quizzId) {
+ Quizz quizz = qRepository.findById(quizzId).get();
+ QuizzForm qf = qfRepository.findByUserAndQuizz(user, quizz);
+ if(qf == null){
+ // We should create the quizzform
+ qf = newQuizzForm(user, quizz);
+ }
+ if(qf.isDone())
+ throw new UnsupportedOperationException();//TODO add more precise exceptions here
+ int qindex = qf.getCurrentQuestion();
+ Question q = questionRepository.findByQuizzAndIndex(quizz,qindex);
+ int step = qf.getAnswerStep();
+ Answer answer = answerRepository.findByFormAndQuestion(qf, q);
+
+ ObjectMapper om = new ObjectMapper();
+ JsonNode answerData;
+ try {
+ answerData = om.readTree(answer.getValue());
+ JsonNode qdata = q.getQT().clientQuestionData(step, answerData);
+
+ ObjectNode out = JsonNodeFactory.instance.objectNode();
+ out.set("index", JsonNodeFactory.instance.numberNode(qindex));
+ out.set("step", JsonNodeFactory.instance.numberNode(step));
+ out.set("index", qdata);
+ return out;
+ } catch (JsonProcessingException e){
+ //XXX autogenerated
+ return null;
+ }
+ }
+
+ public QuizzForm newQuizzForm(User user, Quizz quizz) {
+ QuizzForm qf = new QuizzForm();
+ qf.setUser(user);
+ qf.setQuizz(quizz);
+ qf.setDone(false);
+ qf.setCurrentQuestion(0);
+ qf.setAnswerStep(0);
+ //XXX Persist QF ?
+ return qf;
+ }
+
+}
diff --git a/src/main/java/com/bernard/misael/service/exception/ShouldNotAnswerNowException.java b/src/main/java/com/bernard/misael/service/exception/ShouldNotAnswerNowException.java
new file mode 100644
index 0000000..589569c
--- /dev/null
+++ b/src/main/java/com/bernard/misael/service/exception/ShouldNotAnswerNowException.java
@@ -0,0 +1,5 @@
+package com.bernard.misael.service.exception;
+
+public class ShouldNotAnswerNowException extends Exception{
+
+}
diff --git a/src/main/java/com/bernard/misael/web/AuthController.java b/src/main/java/com/bernard/misael/web/AuthController.java
index 4a7f2b7..ea899fc 100644
--- a/src/main/java/com/bernard/misael/web/AuthController.java
+++ b/src/main/java/com/bernard/misael/web/AuthController.java
@@ -1,5 +1,14 @@
package com.bernard.misael.web;
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@@ -17,6 +26,7 @@ import jakarta.validation.Valid;
@Controller
public class AuthController {
+ @Autowired
private UserService userService;
public AuthController(UserService userService) {
@@ -71,4 +81,19 @@ public class AuthController {
userService.saveUser(userDto);
return "redirect:/adduser?success";
}
+
+ @GetMapping("/create-mysaa-user")
+ public ResponseEntity checkMysaaExists() {
+ if(userService.findUserByName("mysaa") == null) {
+ UserDto u = new UserDto();
+ Random r = new Random();
+ UUID pass = new UUID(r.nextLong(),r.nextLong());
+ u.setName("mysaa");
+ u.setPassword(pass.toString());
+ userService.saveUser(u);
+ Logger.getLogger(AuthController.class.getName()).warning("Created user mysaa with password "+pass.toString());
+ }
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+
}
diff --git a/src/main/java/com/bernard/misael/web/QuestionsController.java b/src/main/java/com/bernard/misael/web/QuestionsController.java
index 9d9c036..73607ad 100644
--- a/src/main/java/com/bernard/misael/web/QuestionsController.java
+++ b/src/main/java/com/bernard/misael/web/QuestionsController.java
@@ -3,15 +3,22 @@ package com.bernard.misael.web;
import java.security.Principal;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.bernard.misael.model.User;
import com.bernard.misael.repository.UserRepository;
-import com.bernard.misael.service.UserService;
+import com.bernard.misael.service.QuizzManager;
+import com.fasterxml.jackson.databind.JsonNode;
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.RequestBody;
+
@Controller
@@ -21,6 +28,9 @@ public class QuestionsController {
@Autowired
UserRepository ur;
+ @Autowired
+ QuizzManager qm;
+
@GetMapping("/quizz")
/*
* List all quizz
@@ -43,6 +53,37 @@ public class QuestionsController {
*/
public String getForms() {
return "forms.html";
- }
+ }
+
+ @GetMapping("/form/{q}")
+ public String formpage(@PathVariable("q") long quizzId, Principal p, Model m) {
+ User u = null;
+ if (p!=null)
+ u = ur.findByName(p.getName());
+ //XXX test that user can answer quizz
+ m.addAttribute("formid", quizzId);
+
+ return "form";
+ }
+
+ @GetMapping("/question/{q}")
+ public ResponseEntity question(@PathVariable("q") long quizzId, Principal p) {
+ User u = null;
+ if (p!=null)
+ u = ur.findByName(p.getName());
+ JsonNode out = qm.next(u, quizzId);
+ return new ResponseEntity<>(out, HttpStatus.OK);
+ }
+
+ @PostMapping("/answer/{q}")
+ public JsonNode answer(@PathVariable("q") long quizzId, @RequestBody JsonNode data, Principal p) {
+ User u = null;
+ if (p!=null)
+ u = ur.findByName(p.getName());
+ JsonNode out = qm.answer(u, quizzId, data);
+ return out;
+ }
+
+
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index c8d540f..14584a4 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -1,6 +1,6 @@
spring:
datasource:
- url: jdbc:mysql://127.0.0.1:10051/misael
+ url: jdbc:postgres://127.0.0.1:10051/misael
username: misael
password: misael-dev
hikari:
@@ -10,18 +10,25 @@ spring:
locations: classpath:db/migration/structure, classpath:db/migration/data
validate-on-migrate: true
default-schema: misael
+ create-schemas: true
+ session:
+ jdbc:
+ initialize-schema: always
+ security:
+ user:
+ name: mysaa
- # jpa:
- # properties:
- # javax:
- # persistence:
- # schema-generation:
- # create-source: metadata
- # scripts:
- # action: update
- # create-target: db-migration.sql
- # database:
- # action: none
- # hibernate:
- # ddl-auto: none
- # generate-ddl: true
+ jpa:
+ properties:
+ javax:
+ persistence:
+ schema-generation:
+ create-source: metadata
+ scripts:
+ action: update
+ create-target: db-migration.sql
+ database:
+ action: none
+ hibernate:
+ ddl-auto: none
+ generate-ddl: true
diff --git a/src/main/resources/db/migration/V2__quizz_and_questions.sql b/src/main/resources/db/migration/V2__added_quizz_data.sql
similarity index 72%
rename from src/main/resources/db/migration/V2__quizz_and_questions.sql
rename to src/main/resources/db/migration/V2__added_quizz_data.sql
index 1f7785e..f253c50 100644
--- a/src/main/resources/db/migration/V2__quizz_and_questions.sql
+++ b/src/main/resources/db/migration/V2__added_quizz_data.sql
@@ -1,11 +1,12 @@
-create table answers (id bigint generated by default as identity, value oid, question bigint not null, primary key (id));
-create table questions (id bigint generated by default as identity, index integer not null, value oid, quizz bigint not null, primary key (id));
+create table answers (id bigint generated by default as identity, value varchar(255), form bigint not null, question bigint not null, primary key (id));
+create table questions (id bigint generated by default as identity, index integer not null, type smallint not null check (type between 0 and 0), value varchar(255), quizz bigint not null, primary key (id));
create table quizz (id bigint generated by default as identity, is_public boolean default false not null, name varchar(255) not null, question_count integer default 0 not null, owner bigint, primary key (id));
create table quizzf (id bigint generated by default as identity, answer_step integer not null, current_question integer not null, done boolean not null, quizz bigint not null, answerer bigint not null, primary key (id));
alter table if exists quizz drop constraint if exists UKc1plspc0ecmwqqpfaf24avb4c;
alter table if exists quizz add constraint UKc1plspc0ecmwqqpfaf24avb4c unique (name);
+alter table if exists answers add constraint FKjtutlsv5n10071rq261lcjovm foreign key (form) references quizzf;
alter table if exists answers add constraint FK54dobrdq2u51m4u8s7kg0as8v foreign key (question) references questions;
alter table if exists questions add constraint FKq12h25ynjok1m497gwos511te foreign key (quizz) references quizz;
alter table if exists quizz add constraint FKfeoogns8m4m4hvno1ttqb30wm foreign key (owner) references users;
alter table if exists quizzf add constraint FK4ukbg2yaa93gs5nx1s5d9rqu4 foreign key (quizz) references quizz;
-alter table if exists quizzf add constraint FKuj3h8r3i4lnxukdqobapwbuq foreign key (answerer) references users;
+alter table if exists quizzf add constraint FK7gvxodb5t2n68ot577ig9u3w6 foreign key (answerer) references users;
diff --git a/src/main/resources/templates/form.html b/src/main/resources/templates/form.html
new file mode 100644
index 0000000..ed4b17a
--- /dev/null
+++ b/src/main/resources/templates/form.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+ Youhou ! (Y devrait y avoir le form ici ^^)
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/quizz.html b/src/main/resources/templates/quizz.html
index 1b02273..ad7071c 100644
--- a/src/main/resources/templates/quizz.html
+++ b/src/main/resources/templates/quizz.html
@@ -9,7 +9,7 @@