Fix questions display
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
parent
b3570b81dc
commit
612af52f50
|
@ -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'],
|
||||
]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,17 +33,16 @@
|
|||
name="list"
|
||||
tag="ul"
|
||||
class="form-table">
|
||||
<li
|
||||
is="text-form-item"
|
||||
v-for="(ans, index) in formQuizAnswers"
|
||||
:key="ans.id"
|
||||
:option="ans"
|
||||
@remove="emitRemoveAnswer(question, index)"
|
||||
<TextFormItem
|
||||
v-for="(answer, index) in answers"
|
||||
:key="answer.id"
|
||||
:option="answer"
|
||||
@remove="emitRemoveAnswer(question, answer, index)"
|
||||
@delete="question.answers.splice(index, 1)" />
|
||||
</transitionGroup>
|
||||
</div>
|
||||
<div>
|
||||
<a class="icon icon-delete svg delete-form" @click="$emit('remove'), $emit('delete')" />
|
||||
<a class="icon icon-delete svg delete-form" @click="$emit('deleteQuestion')" />
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
|
@ -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)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -66,15 +66,14 @@
|
|||
name="list"
|
||||
tag="ul"
|
||||
class="form-table">
|
||||
<li
|
||||
is="quiz-form-item"
|
||||
<QuizFormItem
|
||||
v-for="(question, index) in form.options.formQuizQuestions"
|
||||
:key="question.id"
|
||||
:question="question"
|
||||
:type="question.type"
|
||||
@add-answer="addAnswer"
|
||||
@remove-answer="removeAnswer"
|
||||
@remove="form.options.formQuizQuestions.splice(index, 1)" />
|
||||
@remove-answer="deleteAnswer"
|
||||
@deleteQuestion="deleteQuestion(question, index)" />
|
||||
</transitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -82,6 +81,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import axios from '@nextcloud/axios'
|
||||
import moment from '@nextcloud/moment'
|
||||
import debounce from 'debounce'
|
||||
|
@ -198,7 +198,7 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
addQuestion() {
|
||||
async addQuestion() {
|
||||
this.checkNames()
|
||||
if (this.selected === '') {
|
||||
showError(t('forms', 'Select a question type!'), { duration: 3000 })
|
||||
|
@ -206,8 +206,11 @@ export default {
|
|||
showError(t('forms', 'Cannot have the same question!'))
|
||||
} else {
|
||||
if (this.newQuizQuestion !== null & this.newQuizQuestion !== '' & (/\S/.test(this.newQuizQuestion))) {
|
||||
const response = await axios.post(generateUrl('/apps/forms/api/v1/question/'), { formId: this.form.id, type: this.selected, text: this.newQuizQuestion })
|
||||
const questionId = response.data
|
||||
|
||||
this.form.options.formQuizQuestions.push({
|
||||
id: this.nextQuizQuestionId++,
|
||||
id: questionId,
|
||||
text: this.newQuizQuestion,
|
||||
type: this.selected,
|
||||
answers: [],
|
||||
|
@ -217,6 +220,12 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
async deleteQuestion(question, index) {
|
||||
await axios.delete(generateUrl('/apps/forms/api/v1/question/{id}', { id: question.id }))
|
||||
// TODO catch Error
|
||||
this.form.options.formQuizQuestions.splice(index, 1)
|
||||
},
|
||||
|
||||
checkAnsNames(item, question) {
|
||||
this.uniqueAnsName = true
|
||||
question.answers.forEach(q => {
|
||||
|
@ -226,31 +235,30 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
removeAnswer(item, question, index) {
|
||||
item.formQuizAnswers.splice(index, 1)
|
||||
question.answers.splice(index, 1)
|
||||
},
|
||||
|
||||
addAnswer(item, question) {
|
||||
async addAnswer(item, question) {
|
||||
this.checkAnsNames(item, question)
|
||||
if (!this.uniqueAnsName) {
|
||||
showError(t('forms', 'Two answers cannot be the same!'), { duration: 3000 })
|
||||
} else {
|
||||
if (item.newQuizAnswer !== null & item.newQuizAnswer !== '' & (/\S/.test(item.newQuizAnswer))) {
|
||||
item.formQuizAnswers.push({
|
||||
id: item.nextQuizAnswerId,
|
||||
text: item.newQuizAnswer,
|
||||
})
|
||||
const response = await axios.post(generateUrl('/apps/forms/api/v1/answer/'), { formId: this.form.id, questionId: question.id, text: item.newQuizAnswer })
|
||||
const answerId = response.data
|
||||
|
||||
question.answers.push({
|
||||
id: item.nextQuizAnswerId,
|
||||
id: answerId,
|
||||
text: item.newQuizAnswer,
|
||||
})
|
||||
item.nextQuizAnswerId++
|
||||
}
|
||||
item.newQuizAnswer = ''
|
||||
}
|
||||
},
|
||||
|
||||
async deleteAnswer(question, answer, index) {
|
||||
await axios.delete(generateUrl('/apps/forms/api/v1/answer/{id}', { id: answer.id }))
|
||||
// TODO catch errors
|
||||
question.answers.splice(index, 1)
|
||||
},
|
||||
|
||||
allHaveAns() {
|
||||
this.haveAns = true
|
||||
this.form.options.formQuizQuestions.forEach(q => {
|
||||
|
|
Loading…
Reference in a new issue