From 50594f0a01449feb5f0dff5bb9fe4c9b58a192f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Wed, 22 Apr 2020 17:57:31 +0200 Subject: [PATCH] Option management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- appinfo/routes.php | 11 +- lib/Controller/ApiController.php | 52 ++++- package-lock.json | 30 ++- package.json | 2 + src/components/Questions/AnswerInput.vue | 182 ++++++++++++++++++ src/components/Questions/QuestionMultiple.vue | 170 ++++++++-------- src/mixins/ViewsMixin.js | 2 +- src/utils/CancelableRequest.js | 57 ++++++ src/views/Create.vue | 145 +++----------- 9 files changed, 440 insertions(+), 211 deletions(-) create mode 100644 src/components/Questions/AnswerInput.vue create mode 100644 src/utils/CancelableRequest.js diff --git a/appinfo/routes.php b/appinfo/routes.php index 0c186a7..eaeb20d 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -34,17 +34,24 @@ return [ ['name' => 'page#goto_form', 'url' => '/{hash}', 'verb' => 'GET'], ['name' => 'page#insert_submission', 'url' => '/insert/submission', 'verb' => 'POST'], + // Forms ['name' => 'api#getForms', 'url' => '/api/v1/forms', 'verb' => 'GET'], + ['name' => 'api#newForm', 'url' => '/api/v1/form', 'verb' => 'POST'], ['name' => 'api#getForm', 'url' => '/api/v1/form/{id}', 'verb' => 'GET'], ['name' => 'api#updateForm', 'url' => '/api/v1/form/update', 'verb' => 'POST'], - ['name' => 'api#newForm', 'url' => '/api/v1/form', 'verb' => 'POST'], ['name' => 'api#deleteForm', 'url' => '/api/v1/form/{id}', 'verb' => 'DELETE'], + + // Questions + ['name' => 'api#newQuestion', 'url' => '/api/v1/question', 'verb' => 'POST'], ['name' => 'api#updateQuestion', 'url' => '/api/v1/question/update', 'verb' => 'POST'], ['name' => 'api#reorderQuestions', 'url' => '/api/v1/question/reorder', 'verb' => 'POST'], - ['name' => 'api#newQuestion', 'url' => '/api/v1/question', 'verb' => 'POST'], ['name' => 'api#deleteQuestion', 'url' => '/api/v1/question/{id}', 'verb' => 'DELETE'], + + // Answers ['name' => 'api#newOption', 'url' => '/api/v1/option', 'verb' => 'POST'], + ['name' => 'api#updateOption', 'url' => '/api/v1/option/update', 'verb' => 'POST'], ['name' => 'api#deleteOption', 'url' => '/api/v1/option/{id}', 'verb' => 'DELETE'], + ['name' => 'api#getSubmissions', 'url' => '/api/v1/submissions/{hash}', 'verb' => 'GET'], ['name' => 'system#get_site_users_and_groups', 'url' => '/get/siteusers', 'verb' => 'POST'], diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php index cba80b6..be8b82d 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -473,16 +473,15 @@ class ApiController extends Controller { /** * @NoAdminRequired */ - public function newOption(int $formId, int $questionId, string $text): Http\JSONResponse { - $this->logger->debug('Adding new option: formId: {formId}, questionId: {questionId}, text: {text}', [ - 'formId' => $formId, + public function newOption(int $questionId, string $text): Http\JSONResponse { + $this->logger->debug('Adding new option: questionId: {questionId}, text: {text}', [ 'questionId' => $questionId, 'text' => $text, ]); try { - $form = $this->formMapper->findById($formId); $question = $this->questionMapper->findById($questionId); + $form = $this->formMapper->findById($question->getFormId()); } catch (IMapperException $e) { $this->logger->debug('Could not find form or question so option can\'t be added'); return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST); @@ -493,11 +492,6 @@ class ApiController extends Controller { return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); } - if ($question->getFormId() !== $formId) { - $this->logger->debug('This question is not part of the current form'); - return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); - } - $option = new Option(); $option->setQuestionId($questionId); @@ -505,6 +499,45 @@ class ApiController extends Controller { $option = $this->optionMapper->insert($option); + return new Http\JSONResponse([ + 'id' => $option->getId() + ]); + } + + /** + * @NoAdminRequired + * Writes the given key-value pairs into Database. + + * @param int $id OptionId of option to update + * @param array $keyValuePairs Array of key=>value pairs to update. + */ + public function updateOption(int $id, array $keyValuePairs): Http\JSONResponse { + $this->logger->debug('Updating option: option: {id}, values: {keyValuePairs}', [ + 'id' => $id, + 'keyValuePairs' => $keyValuePairs + ]); + + try { + $option = $this->optionMapper->findById($id); + $question = $this->questionMapper->findById($option->getQuestionId()); + $form = $this->formMapper->findById($question->getFormId()); + } catch (IMapperException $e) { + $this->logger->debug('Could not find option, question or form'); + return new Http\JSONResponse(['message' => 'Could not find option, question or form'], Http::STATUS_BAD_REQUEST); + } + + if ($form->getOwnerId() !== $this->userId) { + $this->logger->debug('This form is not owned by the current user'); + return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); + } + + // Create OptionEntity with given Params & Id. + $option = Option::fromParams($keyValuePairs); + $option->setId($id); + + // Update changed Columns in Db. + $this->optionMapper->update($option); + return new Http\JSONResponse($option->getId()); } @@ -532,7 +565,6 @@ class ApiController extends Controller { $this->optionMapper->delete($option); - //TODO useful response return new Http\JSONResponse($id); } diff --git a/package-lock.json b/package-lock.json index 21e96ad..c5d0632 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4623,6 +4623,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" + }, "events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", @@ -8209,6 +8214,11 @@ "os-tmpdir": "^1.0.0" } }, + "p-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-debounce/-/p-debounce-2.1.0.tgz", + "integrity": "sha512-M9bMt62TTnozdZhqFgs+V7XD2MnuKCaz+7fZdlu2/T7xruI3uIE5CicQ0vx1hV7HIUYF0jF+4/R1AgfOkl74Qw==" + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -8218,8 +8228,7 @@ "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, "p-is-promise": { "version": "2.1.0", @@ -8245,6 +8254,23 @@ "p-limit": "^2.0.0" } }, + "p-queue": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.3.0.tgz", + "integrity": "sha512-fg5dJlFpd5+3CgG3/0ogpVZUeJbjiyXFg0nu53hrOYsybqSiDyxyOpad0Rm6tAiGjgztAwkyvhlYHC53OiAJOA==", + "requires": { + "eventemitter3": "^4.0.0", + "p-timeout": "^3.1.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", diff --git a/package.json b/package.json index 9496808..174e955 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,8 @@ "crypto-js": "^4.0.0", "debounce": "^1.2.0", "json2csv": "5.0.0", + "p-debounce": "^2.1.0", + "p-queue": "^6.3.0", "regenerator-runtime": "^0.13.5", "v-click-outside": "^3.0.1", "vue": "^2.6.11", diff --git a/src/components/Questions/AnswerInput.vue b/src/components/Questions/AnswerInput.vue new file mode 100644 index 0000000..424e74b --- /dev/null +++ b/src/components/Questions/AnswerInput.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/src/components/Questions/QuestionMultiple.vue b/src/components/Questions/QuestionMultiple.vue index 66a3ef6..05306e2 100644 --- a/src/components/Questions/QuestionMultiple.vue +++ b/src/components/Questions/QuestionMultiple.vue @@ -22,6 +22,7 @@