From 35bfeee30698bba6abc400c080c139635c1d1b5f Mon Sep 17 00:00:00 2001 From: ikilledmypc Date: Thu, 22 Aug 2024 16:44:35 +0200 Subject: [PATCH 1/3] fix setup script to use new install syntax --- setup-doughnut-dev.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup-doughnut-dev.sh b/setup-doughnut-dev.sh index 75c94a9d27..bdcd89bf41 100755 --- a/setup-doughnut-dev.sh +++ b/setup-doughnut-dev.sh @@ -46,8 +46,8 @@ install_nixpkg_manager() { if ! command -v nix >/dev/null 2>&1; then download_nixpkg_manager_install_script touch .bash_profile - if [ "${os_type}" == "Mac" || "${os_type}" == "Linux" ]; then - ./install-nix -s -- install + if [ "${os_type}" == "Mac" ] || [ "${os_type}" == "Linux" ]; then + ./install-nix install else echo "Unsupported OS Platform for Nix development enviroment. Exiting!!!" exit 1 From bfea3b80aa48836f773a32876323efdde3a070c3 Mon Sep 17 00:00:00 2001 From: ikilledmypc Date: Thu, 22 Aug 2024 16:45:38 +0200 Subject: [PATCH 2/3] add remove question functionality to back-end --- .../RestQuizQuestionController.java | 10 +++++ .../services/QuizQuestionService.java | 9 ++++ ...tQuizQuestionAndAnswerControllerTests.java | 44 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/backend/src/main/java/com/odde/doughnut/controllers/RestQuizQuestionController.java b/backend/src/main/java/com/odde/doughnut/controllers/RestQuizQuestionController.java index c2eda10a79..7e9fbfe40a 100644 --- a/backend/src/main/java/com/odde/doughnut/controllers/RestQuizQuestionController.java +++ b/backend/src/main/java/com/odde/doughnut/controllers/RestQuizQuestionController.java @@ -135,6 +135,16 @@ public QuizQuestionAndAnswer addQuestionManually( return quizQuestionService.addQuestion(note, questionAndAnswer); } + @DeleteMapping("/{note}/note-questions/{question}") + @Transactional + public void removeQuestion( + @PathVariable("note") @Schema(type = "integer") Note note, + @PathVariable("question") @Schema(type = "integer") QuizQuestionAndAnswer question) + throws UnexpectedNoAccessRightException { + currentUser.assertAuthorization(note); + quizQuestionService.removeQuestion(note, question); + } + @PostMapping("/{note}/refine-question") @Transactional public QuizQuestionAndAnswer refineQuestion( diff --git a/backend/src/main/java/com/odde/doughnut/services/QuizQuestionService.java b/backend/src/main/java/com/odde/doughnut/services/QuizQuestionService.java index e6cde0e53d..975d147d39 100644 --- a/backend/src/main/java/com/odde/doughnut/services/QuizQuestionService.java +++ b/backend/src/main/java/com/odde/doughnut/services/QuizQuestionService.java @@ -42,6 +42,15 @@ public QuizQuestionAndAnswer addQuestion( return questionAndAnswer; } + public void removeQuestion(Note note, QuizQuestionAndAnswer questionAndAnswer) { + // Approval status should be reset whenever note questions are changed + Notebook parentNotebook = note.getNotebook(); + parentNotebook.setApprovalStatus(ApprovalStatus.NOT_APPROVED); + modelFactoryService.save(parentNotebook); + + modelFactoryService.remove(questionAndAnswer); + } + public QuizQuestionAndAnswer refineQuestion(Note note, QuizQuestionAndAnswer questionAndAnswer) { MCQWithAnswer aiGeneratedRefineQuestion = aiQuestionGenerator.getAiGeneratedRefineQuestion( diff --git a/backend/src/test/java/com/odde/doughnut/controllers/RestQuizQuestionAndAnswerControllerTests.java b/backend/src/test/java/com/odde/doughnut/controllers/RestQuizQuestionAndAnswerControllerTests.java index f22fb41e6f..a19c126963 100644 --- a/backend/src/test/java/com/odde/doughnut/controllers/RestQuizQuestionAndAnswerControllerTests.java +++ b/backend/src/test/java/com/odde/doughnut/controllers/RestQuizQuestionAndAnswerControllerTests.java @@ -517,6 +517,50 @@ void resetNotebookApprovalOnAdd() throws UnexpectedNoAccessRightException { } } + @Nested + class removeAQuestionFromNote { + @Test + void authorization() { + Note note = makeMe.aNote().please(); + QuizQuestionAndAnswer mcqWithAnswer = makeMe.aQuestion().please(); + mcqWithAnswer.setNote(note); + assertThrows( + UnexpectedNoAccessRightException.class, + () -> controller.removeQuestion(note, mcqWithAnswer)); + } + + @Test + void persistent() throws UnexpectedNoAccessRightException { + Note note = makeMe.aNote().creatorAndOwner(currentUser).please(); + QuizQuestionAndAnswer mcqWithAnswer = makeMe.aQuestion().please(); + controller.addQuestionManually(note, mcqWithAnswer); + makeMe.refresh(note); + assertThat(note.getQuizQuestionAndAnswers(), hasSize(1)); + controller.removeQuestion(note, mcqWithAnswer); + makeMe.refresh(note); + assertThat(note.getQuizQuestionAndAnswers(), empty()); + } + + @Test + void resetNotebookApprovalOnRemove() throws UnexpectedNoAccessRightException { + Note note = + makeMe + .aNote() + .creatorAndOwner(currentUser) + .asHeadNoteOfANotebook(currentUser.getEntity().getOwnership()) + .withApprovalStatus(ApprovalStatus.PENDING) + .please(); + QuizQuestionAndAnswer mcqWithAnswer = makeMe.aQuestion().please(); + Notebook parentNotebook = note.getNotebook(); + makeMe.refresh(parentNotebook); + assertEquals(ApprovalStatus.PENDING, parentNotebook.getApprovalStatus()); + + controller.removeQuestion(note, mcqWithAnswer); + makeMe.refresh(note); + assertEquals(ApprovalStatus.NOT_APPROVED, note.getNotebook().getApprovalStatus()); + } + } + @Nested class RefineQuestion { @Test From cb93badac4b792e4c437728a3ed57eb33badad2c Mon Sep 17 00:00:00 2001 From: ikilledmypc Date: Fri, 23 Aug 2024 14:51:15 +0200 Subject: [PATCH 3/3] add remove question functionality to front-end and e2e tests --- .../quiz_questions_management.feature | 14 +++++++ e2e_test/start/pageObjects/notePage.ts | 4 ++ e2e_test/step_definitions/note.ts | 7 ++++ frontend/src/components/notes/Questions.vue | 24 ++++++++++- .../RestQuizQuestionControllerService.ts | 22 ++++++++++ .../tests/components/notes/Questions.spec.ts | 41 +++++++++++++++++++ open_api_docs.yaml | 25 +++++++++++ 7 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 frontend/tests/components/notes/Questions.spec.ts diff --git a/e2e_test/features/assessment/quiz_questions_management.feature b/e2e_test/features/assessment/quiz_questions_management.feature index 1a97d88685..e662a7d20e 100644 --- a/e2e_test/features/assessment/quiz_questions_management.feature +++ b/e2e_test/features/assessment/quiz_questions_management.feature @@ -28,6 +28,20 @@ Feature: Quiz Question Management | Why do cows have hooves instead of feet? | Because they lactose! | Woof! | What? | 0 | Then I can request approval for the notebook "The cow joke" + Scenario: Can delete question + Given I am logged in as an admin + And I have a notebook with the head note "The cow joke" + And I add the following question for the note "The cow joke": + | Stem | Choice 0 | Choice 1 | Choice 2 | Correct Choice Index | + | Why do cows have hooves instead of feet? | Because they lactose! | Woof! | What? | 0 | + And I add the following question for the note "The cow joke": + | Stem | Choice 0 | Choice 1 | Choice 2 | Correct Choice Index | + | What do you call a cow with not leg? | Ground beef | Cowboy | Oxford | 0 | + When I click on the delete button for question "Why do cows have hooves instead of feet?" for note "The cow joke" + Then I should see the questions in the question list of the note "The cow joke": + | Question | Correct Choice | + | What do you call a cow with not leg? | Ground beef | + @usingMockedOpenAiService Scenario: Can generate the question by AI Given OpenAI now generates this question: diff --git a/e2e_test/start/pageObjects/notePage.ts b/e2e_test/start/pageObjects/notePage.ts index bc748e0301..836e6da5c3 100644 --- a/e2e_test/start/pageObjects/notePage.ts +++ b/e2e_test/start/pageObjects/notePage.ts @@ -193,6 +193,10 @@ export const assumeNotePage = (noteTopic?: string) => { addQuestion(row: Record) { this.openQuestionList().addQuestionPage().addQuestion(row) }, + deleteQuestion(question: string) { + this.openQuestionList() + cy.findByText(question).parent('tr').findByText('delete').click() + }, refineQuestion(row: Record) { this.openQuestionList().addQuestionPage().refineQuestion(row) }, diff --git a/e2e_test/step_definitions/note.ts b/e2e_test/step_definitions/note.ts index 057f71ceba..37026ff802 100644 --- a/e2e_test/step_definitions/note.ts +++ b/e2e_test/step_definitions/note.ts @@ -96,6 +96,13 @@ Given( } ) +When( + 'I click on the delete button for question {string} for note {string}', + (question: string, noteTopic: string) => { + start.jumpToNotePage(noteTopic).deleteQuestion(question) + } +) + Given( 'I refine the following question for the note {string}:', (noteTopic: string, data: DataTable) => { diff --git a/frontend/src/components/notes/Questions.vue b/frontend/src/components/notes/Questions.vue index e6cab5710c..db75750de3 100644 --- a/frontend/src/components/notes/Questions.vue +++ b/frontend/src/components/notes/Questions.vue @@ -15,6 +15,7 @@ + @@ -28,6 +29,9 @@ v-for="(question, outerIndex) in questions" :key="question.quizQuestion.multipleChoicesQuestion.stem" > +
edit Approved Question Text A + +
No questions -
+