diff --git a/client/client.go b/client/client.go index afd856e..574a3e4 100644 --- a/client/client.go +++ b/client/client.go @@ -2,11 +2,6 @@ package client import "git.andreafazzi.eu/andrea/probo/models" -type Response struct { - Status string `json:"status"` - Content interface{} `json:"content"` -} - type Question struct { Text string `json:"text"` } @@ -21,18 +16,23 @@ type Quiz struct { Answers []*Answer `json:"answers"` } +type BaseResponse struct { + Status string `json:"status"` + Message string `json:"message"` +} + type ReadAllQuizResponse struct { - Status string `json:"status"` + BaseResponse Content []*models.Quiz `json:"content"` } type CreateQuizResponse struct { - Status string `json:"status"` + BaseResponse Content *models.Quiz `json:"content"` } type UpdateQuizResponse struct { - Status string `json:"status"` + BaseResponse Content *models.Quiz `json:"content"` } @@ -44,11 +44,6 @@ type CreateAnswerRequest struct { *Answer } -type CreateQuizRequest struct { - *Quiz -} - -type UpdateQuizRequest struct { - ID string +type CreateUpdateQuizRequest struct { *Quiz } diff --git a/main.go b/main.go index b5822dc..877cd18 100644 --- a/main.go +++ b/main.go @@ -15,8 +15,8 @@ const port = "3000" func main() { logger.SetLevel(logger.DebugLevel) - server := NewQuizHubCollectorServer( - memory.NewMemoryQuizHubCollectorStore( + server := NewProboCollectorServer( + memory.NewMemoryProboCollectorStore( sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn), ), ) diff --git a/misc/logseq/src/index.ts b/misc/logseq/src/index.ts index 7a437d5..5c0a394 100644 --- a/misc/logseq/src/index.ts +++ b/misc/logseq/src/index.ts @@ -55,17 +55,21 @@ const main = () => { const proboId = `probo_${id}`; logseq.provideModel({ - async postQuiz() { - const parentBlock = await logseq.Editor.getBlock(payload.uuid, { includeChildren: true }); - const quizzes = parentBlock.children.map((child: BlockEntity) => { - const question = { text: child.content } - const answers = child.children.map((answer: BlockEntity, i: number) => { + async createOrUpdateQuiz() { + const parentBlock = await logseq.Editor.getBlock(payload.uuid, { includeChildren: true }); + const answers = child.children.map((answer: BlockEntity, i: number) => { return { text: answer.content, correct: (i == 0) ? true : false } }) + + const quiz = { + question: {text: parentBlock.children[0].content }, + answers: answers + } + const question = { text: child.content } return { question: question, answers: answers, uuid: child.uuid } }); quizzes.forEach(async (quiz, i) => { - const res = await fetch(endpoint, { method: 'POST', body: JSON.stringify(quiz) }) + const res = await fetch(endpoint+'/create', { method: 'POST', body: JSON.stringify(quiz) }) const data = await res.json(); const block = await logseq.Editor.getBlock(quiz.uuid) await logseq.Editor.upsertBlockProperty(parentBlock.uuid, `probo-quiz-uuid`, data.content.ID) @@ -93,7 +97,7 @@ const main = () => { key: `${proboId}`, slot, reset: true, - template: ``, + template: ``, }); }); diff --git a/server.go b/server.go index 19b6462..ff276bc 100644 --- a/server.go +++ b/server.go @@ -12,84 +12,115 @@ import ( "github.com/julienschmidt/httprouter" ) -const jsonContentType = "application/json" - -type QuizHubCollectorServer struct { - store store.QuizHubCollectorStore +type ProboCollectorServer struct { + store store.ProboCollectorStore http.Handler } -func NewQuizHubCollectorServer(store store.QuizHubCollectorStore) *QuizHubCollectorServer { - ps := new(QuizHubCollectorServer) +func NewProboCollectorServer(store store.ProboCollectorStore) *ProboCollectorServer { + ps := new(ProboCollectorServer) ps.store = store router := httprouter.New() router.GET("/quizzes", httprouter.Handle(ps.readAllQuizzesHandler)) router.POST("/quizzes/create", httprouter.Handle(ps.createQuizHandler)) - router.POST("/quizzes/:id/update", httprouter.Handle(ps.updateQuizHandler)) - // router.Handle("/quizzes", logger.WithLogging(http.HandlerFunc(ps.testHandler))) + router.PUT("/quizzes/update/:id", httprouter.Handle(ps.updateQuizHandler)) - ps.Handler = logger.WithLogging(router) + ps.Handler = logger.WithLogging(ps.jsonHeaderMiddleware(router)) return ps } -func (ps *QuizHubCollectorServer) readAllQuizzesHandler(w http.ResponseWriter, r *http.Request, params httprouter.Params) { - w.Header().Set("content-type", jsonContentType) - json.NewEncoder(w).Encode(ps.readAllQuizzes(w, r)) +func (ps *ProboCollectorServer) jsonHeaderMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "application/json") + next.ServeHTTP(w, r) + }) } -func (ps *QuizHubCollectorServer) createQuizHandler(w http.ResponseWriter, r *http.Request, params httprouter.Params) { - response := new(client.Response) +func (ps *ProboCollectorServer) readAllQuizzesHandler(w http.ResponseWriter, r *http.Request, params httprouter.Params) { + response := new(client.ReadAllQuizResponse) + + quizzes, err := ps.readAllQuiz(w, r) + if err != nil { + response = &client.ReadAllQuizResponse{ + BaseResponse: client.BaseResponse{Status: "error", Message: err.Error()}, + Content: nil, + } + } else { + response = &client.ReadAllQuizResponse{ + BaseResponse: client.BaseResponse{Status: "success", Message: ""}, + Content: quizzes, + } + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(response) +} + +func (ps *ProboCollectorServer) createQuizHandler(w http.ResponseWriter, r *http.Request, params httprouter.Params) { + response := new(client.CreateQuizResponse) quiz, err := ps.createQuiz(w, r) if err != nil { - response = &client.Response{Status: "error", Content: err.Error()} + response = &client.CreateQuizResponse{ + BaseResponse: client.BaseResponse{Status: "error", Message: err.Error()}, + Content: nil, + } } - response = &client.Response{Status: "success", Content: quiz} + response = &client.CreateQuizResponse{ + BaseResponse: client.BaseResponse{Status: "success", Message: ""}, + Content: quiz, + } w.WriteHeader(http.StatusAccepted) json.NewEncoder(w).Encode(response) } -func (ps *QuizHubCollectorServer) updateQuizHandler(w http.ResponseWriter, r *http.Request, params httprouter.Params) { - response := new(client.Response) +func (ps *ProboCollectorServer) updateQuizHandler(w http.ResponseWriter, r *http.Request, params httprouter.Params) { + response := new(client.UpdateQuizResponse) quiz, err := ps.updateQuiz(w, r, params.ByName("id")) if err != nil { - response = &client.Response{Status: "error", Content: err.Error()} + response = &client.UpdateQuizResponse{ + BaseResponse: client.BaseResponse{Status: "error", Message: err.Error()}, + Content: nil, + } + } else { + response = &client.UpdateQuizResponse{ + BaseResponse: client.BaseResponse{Status: "success", Message: ""}, + Content: quiz, + } } - response = &client.Response{Status: "success", Content: quiz} - w.WriteHeader(http.StatusAccepted) json.NewEncoder(w).Encode(response) } -func (ps *QuizHubCollectorServer) readAllQuizzes(w http.ResponseWriter, r *http.Request) *client.Response { - tests, err := ps.store.ReadAllQuizzes() +func (ps *ProboCollectorServer) readAllQuiz(w http.ResponseWriter, r *http.Request) ([]*models.Quiz, error) { + quizzes, err := ps.store.ReadAllQuizzes() if err != nil { - return &client.Response{Status: "error", Content: err.Error()} + return nil, err } - return &client.Response{Status: "success", Content: tests} + return quizzes, nil } -func (ps *QuizHubCollectorServer) updateQuiz(w http.ResponseWriter, r *http.Request, id string) (*models.Quiz, error) { +func (ps *ProboCollectorServer) updateQuiz(w http.ResponseWriter, r *http.Request, id string) (*models.Quiz, error) { body, err := ioutil.ReadAll(r.Body) if err != nil { return nil, err } - updateQuizReq := new(client.UpdateQuizRequest) + updateQuizReq := new(client.CreateUpdateQuizRequest) err = json.Unmarshal(body, &updateQuizReq) if err != nil { return nil, err } - updatedQuiz, err := ps.store.UpdateQuiz(updateQuizReq) + updatedQuiz, err := ps.store.UpdateQuiz(updateQuizReq, id) if err != nil { return nil, err } @@ -97,13 +128,13 @@ func (ps *QuizHubCollectorServer) updateQuiz(w http.ResponseWriter, r *http.Requ return updatedQuiz, nil } -func (ps *QuizHubCollectorServer) createQuiz(w http.ResponseWriter, r *http.Request) (*models.Quiz, error) { +func (ps *ProboCollectorServer) createQuiz(w http.ResponseWriter, r *http.Request) (*models.Quiz, error) { body, err := ioutil.ReadAll(r.Body) if err != nil { return nil, err } - createQuizReq := new(client.CreateQuizRequest) + createQuizReq := new(client.CreateUpdateQuizRequest) err = json.Unmarshal(body, &createQuizReq) if err != nil { diff --git a/server_integration_test.go b/server_integration_test.go index db2f63f..c8dee7c 100644 --- a/server_integration_test.go +++ b/server_integration_test.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "fmt" "net/http" "net/http/httptest" "reflect" @@ -18,8 +19,8 @@ type integrationTestSuite struct { } func (t *integrationTestSuite) TestQuizCreateAndReadAll() { - server := NewQuizHubCollectorServer( - memory.NewMemoryQuizHubCollectorStore( + server := NewProboCollectorServer( + memory.NewMemoryProboCollectorStore( sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn), ), ) @@ -60,9 +61,70 @@ func (t *integrationTestSuite) TestQuizCreateAndReadAll() { } } +func (t *integrationTestSuite) TestQuizCreateAndUpdate() { + server := NewProboCollectorServer( + memory.NewMemoryProboCollectorStore( + sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn), + ), + ) + + // POST a new question using a JSON payload + + payload := ` +{ + "question": {"text": "Question 1"}, + "answers": [ + {"text": "Text of the answer 1", "correct": true}, + {"text": "Text of the answer 2"}, + {"text": "Text of the answer 3"}, + {"text": "Text of the answer 4"} + ] +} +` + createQuizResponse, err := t.createQuiz(server, payload) + t.True(err == nil, "Response should be decoded properly") + + if !t.Failed() { + payload = ` +{ + "question": {"text": "Updated Question 1"}, + "answers": [ + {"text": "Text of the answer 1"}, + {"text": "Text of the answer 2"}, + {"text": "Text of the answer 3", "correct": true}, + {"text": "Text of the answer 4"} + ] +} + +` + updateQuizResponse, err := t.updateQuiz(server, payload, createQuizResponse.Content.ID) + t.True(err == nil, "Response should be decoded properly") + + if !t.Failed() { + t.Equal("Updated Question 1", updateQuizResponse.Content.Question.Text) + t.Equal("Text of the answer 3", updateQuizResponse.Content.Correct.Text) + } + + } +} + +func (t *integrationTestSuite) TestUpdateNotExistentQuiz() { + server := NewProboCollectorServer( + memory.NewMemoryProboCollectorStore( + sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn), + ), + ) + + payload := "" + r, err := t.updateQuiz(server, payload, "1234") + + t.True(err == nil, fmt.Sprintf("The operation should not return an error: %v", err)) + t.Equal("error", r.Status) +} + func (t *integrationTestSuite) TestCatchDuplicateQuiz() { - server := NewQuizHubCollectorServer( - memory.NewMemoryQuizHubCollectorStore( + server := NewProboCollectorServer( + memory.NewMemoryProboCollectorStore( sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn), ), ) @@ -82,7 +144,7 @@ func (t *integrationTestSuite) TestCatchDuplicateQuiz() { ` quiz1, err := t.createQuiz(server, payload) - t.True(err == nil) + t.True(err == nil, fmt.Sprintf("Create quiz should not raise an error: %v", err)) quiz2, err := t.createQuiz(server, payload) @@ -90,8 +152,8 @@ func (t *integrationTestSuite) TestCatchDuplicateQuiz() { t.True(reflect.DeepEqual(quiz1, quiz2), "Quizzes shold be exactly the same") } -func (t *integrationTestSuite) createQuiz(server *QuizHubCollectorServer, payload string) (*client.CreateQuizResponse, error) { - request, _ := http.NewRequest(http.MethodPost, "/quizzes", strings.NewReader(payload)) +func (t *integrationTestSuite) createQuiz(server *ProboCollectorServer, payload string) (*client.CreateQuizResponse, error) { + request, _ := http.NewRequest(http.MethodPost, "/quizzes/create", strings.NewReader(payload)) response := httptest.NewRecorder() server.ServeHTTP(response, request) @@ -106,7 +168,23 @@ func (t *integrationTestSuite) createQuiz(server *QuizHubCollectorServer, payloa return decodedResponse, err } -func (t *integrationTestSuite) readAllQuiz(server *QuizHubCollectorServer) (*client.ReadAllQuizResponse, error) { +func (t *integrationTestSuite) updateQuiz(server *ProboCollectorServer, payload string, id string) (*client.UpdateQuizResponse, error) { + request, _ := http.NewRequest(http.MethodPut, "/quizzes/update/"+id, strings.NewReader(payload)) + response := httptest.NewRecorder() + + server.ServeHTTP(response, request) + + decodedResponse := new(client.UpdateQuizResponse) + + err := json.Unmarshal(response.Body.Bytes(), decodedResponse) + if err != nil { + return decodedResponse, err + } + + return decodedResponse, err +} + +func (t *integrationTestSuite) readAllQuiz(server *ProboCollectorServer) (*client.ReadAllQuizResponse, error) { request, _ := http.NewRequest(http.MethodGet, "/quizzes", nil) response := httptest.NewRecorder() diff --git a/server_test.go b/server_test.go index 87186fe..af9663d 100644 --- a/server_test.go +++ b/server_test.go @@ -24,10 +24,16 @@ type StubTestHubCollectorStore struct { tests []*models.Quiz } -func (store *StubTestHubCollectorStore) CreateQuiz(test *client.CreateQuizRequest) (*models.Quiz, error) { +func (store *StubTestHubCollectorStore) CreateQuiz(test *client.CreateUpdateQuizRequest) (*models.Quiz, error) { return nil, nil } +func (store *StubTestHubCollectorStore) UpdateQuiz(quiz *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) { + store.tests[0].Question.Text = quiz.Question.Text + + return store.tests[0], nil +} + func (store *StubTestHubCollectorStore) ReadAllQuizzes() ([]*models.Quiz, error) { return store.tests, nil } @@ -44,9 +50,9 @@ func (t *testSuite) BeforeAll() { logger.SetLevel(logger.Disabled) } -func (t *testSuite) TestGETQuestions() { +func (t *testSuite) TestReadAllQuizzes() { expectedResult := &client.ReadAllQuizResponse{ - Status: "success", + BaseResponse: client.BaseResponse{Status: "success"}, Content: []*models.Quiz{ { Question: &models.Question{ID: "1", Text: "Question 1"}, @@ -62,7 +68,7 @@ func (t *testSuite) TestGETQuestions() { }, }} - server := NewQuizHubCollectorServer(store) + server := NewProboCollectorServer(store) request, _ := http.NewRequest(http.MethodGet, "/quizzes", nil) response := httptest.NewRecorder() @@ -71,7 +77,7 @@ func (t *testSuite) TestGETQuestions() { result := getResponse(response.Body) - t.True(result.Status == expectedResult.Status) + t.Equal("application/json", response.Header().Get("Content-Type")) t.True(testsAreEqual(result, expectedResult)) t.Equal(http.StatusOK, response.Code) @@ -79,9 +85,9 @@ func (t *testSuite) TestGETQuestions() { func (t *testSuite) TestUpdateQuiz() { expectedResponse := &client.UpdateQuizResponse{ - Status: "success", + BaseResponse: client.BaseResponse{Status: "success"}, Content: &models.Quiz{ - Question: &models.Question{ID: "1", Text: "Question 1"}, + Question: &models.Question{ID: "1", Text: "Updated Question 1"}, Answers: []*models.Answer{{}, {}, {}}, }, } @@ -93,11 +99,11 @@ func (t *testSuite) TestUpdateQuiz() { }, }} - server := NewQuizHubCollectorServer(store) + server := NewProboCollectorServer(store) payload := ` { - "question": {"text": "Update Question 1"}, + "question": {"text": "Updated Question 1"}, "answers": [ {"text": "Text of the answer 1", "correct": true}, {"text": "Text of the answer 2"}, @@ -106,7 +112,7 @@ func (t *testSuite) TestUpdateQuiz() { ] } ` - request, _ := http.NewRequest(http.MethodPut, "/quizzes/1/update", strings.NewReader(payload)) + request, _ := http.NewRequest(http.MethodPut, "/quizzes/update/1", strings.NewReader(payload)) response := httptest.NewRecorder() server.ServeHTTP(response, request) @@ -118,14 +124,15 @@ func (t *testSuite) TestUpdateQuiz() { if !t.Failed() { t.True(result.Status == expectedResponse.Status) t.True(reflect.DeepEqual(result, expectedResponse)) - t.Equal(http.StatusOK, response.Code) + t.Equal("application/json", response.Header().Get("Content-Type")) + t.Equal(http.StatusAccepted, response.Code) } } func getResponse(body io.Reader) (response *client.ReadAllQuizResponse) { err := json.NewDecoder(body).Decode(&response) if err != nil { - panic(fmt.Errorf("Unable to parse response from server %q into slice of Test, '%v'", body, err)) + panic(fmt.Errorf("Unable to parse response from server %q: %v", body, err)) } return diff --git a/store/memory/memory.go b/store/memory/memory.go index fe67ed8..7235490 100644 --- a/store/memory/memory.go +++ b/store/memory/memory.go @@ -1,6 +1,7 @@ package memory import ( + "fmt" "sync" "git.andreafazzi.eu/andrea/probo/client" @@ -9,32 +10,46 @@ import ( "github.com/google/uuid" ) -type MemoryQuizHubCollectorStore struct { - questions map[string]*models.Question - answers map[string]*models.Answer - quizzes map[string]*models.Quiz +type MemoryProboCollectorStore struct { + quizzes map[string]*models.Quiz - questionAnswer map[string][]string - testQuestion map[string]uint + questionsHashes map[string]*models.Question + answersHashes map[string]*models.Answer + quizzesHashes map[string]*models.Quiz + + hasher hasher.Hasher // A mutex is used to synchronize read/write access to the map lock sync.RWMutex - - hasher hasher.Hasher } -func NewMemoryQuizHubCollectorStore(hasher hasher.Hasher) *MemoryQuizHubCollectorStore { - s := new(MemoryQuizHubCollectorStore) +func NewMemoryProboCollectorStore(hasher hasher.Hasher) *MemoryProboCollectorStore { + s := new(MemoryProboCollectorStore) s.hasher = hasher - s.questions = make(map[string]*models.Question) - s.answers = make(map[string]*models.Answer) + + s.questionsHashes = make(map[string]*models.Question) + s.answersHashes = make(map[string]*models.Answer) + s.quizzesHashes = make(map[string]*models.Quiz) + s.quizzes = make(map[string]*models.Quiz) return s } -func (s *MemoryQuizHubCollectorStore) readQuiz(id string) *models.Quiz { +func (s *MemoryProboCollectorStore) getQuizFromHash(hash string) *models.Quiz { + s.lock.RLock() + defer s.lock.RUnlock() + + quiz, ok := s.quizzesHashes[hash] + if ok { + return quiz + } + + return nil +} + +func (s *MemoryProboCollectorStore) getQuizFromID(id string) *models.Quiz { s.lock.RLock() defer s.lock.RUnlock() @@ -46,11 +61,11 @@ func (s *MemoryQuizHubCollectorStore) readQuiz(id string) *models.Quiz { return nil } -func (s *MemoryQuizHubCollectorStore) readQuestion(id string) *models.Question { +func (s *MemoryProboCollectorStore) getQuestionFromHash(hash string) *models.Question { s.lock.RLock() defer s.lock.RUnlock() - question, ok := s.questions[id] + question, ok := s.questionsHashes[hash] if ok { return question } @@ -58,11 +73,11 @@ func (s *MemoryQuizHubCollectorStore) readQuestion(id string) *models.Question { return nil } -func (s *MemoryQuizHubCollectorStore) readAnswer(id string) *models.Answer { +func (s *MemoryProboCollectorStore) getAnswerFromHash(hash string) *models.Answer { s.lock.RLock() defer s.lock.RUnlock() - answer, ok := s.answers[id] + answer, ok := s.answersHashes[hash] if ok { return answer } @@ -70,122 +85,96 @@ func (s *MemoryQuizHubCollectorStore) readAnswer(id string) *models.Answer { return nil } -func (s *MemoryQuizHubCollectorStore) createQuiz(id string, hash string, quiz *models.Quiz) *models.Quiz { +func (s *MemoryProboCollectorStore) createQuizFromHash(id string, hash string, quiz *models.Quiz) *models.Quiz { s.lock.Lock() defer s.lock.Unlock() quiz.ID = id - s.quizzes[hash] = quiz + + s.quizzesHashes[hash] = quiz + s.quizzes[id] = quiz return quiz } -func (s *MemoryQuizHubCollectorStore) createQuestion(id string, question *models.Question) *models.Question { +func (s *MemoryProboCollectorStore) createQuestionFromHash(hash string, question *models.Question) *models.Question { s.lock.Lock() defer s.lock.Unlock() - s.questions[id] = question + s.questionsHashes[hash] = question return question } -func (s *MemoryQuizHubCollectorStore) createAnswer(id string, answer *models.Answer) *models.Answer { +func (s *MemoryProboCollectorStore) createAnswerFromHash(hash string, answer *models.Answer) *models.Answer { s.lock.Lock() defer s.lock.Unlock() - s.answers[id] = answer + s.answersHashes[hash] = answer return answer } -func (s *MemoryQuizHubCollectorStore) ReadAllQuizzes() ([]*models.Quiz, error) { +func (s *MemoryProboCollectorStore) ReadAllQuizzes() ([]*models.Quiz, error) { result := make([]*models.Quiz, 0) - for id, _ := range s.quizzes { - result = append(result, s.readQuiz(id)) + for hash := range s.quizzesHashes { + result = append(result, s.getQuizFromHash(hash)) } return result, nil } -func (s *MemoryQuizHubCollectorStore) CreateQuiz(r *client.CreateQuizRequest) (*models.Quiz, error) { +func (s *MemoryProboCollectorStore) createOrUpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) { hashes := s.hasher.QuizHashes(r.Quiz) - - quizID := uuid.New().String() quizHash := hashes[len(hashes)-1] - quiz := s.readQuiz(quizHash) + quiz := s.getQuizFromHash(quizHash) if quiz != nil { // Quiz is already present in the store return quiz, nil } - quiz = new(models.Quiz) + if id != "" { + quiz = s.getQuizFromID(id) + if quiz == nil { // Quiz is already present in the store + return nil, fmt.Errorf("Quiz ID %v doesn't exist in the store!", id) + } + } else { + id = uuid.New().String() + quiz = new(models.Quiz) + } questionHash := hashes[0] - q := s.readQuestion(questionHash) + q := s.getQuestionFromHash(questionHash) if q == nil { // if the question is not in the store then we should add it - q = s.createQuestion(questionHash, &models.Question{ + q = s.createQuestionFromHash(questionHash, &models.Question{ ID: uuid.New().String(), - Text: r.Question.Text, + Text: r.Quiz.Question.Text, }) } // Populate Question field quiz.Question = q - for i, answer := range r.Answers { + for i, answer := range r.Quiz.Answers { answerHash := hashes[i+1] - a := s.readAnswer(answerHash) + a := s.getAnswerFromHash(answerHash) if a == nil { // if the answer is not in the store add it - a = s.createAnswer(answerHash, &models.Answer{ + a = s.createAnswerFromHash(answerHash, &models.Answer{ ID: uuid.New().String(), Text: answer.Text, }) - if answer.Correct { - quiz.Correct = a // s.readAnswer(answerID) - } + } + if answer.Correct { + quiz.Correct = a // s.readAnswer(answerID) } quiz.Answers = append(quiz.Answers, a) } - return s.createQuiz(quizID, quizHash, quiz), nil + return s.createQuizFromHash(id, quizHash, quiz), nil } -func (s *MemoryQuizHubCollectorStore) UpdateQuiz(r *client.UpdateQuizRequest) (*models.Quiz, error) { - hashes := s.hasher.QuizHashes(r.Quiz) - - quizID := uuid.New().String() - quizHash := hashes[len(hashes)-1] - - quiz := s.readQuiz(quizHash) - if quiz != nil { // Quiz is already present in the store - return quiz, nil - } - - quiz = new(models.Quiz) - - questionHash := hashes[0] - q := s.readQuestion(questionHash) - if q == nil { // if the question is not in the store then we should add it - q = s.createQuestion(questionHash, &models.Question{ - ID: uuid.New().String(), - Text: r.Question.Text, - }) - } - - // Populate Question field - quiz.Question = q - for i, answer := range r.Answers { - answerHash := hashes[i+1] - a := s.readAnswer(answerHash) - if a == nil { // if the answer is not in the store add it - a = s.createAnswer(answerHash, &models.Answer{ - ID: uuid.New().String(), - Text: answer.Text, - }) - if answer.Correct { - quiz.Correct = a // s.readAnswer(answerID) - } - } - quiz.Answers = append(quiz.Answers, a) - } - - return s.createQuiz(quizID, quizHash, quiz), nil +func (s *MemoryProboCollectorStore) CreateQuiz(r *client.CreateUpdateQuizRequest) (*models.Quiz, error) { + return s.createOrUpdateQuiz(r, "") +} + +func (s *MemoryProboCollectorStore) UpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) { + return s.createOrUpdateQuiz(r, id) } diff --git a/store/store.go b/store/store.go index 941138f..a76e9c7 100644 --- a/store/store.go +++ b/store/store.go @@ -5,8 +5,9 @@ import ( "git.andreafazzi.eu/andrea/probo/models" ) -type QuizHubCollectorStore interface { +type ProboCollectorStore interface { ReadAllQuizzes() ([]*models.Quiz, error) - CreateQuiz(r *client.CreateQuizRequest) (*models.Quiz, error) - UpdateQuiz(r *client.UpdateQuizRequest) (*models.Quiz, error) + + CreateQuiz(r *client.CreateUpdateQuizRequest) (*models.Quiz, error) + UpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) } diff --git a/tests/hurl/create_new_quiz.hurl b/tests/hurl/create_new_quiz.hurl index 1f9cf67..71c50a0 100644 --- a/tests/hurl/create_new_quiz.hurl +++ b/tests/hurl/create_new_quiz.hurl @@ -1,4 +1,4 @@ -POST http://localhost:3000/quizzes +POST http://localhost:3000/quizzes/create { "question": {"text": "Text of Question 1"}, "answers": [