Selaa lähdekoodia

complete questionnaire

master
DemiSel 2 vuotta sitten
vanhempi
commit
7fa7ab5494

+ 31
- 0
backend/src/main/java/api/JsonKeys.java Näytä tiedosto

@@ -0,0 +1,31 @@
1
+package api;
2
+
3
+import com.github.cliftonlabs.json_simple.JsonKey;
4
+
5
+public enum JsonKeys implements JsonKey {
6
+    KEY_QUESTION("question"),
7
+    KEY_QUESTIONS("questions"),
8
+    KEY_ANSWER("answer"),
9
+    KEY_ANSWERS("answers"),
10
+    KEY_DESCRIPTION("description"),
11
+    KEY_NAME("name"),
12
+    KEY_ID("id");
13
+
14
+
15
+    private final Object value;
16
+
17
+    JsonKeys(Object iValue)
18
+    {
19
+        value = iValue;
20
+    }
21
+
22
+    @Override
23
+    public String getKey() {
24
+        return (String) value;
25
+    }
26
+
27
+    @Override
28
+    public Object getValue() {
29
+        return value;
30
+    }
31
+}

+ 15
- 6
backend/src/main/java/api/ResponseHandler.java Näytä tiedosto

@@ -6,6 +6,7 @@ import com.sun.net.httpserver.HttpExchange;
6 6
 import com.sun.net.httpserver.HttpHandler;
7 7
 import controller.ModelController;
8 8
 import controller.QuestionnaireController;
9
+import controller.SessionController;
9 10
 
10 11
 import java.io.IOException;
11 12
 import java.io.OutputStream;
@@ -24,7 +25,7 @@ public class ResponseHandler implements HttpHandler {
24 25
             // parse request body : either empty or a JSON Object
25 26
             // ---------------------------------
26 27
             if (iBody.length() > 0) {
27
-                Jsoner.deserialize(iBody, vRequestJson);
28
+                vRequestJson = Jsoner.deserialize(iBody, vRequestJson);
28 29
             }
29 30
 
30 31
             // ---------------------------------
@@ -34,7 +35,7 @@ public class ResponseHandler implements HttpHandler {
34 35
                 case "GET":
35 36
                     switch (iPath.length) {
36 37
                         case 0:
37
-                            vResponseObject = iController.getAllEntries(vRequestJson); break;
38
+                            vResponseObject = iController.get(vRequestJson); break;
38 39
                         case 1:
39 40
                             vResponseObject = iController.getEntriesForId(iPath[0], vRequestJson); break;
40 41
                         default: throw new Exception(String.format("GET with %d subdirectories not implemented", iPath.length));
@@ -61,6 +62,7 @@ public class ResponseHandler implements HttpHandler {
61 62
             }
62 63
         }catch(Exception vex)
63 64
         {
65
+            vex.printStackTrace();
64 66
             vResponseObject.put("error",vex.getMessage());
65 67
         }
66 68
 
@@ -75,6 +77,10 @@ public class ResponseHandler implements HttpHandler {
75 77
         String[] vRequestURI = iExchange.getRequestURI().getPath().split("/");
76 78
         String vRequestMethod = iExchange.getRequestMethod();
77 79
         String vRequestBody = new String(iExchange.getRequestBody().readAllBytes());
80
+        iExchange.getResponseHeaders().set("Content-Type","application/json; charset=utf-8");
81
+        iExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
82
+        iExchange.getResponseHeaders().set("Access-Control-Allow-Methods", "*");
83
+        iExchange.getResponseHeaders().set("Access-Control-Allow-Headers", "*");
78 84
 
79 85
         try {
80 86
             if(vRequestURI.length < 1)
@@ -84,19 +90,22 @@ public class ResponseHandler implements HttpHandler {
84 90
                 case "questionnaire":
85 91
                     vController = new QuestionnaireController();
86 92
                     break;
93
+                case "session":
94
+                    vController = new SessionController();
95
+                    break;
87 96
                 default:
88 97
                     throw new Exception(String.format("Unknown path '%s'", vRequestURI[1]));
89 98
             }
90 99
 
91 100
             vRequestAnswerBytes = getResponse(vRequestMethod, Arrays.copyOfRange(vRequestURI,2, vRequestURI.length), vRequestBody, vController).toJson().getBytes(StandardCharsets.UTF_8);
92
-            iExchange.getResponseHeaders().set("Content-Type","application/json; charset=utf-8");
93
-            iExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
94 101
             iExchange.sendResponseHeaders(200, vRequestAnswerBytes.length);
95 102
         }
96 103
         catch(Exception vex){
104
+            JsonObject vErrorJsonObect = new JsonObject();
105
+            vErrorJsonObect.put("error", vex.getMessage());
106
+            vRequestAnswerBytes = vErrorJsonObect.toJson().getBytes(StandardCharsets.UTF_8);
97 107
             vex.printStackTrace();
98
-            iExchange.sendResponseHeaders(405, vex.getMessage().getBytes(StandardCharsets.UTF_8).length);
99
-            vRequestAnswerBytes = vex.getMessage().getBytes(StandardCharsets.UTF_8);
108
+            iExchange.sendResponseHeaders(500, vRequestAnswerBytes.length);
100 109
             }
101 110
 
102 111
         vOutputStream.write(vRequestAnswerBytes);

+ 1
- 1
backend/src/main/java/controller/ModelController.java Näytä tiedosto

@@ -4,7 +4,7 @@ import com.github.cliftonlabs.json_simple.JsonObject;
4 4
 
5 5
 public abstract class ModelController {
6 6
 
7
-    public JsonObject getAllEntries(JsonObject iBody) throws Exception{
7
+    public JsonObject get(JsonObject iBody) throws Exception{
8 8
         throw new Exception("Not implemented");
9 9
     }
10 10
 

+ 1
- 1
backend/src/main/java/controller/QuestionnaireController.java Näytä tiedosto

@@ -5,7 +5,7 @@ import model.questionnaire.Questionnaire;
5 5
 
6 6
 public class QuestionnaireController extends ModelController {
7 7
 
8
-    public JsonObject getAllEntries(JsonObject iJsonObject)
8
+    public JsonObject get(JsonObject iJsonObject)
9 9
     {
10 10
         return Questionnaire.getTheOnlyExistingQuestionnaire().asJsonObject();
11 11
     }

+ 38
- 0
backend/src/main/java/controller/SessionController.java Näytä tiedosto

@@ -0,0 +1,38 @@
1
+package controller;
2
+
3
+import com.github.cliftonlabs.json_simple.JsonKey;
4
+import com.github.cliftonlabs.json_simple.JsonObject;
5
+import model.questionnaire.Answer;
6
+import model.questionnaire.Question;
7
+import model.questionnaire.Session;
8
+import java.util.UUID;
9
+
10
+import static api.JsonKeys.KEY_ANSWER;
11
+import static api.JsonKeys.KEY_QUESTION;
12
+
13
+public class SessionController extends ModelController {
14
+
15
+    public JsonObject get(JsonObject iJsonObject) {
16
+        return new Session().asJsonObject();
17
+    }
18
+
19
+    public JsonObject updateEntry(String iID, JsonObject iBody) throws Exception{
20
+        Session vSession = Session.getSessionForUUID(UUID.fromString(iID));
21
+        if(null == vSession)
22
+            throw new Exception(String.format("No session for UUID %s", iID));
23
+
24
+        String vQuestionId = iBody.getString(KEY_QUESTION);
25
+        String vAnswerId   = iBody.getString(KEY_ANSWER);
26
+        Question vQuestion = Question.getForUUID(UUID.fromString(vQuestionId));
27
+        if(null == vQuestion)
28
+            throw new Exception(String.format("No question for UUID %s",vQuestionId));
29
+        Answer vAnswer = vQuestion.getAnswerForUUID(UUID.fromString(vAnswerId));
30
+        if(null == vAnswer)
31
+            throw new Exception(String.format("No answer at index %d", vAnswerId));
32
+
33
+        vSession.getSessionAnswers().setAnswer(vQuestion, vAnswer);
34
+        System.out.println(vSession.asJsonObject().toString());
35
+        return new JsonObject();
36
+    }
37
+
38
+}

+ 8
- 5
backend/src/main/java/model/questionnaire/Answer.java Näytä tiedosto

@@ -10,9 +10,12 @@ import java.io.Writer;
10 10
 import java.nio.charset.StandardCharsets;
11 11
 import java.util.UUID;
12 12
 
13
+import static api.JsonKeys.KEY_DESCRIPTION;
14
+import static api.JsonKeys.KEY_ID;
15
+
13 16
 public class Answer implements Jsonable {
14 17
 
15
-    private UUID    fUUID;
18
+    private UUID fId;
16 19
     private float   fWeight;
17 20
     private Trait   fTrait;
18 21
     private String  fDescription;
@@ -20,7 +23,7 @@ public class Answer implements Jsonable {
20 23
 
21 24
     public Answer(String iDescription, Trait iTrait, float iWeight)
22 25
     {
23
-        fUUID           = UUID.randomUUID();    // I feel like I should check this is truly unique among answers
26
+        fId = UUID.randomUUID();    // I feel like I should check this is truly unique among answers
24 27
         fWeight         = iWeight;
25 28
         fTrait          = iTrait;
26 29
         fDescription    = iDescription;
@@ -28,7 +31,7 @@ public class Answer implements Jsonable {
28 31
 
29 32
     public Trait getTrait() { return fTrait; }
30 33
     public float getWeight() { return fWeight; }
31
-
34
+    public UUID getId() { return fId; }
32 35
 
33 36
     @Override
34 37
     public String toJson() {
@@ -45,8 +48,8 @@ public class Answer implements Jsonable {
45 48
     @Override
46 49
     public void toJson(Writer writable) throws IOException {
47 50
         final JsonObject vResult = new JsonObject();
48
-        vResult.put("description", fDescription);
49
-        vResult.put("id", fUUID.toString());
51
+        vResult.put(KEY_DESCRIPTION, fDescription);
52
+        vResult.put(KEY_ID, fId.toString());
50 53
         writable.write(new String(vResult.toJson().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
51 54
     }
52 55
 }

+ 25
- 2
backend/src/main/java/model/questionnaire/Question.java Näytä tiedosto

@@ -7,19 +7,41 @@ import java.io.IOException;
7 7
 import java.io.StringWriter;
8 8
 import java.io.Writer;
9 9
 import java.nio.charset.StandardCharsets;
10
+import java.util.HashMap;
10 11
 import java.util.List;
12
+import java.util.UUID;
13
+
14
+import static api.JsonKeys.*;
11 15
 
12 16
 public class Question implements Jsonable {
13 17
 
18
+    private static final HashMap<UUID, Question> sQuestions = new HashMap<>();
19
+    private UUID fId;
14 20
     private List<Answer> fAnswers;
15 21
     private String fName;
16 22
 
17 23
     public Question(String iName, List<Answer> iAnswers)
18 24
     {
25
+        fId = UUID.randomUUID();
19 26
         fName = iName;
20 27
         fAnswers = iAnswers;
28
+        sQuestions.put(fId, this);
29
+    }
30
+
31
+
32
+    public static Question getForUUID(UUID iId) {
33
+        return sQuestions.get(iId);
21 34
     }
22 35
 
36
+
37
+    public Answer getAnswerForUUID(UUID iId) {
38
+        return fAnswers.stream().filter( answer -> answer.getId().equals(iId)).findFirst().get();
39
+    }
40
+
41
+    // ------------------------------------------------------------------
42
+    // Jsonable Implementation
43
+    // ------------------------------------------------------------------
44
+
23 45
     @Override
24 46
     public String toJson() {
25 47
         final StringWriter writable = new StringWriter();
@@ -35,8 +57,9 @@ public class Question implements Jsonable {
35 57
     @Override
36 58
     public void toJson(Writer writable) throws IOException {
37 59
         JsonObject vResult = new JsonObject();
38
-        vResult.put("name", fName);
39
-        vResult.put("answers", fAnswers);
60
+        vResult.put(KEY_NAME, fName);
61
+        vResult.put(KEY_ANSWERS, fAnswers);
62
+        vResult.put(KEY_ID, fId.toString());
40 63
         writable.write(new String(vResult.toJson().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
41 64
     }
42 65
 }

+ 5
- 2
backend/src/main/java/model/questionnaire/Questionnaire.java Näytä tiedosto

@@ -5,6 +5,9 @@ import com.github.cliftonlabs.json_simple.JsonObject;
5 5
 import java.util.ArrayList;
6 6
 import java.util.List;
7 7
 
8
+import static api.JsonKeys.KEY_NAME;
9
+import static api.JsonKeys.KEY_QUESTIONS;
10
+
8 11
 public class Questionnaire{
9 12
 
10 13
     private static List<Questionnaire> sQuestionnaires = new ArrayList<>();
@@ -24,8 +27,8 @@ public class Questionnaire{
24 27
 
25 28
     public JsonObject asJsonObject(){
26 29
         JsonObject vResult = new JsonObject();
27
-        vResult.put("name", fName);
28
-        vResult.put("questions",fQuestions);
30
+        vResult.put(KEY_NAME, fName);
31
+        vResult.put(KEY_QUESTIONS,fQuestions);
29 32
         return vResult;
30 33
     }
31 34
 }

+ 48
- 3
backend/src/main/java/model/questionnaire/Session.java Näytä tiedosto

@@ -1,22 +1,67 @@
1 1
 package model.questionnaire;
2 2
 
3
+import com.github.cliftonlabs.json_simple.JsonObject;
4
+import com.github.cliftonlabs.json_simple.Jsonable;
3 5
 import model.personnality.Personality;
4 6
 
7
+import java.io.IOException;
8
+import java.io.StringWriter;
9
+import java.io.Writer;
10
+import java.nio.charset.StandardCharsets;
11
+import java.util.HashMap;
5 12
 import java.util.UUID;
6 13
 
7
-public class Session {
14
+import static api.JsonKeys.KEY_ID;
8 15
 
16
+public class Session implements Jsonable {
17
+
18
+    private static HashMap<UUID, Session> sSessions = new HashMap<UUID, Session>();
9 19
     private UUID fId;
10 20
     private SessionAnswers fAnswers;
11 21
     private Personality    fPersonality;
12 22
 
13
-    public Session(UUID iId){
14
-        fId = iId;
23
+    public Session(){
24
+        fId = UUID.randomUUID();
15 25
         fAnswers = new SessionAnswers();
16 26
         fPersonality = new Personality();
27
+        sSessions.put(fId, this);
17 28
     }
18 29
 
30
+
19 31
     public SessionAnswers getSessionAnswers(){ return fAnswers; }
20 32
 
33
+    public static Session getSessionForUUID(UUID iId){
34
+        return sSessions.get(iId);
35
+    }
36
+
37
+
38
+    // ------------------------------------------------------------------
39
+    // Jsonable Implementation
40
+    // ------------------------------------------------------------------
41
+    public JsonObject asJsonObject() {
42
+        JsonObject vResult = new JsonObject();
43
+        vResult.put(KEY_ID, fId.toString());
44
+
45
+        return vResult;
46
+    }
47
+
48
+
49
+    @Override
50
+    public String toJson() {
51
+        final StringWriter writable = new StringWriter();
52
+        try{
53
+            this.toJson(writable);
54
+        }catch(final IOException caught)
55
+        {
56
+            caught.printStackTrace();
57
+        }
58
+        return writable.toString();
59
+    }
60
+
61
+
62
+    @Override
63
+    public void toJson(Writer writable) throws IOException {
64
+        writable.write(new String(asJsonObject().toJson().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
65
+    }
21 66
 
22 67
 }

+ 1
- 0
backend/src/main/java/model/questionnaire/SessionAnswers.java Näytä tiedosto

@@ -14,6 +14,7 @@ public class SessionAnswers {
14 14
     private HashMap<Trait, Float> fTraits;
15 15
 
16 16
     public SessionAnswers() {
17
+        fTraits = new HashMap<>();
17 18
         fAnswers = new HashMap<>();
18 19
     }
19 20
 

+ 30
- 3
frontend/src/App.js Näytä tiedosto

@@ -1,9 +1,32 @@
1 1
 import './App.css';
2 2
 import React from 'react';
3 3
 import Questionnaire from './component/questionnaire';
4
+import url from './server';
5
+
4 6
 
5 7
 function App() {
6 8
   const [questionnaireStarted, onStartQuestionnaire] = React.useState(false);
9
+  const [sessionIdReceived, onSessionIdReceived] = React.useState(null);
10
+  const [sessionIdRequested, onSessionIdRequested] = React.useState(false);
11
+  const [errorOccured, onErrorOccured] = React.useState(null);
12
+  //-------------------------------
13
+  // Fetch session id
14
+  //-------------------------------
15
+  if(null === sessionIdReceived && !sessionIdRequested)
16
+  {
17
+    onSessionIdRequested(true);
18
+    fetch(url+"/session")
19
+        .then(response => response.json())
20
+        .then(result => {
21
+            if('error' in result)
22
+              onErrorOccured(result.error);
23
+            else
24
+              onSessionIdReceived(result.id);
25
+        })
26
+        .catch( e => {
27
+            console.log(e);
28
+        });
29
+  }
7 30
 
8 31
   return (
9 32
     <div>
@@ -11,17 +34,21 @@ function App() {
11 34
         Are you an introvert or an extrovert ?
12 35
       </h1>
13 36
       <div>
14
-        Take this ✨ totally legit test ✨ and find out !
37
+        Take this <i>✨ totally legit personality test ✨</i> and find out !
15 38
       </div>
16 39
       {
17
-        !questionnaireStarted && 
40
+        null === sessionIdReceived &&
41
+        <div> {null === errorOccured ? "Contacting server..." : "A server error occured 😨 : "+errorOccured} </div>
42
+      }
43
+      {
44
+        !questionnaireStarted && null!=sessionIdReceived &&
18 45
         <div
19 46
         onClick={() => onStartQuestionnaire(true)}>
20 47
           Start
21 48
         </div>
22 49
       }
23 50
       { questionnaireStarted &&
24
-        <Questionnaire/>}
51
+        <Questionnaire sessionId={sessionIdReceived}/>}
25 52
     </div>
26 53
   );
27 54
 }

+ 31
- 7
frontend/src/component/question.js Näytä tiedosto

@@ -1,15 +1,16 @@
1 1
 import React from 'react';
2 2
 import url from '../server';
3
+import Questionnaire from './questionnaire';
3 4
 
4 5
 function Question(props){
5
-    let question = props.questions[props.index];
6
-    const [selectedAnswer, onSelectAnswer] = React.useState(question.answer);
6
+    let current_question = props.questions[props.index];
7
+    const [selectedAnswer, onSelectAnswer] = React.useState(current_question.answer);
7 8
     let question_answers = [];
8 9
 
9 10
     //-------------------------------
10 11
     // Build question form
11 12
     //-------------------------------
12
-    question.answers.forEach(answer => {
13
+    current_question.answers.forEach(answer => {
13 14
         let dom_id = "answer"+answer.id
14 15
         question_answers.push(
15 16
             <div key={dom_id}>
@@ -21,23 +22,46 @@ function Question(props){
21 22
     
22 23
     return (
23 24
     <div>
24
-        <div> {question.name} </div>
25
+        <div> {current_question.name} </div>
25 26
         <div onChange={(value) => onSelectAnswer(value.target.value)}>
26 27
         {question_answers}
27 28
         </div>
28 29
         <div
29 30
             onClick={() => {
31
+                //-------------------------------
32
+                // POST question answer
33
+                //-------------------------------
34
+                fetch(url+"/session/"+props.sessionId, {
35
+                    method:'PUT',
36
+                    body: JSON.stringify({
37
+                        question: current_question.id,
38
+                        answer: selectedAnswer
39
+                    }),
40
+                    headers: {"Content-type": "application/json; charset=UTF-8"}
41
+                }) 
42
+                .then(response => response.json())
43
+                .then(result => {
44
+                    if(props.index === props.questions.length - 1)
45
+                    {
46
+                        //-------------------------------
47
+                        // Tell the (parent) questionnaire that the results should be available
48
+                        //-------------------------------
49
+                        props.questionnaireCompleted(true);
50
+                    }
51
+                })
52
+                .catch( e => console.error(e))
53
+
30 54
                 if(props.index === props.questions.length - 1)
31 55
                 {
32
-                    question.answer = selectedAnswer;
56
+                    current_question.answer = selectedAnswer;
33 57
                 }
34 58
                 else
35 59
                 {
36
-                    question.answer = selectedAnswer;
60
+                    current_question.answer = selectedAnswer;
37 61
                     props.moveToQuestion(props.index + 1);
38 62
                 }
39 63
             }}>
40
-                {props.index < props.questions.length -1 ? "Validate" : "Get Result" }
64
+                {props.index < props.questions.length -1 ? "Validate" : "Get Results" }
41 65
         </div>
42 66
     </div>
43 67
     );

+ 14
- 3
frontend/src/component/questionnaire.js Näytä tiedosto

@@ -1,10 +1,12 @@
1 1
 import React from 'react';
2 2
 import url from '../server';
3 3
 import Question from './question';
4
+import QuestionnaireResult from './questionnaire_result';
4 5
 
5
-function Questionnaire(){
6
+function Questionnaire(props){
6 7
     const [currentIndex, onMoveToIndex] = React.useState(0);
7 8
     const [questionnaireDataFetched, onQuestionnaireDataFetched] = React.useState(null);
9
+    const [resultsAvailable, onQuestionnaireCompleted] = React.useState(false);
8 10
 
9 11
     //-------------------------------
10 12
     // Fetch questionnaire
@@ -14,13 +16,16 @@ function Questionnaire(){
14 16
         fetch(url+"/questionnaire")
15 17
             .then(response => response.json())
16 18
             .then(result => {
19
+                if('error' in result)
20
+                    console.error(result);
17 21
                 onQuestionnaireDataFetched(result);
18 22
             })
19 23
             .catch( e => {
20 24
                 console.log(e);
21
-            })
25
+            });
22 26
     }
23 27
 
28
+    if(!resultsAvailable)
24 29
     return (<React.Fragment>
25 30
         {
26 31
             null === questionnaireDataFetched ?
@@ -28,9 +33,11 @@ function Questionnaire(){
28 33
             :
29 34
             <Question
30 35
                 key={"question_"+currentIndex}   //force throw away to ease radio buttons management 
36
+                sessionId={props.sessionId}
31 37
                 questions={questionnaireDataFetched.questions}
32 38
                 index={currentIndex}
33
-                moveToQuestion={onMoveToIndex}/>
39
+                moveToQuestion={onMoveToIndex}
40
+                questionnaireCompleted={onQuestionnaireCompleted}/>
34 41
         }
35 42
         <div>
36 43
         {
@@ -43,6 +50,10 @@ function Questionnaire(){
43 50
         </div>
44 51
         </React.Fragment>
45 52
     )
53
+    else
54
+    return(
55
+        <QuestionnaireResult/>
56
+    )
46 57
 }
47 58
 
48 59
 export default Questionnaire;

+ 18
- 0
frontend/src/component/questionnaire_result.js Näytä tiedosto

@@ -0,0 +1,18 @@
1
+import React from 'react';
2
+import url from '../server';
3
+
4
+function QuestionnaireResult(props){
5
+    const [resultsFetched, onResultsFetched] = React.useState(null);
6
+
7
+    if(null === resultsFetched)
8
+    {
9
+        
10
+    }
11
+    return(
12
+        <div>
13
+            Results
14
+        </div>
15
+    )
16
+}
17
+
18
+export default QuestionnaireResult;

Loading…
Peruuta
Tallenna