Merge pull request #895 from nextcloud/validate_submission

This commit is contained in:
John Molakvoæ 2021-04-22 16:59:10 +02:00 коммит произвёл GitHub
Родитель 1cf51a7467 64ccb5a5de
Коммит 87dd08eb84
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 170 добавлений и 0 удалений

Просмотреть файл

@ -973,6 +973,11 @@ class ApiController extends OCSController {
throw new OCSForbiddenException('Already submitted');
}
// Is the submission valid
if (!$this->submissionService->validateSubmission($questions, $answers)) {
throw new OCSBadRequestException('At least one submitted answer is not valid');
}
// Create Submission
$submission = new Submission();
$submission->setFormId($formId);

Просмотреть файл

@ -26,6 +26,7 @@ namespace OCA\Forms\Service;
use DateTimeZone;
use OCA\Forms\Constants;
use OCA\Forms\Db\FormMapper;
use OCA\Forms\Db\QuestionMapper;
use OCA\Forms\Db\SubmissionMapper;
@ -240,4 +241,54 @@ class SubmissionService {
return $csv->getContent();
}
/**
* Validate all answers against the questions
* @param array $questions Array of the questions of the form
* @param array $answers Array of the submitted answers
* @return boolean If the submission is valid
*/
public function validateSubmission(array $questions, array $answers): bool {
// Check by questions
foreach ($questions as $question) {
$questionId = $question['id'];
$questionAnswered = array_key_exists($questionId, $answers);
// Check if all required questions have an answer
if ($question['isRequired'] && (!$questionAnswered || !array_filter($answers[$questionId], 'strlen'))) {
return false;
}
// Perform further checks only for answered questions
// TODO Check if date questions have valid answers
if ($questionAnswered) {
// Check if non multiple questions have not more than one answer
if ($question['type'] !== Constants::ANSWER_TYPE_MULTIPLE && count($answers[$questionId]) > 1) {
return false;
}
// Check if all answers are within the possible options
if (in_array($question['type'], Constants::ANSWER_PREDEFINED)) {
foreach ($answers[$questionId] as $answer) {
// Search corresponding option, return false if non-existent
if (array_search($answer, array_column($question['options'], 'id')) === false) {
return false;
}
}
}
}
}
// Check for excess answers
foreach ($answers as $id => $answerArray) {
// Search corresponding question, return false if not found
$questionIndex = array_search($id, array_column($questions, 'id'));
if ($questionIndex === false) {
return false;
}
}
return true;
}
}

Просмотреть файл

@ -462,4 +462,118 @@ class FilterTest extends TestCase {
return $dataExpectation;
}
// Data for validation of Submissions
public function dataValidateSubmission() {
return [
'required-not-answered' => [
// Questions
[
['id' => 1, 'type' => 'short', 'isRequired' => true]
],
// Answers
[],
// Expected Result
false
],
'required-not-answered-string' => [
// Questions
[
['id' => 1, 'type' => 'short', 'isRequired' => true]
],
// Answers
[
'1' => ['']
],
// Expected Result
false
],
'more-than-allowed' => [
// Questions
[
['id' => 1, 'type' => 'multiple_unique', 'isRequired' => false, 'options' => [
['id' => 3],
['id' => 5]
]]
],
// Answers
[
'1' => [3,5]
],
// Expected Result
false
],
'option-not-known' => [
// Questions
[
['id' => 1, 'type' => 'multiple', 'isRequired' => false, 'options' => [
['id' => 3],
['id' => 5]
]],
],
// Answers
[
'1' => [3,10]
],
// Expected Result
false
],
'question-not-known' => [
// Questions
[
['id' => 1, 'type' => 'short', 'isRequired' => false]
],
// Answers
[
'2' => ['answer']
],
// Expected Result
false
],
'full-good-submission' => [
// Questions
[
['id' => 1, 'type' => 'short', 'isRequired' => false],
['id' => 2, 'type' => 'long', 'isRequired' => true],
['id' => 3, 'type' => 'date', 'isRequired' => true],
['id' => 4, 'type' => 'datetime', 'isRequired' => false],
['id' => 5, 'type' => 'multiple', 'isRequired' => false, 'options' => [
['id' => 1],
['id' => 2]
]],
['id' => 6, 'type' => 'multiple_unique', 'isRequired' => false, 'options' => [
['id' => 3],
['id' => 4]
]],
['id' => 7, 'type' => 'dropdown', 'isRequired' => true, 'options' => [
['id' => 5],
['id' => 6]
]],
],
// Answers
[
'1' => ['answer'],
'2' => ['answerABitLonger'],
'3' => ['28. April 2021'],
'4' => ['20. April 2021 04:40'],
'5' => [1,2],
'6' => [4],
'7' => [5],
],
// Expected Result
true
]
];
}
/**
* @dataProvider dataValidateSubmission
*
* @param array $questions
* @param array $answers
* @param bool $expected
*/
public function testValidateSubmission(array $questions, array $answers, bool $expected) {
$this->assertEquals($expected, $this->submissionService->validateSubmission($questions, $answers));
}
};