diff --git a/appinfo/routes.php b/appinfo/routes.php index 93ee157..c7d09c6 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -47,6 +47,10 @@ return [ ['name' => 'api#newForm', 'url' => 'api/v1/form', 'verb' => 'POST'], ['name' => 'api#deleteForm', 'url' => 'api/v1/form/{id}', 'verb' => 'DELETE'], + ['name' => 'api#newQuestion', 'url' => 'api/v1/question/', 'verb' => 'POST'], + ['name' => 'api#deleteQuestion', 'url' => 'api/v1/question/{id}', 'verb' => 'DELETE'], + ['name' => 'api#newAnswer', 'url' => 'api/v1/answer/', 'verb' => 'POST'], + ['name' => 'api#deleteAnswer', 'url' => 'api/v1/answer/{id}', 'verb' => 'DELETE'], ['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 ff41fcc..55acc4a 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -32,8 +32,10 @@ use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\IMapperException; use OCP\IGroupManager; +use OCP\ILogger; use OCP\IRequest; use OCP\IUser; use OCP\IUserManager; @@ -41,7 +43,6 @@ use OCP\Security\ISecureRandom; use OCA\Forms\Db\Event; use OCA\Forms\Db\EventMapper; -use OCA\Forms\Db\Vote; use OCA\Forms\Db\VoteMapper; use OCA\Forms\Db\Question; @@ -49,7 +50,7 @@ use OCA\Forms\Db\QuestionMapper; use OCA\Forms\Db\Answer; use OCA\Forms\Db\AnswerMapper; - +use OCP\Util; class ApiController extends Controller { @@ -60,6 +61,12 @@ class ApiController extends Controller { private $questionMapper; private $answerMapper; + /** @var ILogger */ + private $logger; + + /** @var string */ + private $userId; + /** * PageController constructor. * @param string $appName @@ -81,7 +88,8 @@ class ApiController extends Controller { EventMapper $eventMapper, VoteMapper $voteMapper, QuestionMapper $questionMapper, - AnswerMapper $answerMapper + AnswerMapper $answerMapper, + ILogger $logger ) { parent::__construct($appName, $request); $this->userId = $userId; @@ -91,6 +99,7 @@ class ApiController extends Controller { $this->voteMapper = $voteMapper; $this->questionMapper = $questionMapper; $this->answerMapper = $answerMapper; + $this->logger = $logger; } /** @@ -472,7 +481,6 @@ class ApiController extends Controller { $newEvent->setHash($oldForm->getHash()); $newEvent->setId($oldForm->getId()); $this->eventMapper->update($newEvent); - $this->questionMapper->deleteByForm($newEvent->getId()); } elseif ($mode === 'create') { // Create new form @@ -488,27 +496,6 @@ class ApiController extends Controller { $newEvent = $this->eventMapper->insert($newEvent); } - // Update options - foreach($options['formQuizQuestions'] as $questionElement){ - $newQuestion = new Question(); - - $newQuestion->setFormId($newEvent->getId()); - $newQuestion->setFormQuestionType($questionElement['type']); - $newQuestion->setFormQuestionText(trim(htmlspecialchars($questionElement['text']))); - - $newQuestion = $this->questionMapper->insert($newQuestion); - - foreach($questionElement['answers'] as $answer){ - $newAnswer = new Answer(); - - $newAnswer->setFormId($newEvent->getId()); - $newAnswer->setQuestionId($newQuestion->getId()); - $newAnswer->setText($answer['text']); - - $newAnswer = $this->answerMapper->insert($newAnswer); - } - } - return new DataResponse(array( 'id' => $newEvent->getId(), 'hash' => $newEvent->getHash() @@ -531,9 +518,136 @@ class ApiController extends Controller { )); $event->setTitle('New form'); $event->setDescription(''); + $event->setAccess('public'); $this->eventMapper->insert($event); return new Http\JSONResponse($this->getForm($event->getHash())); } + + /** + * @NoAdminRequired + */ + public function newQuestion(int $formId, string $type, string $text): Http\JSONResponse { + $this->logger->debug('Adding new question: formId: {formId}, type: {type}, text: {text}', [ + 'formId' => $formId, + 'type' => $type, + 'text' => $text, + ]); + + try { + $form = $this->eventMapper->find($formId); + } catch (IMapperException $e) { + $this->logger->debug('Could not find form'); + return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST); + } + + if ($form->getOwner() !== $this->userId) { + $this->logger->debug('This form is not owned by the current user'); + return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); + } + + $question = new Question(); + + $question->setFormId($formId); + $question->setFormQuestionType($type); + $question->setFormQuestionText($text); + + $question = $this->questionMapper->insert($question); + + return new Http\JSONResponse($question->getId()); + } + + /** + * @NoAdminRequired + */ + public function deleteQuestion(int $id): Http\JSONResponse { + $this->logger->debug('Delete question: {id}', [ + 'id' => $id, + ]); + + try { + $question = $this->questionMapper->findById($id); + $form = $this->eventMapper->find($question->getFormId()); + } catch (IMapperException $e) { + $this->logger->debug('Could not find form or question of this answer'); + return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST); + } + + if ($form->getOwner() !== $this->userId) { + $this->logger->debug('This form is not owned by the current user'); + return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); + } + + $this->answerMapper->deleteByQuestion($id); + $this->questionMapper->delete($question); + + return new Http\JSONResponse($id); + } + + /** + * @NoAdminRequired + */ + public function newAnswer(int $formId, int $questionId, string $text): Http\JSONResponse { + $this->logger->debug('Adding new answer: formId: {formId}, questoinId: {questionId}, text: {text}', [ + 'formId' => $formId, + 'questionId' => $questionId, + 'text' => $text, + ]); + + try { + $form = $this->eventMapper->find($formId); + $question = $this->questionMapper->findById($questionId); + } catch (IMapperException $e) { + $this->logger->debug('Could not find form or question so answer can\'t be added'); + return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST); + } + + if ($form->getOwner() !== $this->userId) { + $this->logger->debug('This form is not owned by the current user'); + return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); + } + + if ($question->getFormId() !== $formId) { + $this->logger->debug('This question is not owned by the current user'); + return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); + } + + $answer = new Answer(); + + $answer->setFormId($formId); + $answer->setQuestionId($questionId); + $answer->setText($text); + + $answer = $this->answerMapper->insert($answer); + + return new Http\JSONResponse($answer->getId()); + } + + /** + * @NoAdminRequired + */ + public function deleteAnswer(int $id): Http\JSONResponse { + $this->logger->debug('Deleting answer: {id}', [ + 'id' => $id + ]); + + try { + $answer = $this->answerMapper->findById($id); + $form = $this->eventMapper->find($answer->getFormId()); + } catch (IMapperException $e) { + $this->logger->debug('Could not find form or answer'); + return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST); + } + + if ($form->getOwner() !== $this->userId) { + $this->logger->debug('This form is not owned by the current user'); + return new Http\JSONResponse([], Http::STATUS_FORBIDDEN); + } + + $this->answerMapper->delete($answer); + + //TODO useful response + return new Http\JSONResponse($id); + } } diff --git a/lib/Db/AnswerMapper.php b/lib/Db/AnswerMapper.php index f002ea0..c9681e7 100644 --- a/lib/Db/AnswerMapper.php +++ b/lib/Db/AnswerMapper.php @@ -95,4 +95,27 @@ class AnswerMapper extends QBMapper { $qb->execute(); } + + public function findById(int $answerId): Answer { + $qb = $this->db->getQueryBuilder(); + + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('id', $qb->createNamedParameter($answerId)) + ); + + return $this->findEntity($qb); + } + + public function deleteByQuestion(int $questionId): void { + $qb = $this->db->getQueryBuilder(); + + $qb->delete($this->getTableName()) + ->where( + $qb->expr()->eq('question_id', $qb->createNamedParameter($questionId)) + ); + + $qb->execute(); + } } diff --git a/lib/Db/QuestionMapper.php b/lib/Db/QuestionMapper.php index cadd59e..1a4f28a 100644 --- a/lib/Db/QuestionMapper.php +++ b/lib/Db/QuestionMapper.php @@ -30,10 +30,6 @@ use OCP\AppFramework\Db\QBMapper; class QuestionMapper extends QBMapper { - /** - * TextMapper constructor. - * @param IDBConnection $db - */ public function __construct(IDBConnection $db) { parent::__construct($db, 'forms_questions', Question::class); } @@ -47,13 +43,13 @@ class QuestionMapper extends QBMapper { public function findByForm(int $formId): array { $qb = $this->db->getQueryBuilder(); - $qb->select('*') - ->from($this->getTableName()) - ->where( - $qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT)) - ); + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT)) + ); - return $this->findEntities($qb); + return $this->findEntities($qb); } /** @@ -62,12 +58,24 @@ class QuestionMapper extends QBMapper { public function deleteByForm(int $formId): void { $qb = $this->db->getQueryBuilder(); - $qb->delete($this->getTableName()) - ->where( - $qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT)) - ); + $qb->delete($this->getTableName()) + ->where( + $qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT)) + ); - $qb->execute(); + $qb->execute(); + } + + public function findById(int $questionId): Question { + $qb = $this->db->getQueryBuilder(); + + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('id', $qb->createNamedParameter($questionId)) + ); + + return $this->findEntity($qb); } } diff --git a/src/components/quizFormItem.vue b/src/components/quizFormItem.vue index 9561473..40b0898 100644 --- a/src/components/quizFormItem.vue +++ b/src/components/quizFormItem.vue @@ -33,17 +33,16 @@ name="list" tag="ul" class="form-table"> -
  • - +
  • @@ -58,25 +57,29 @@ export default { question: { type: Object, default: undefined, - answers: [], }, }, data() { return { - formQuizAnswers: [], nextQuizAnswerId: 1, newQuizAnswer: '', type: '', } }, + computed: { + answers() { + return this.question.answers || [] + }, + }, + methods: { emitNewAnswer(question) { this.$emit('add-answer', this, question) }, - emitRemoveAnswer(question, id) { - this.$emit('remove-answer', this, question, id) + emitRemoveAnswer(question, answer, index) { + this.$emit('remove-answer', question, answer, index) }, }, } diff --git a/src/views/Create.vue b/src/views/Create.vue index f81c9b3..ee2f136 100644 --- a/src/views/Create.vue +++ b/src/views/Create.vue @@ -66,15 +66,14 @@ name="list" tag="ul" class="form-table"> -
  • + @remove-answer="deleteAnswer" + @deleteQuestion="deleteQuestion(question, index)" /> @@ -82,6 +81,7 @@