Alter Database
Signed-off-by: Jonas Rittershofer <jotoeri@users.noreply.github.com>
This commit is contained in:
parent
d402107cbb
commit
03e9ff4a86
|
@ -5,7 +5,7 @@
|
|||
<name>Forms</name>
|
||||
<summary>A forms app, similar to Google Forms.</summary>
|
||||
<description>A forms app, similar to Google Forms with the possibility to restrict access (members, certain groups/users, and public).</description>
|
||||
<version>1.1.2</version>
|
||||
<version>1.2.0</version>
|
||||
<licence>agpl</licence>
|
||||
<author>Vinzenz Rosenkranz</author>
|
||||
<author>René Gieling</author>
|
||||
|
|
|
@ -33,23 +33,23 @@ return [
|
|||
|
||||
['name' => 'page#goto_form', 'url' => '/{hash}', 'verb' => 'GET'],
|
||||
|
||||
['name' => 'page#insert_vote', 'url' => '/insert/vote', 'verb' => 'POST'],
|
||||
['name' => 'page#insert_submission', 'url' => '/insert/submission', 'verb' => 'POST'],
|
||||
['name' => 'page#search', 'url' => '/search', 'verb' => 'POST'],
|
||||
['name' => 'page#get_display_name', 'url' => '/get/displayname', 'verb' => 'POST'],
|
||||
|
||||
['name' => 'api#write_form', 'url' => '/write/form', 'verb' => 'POST'],
|
||||
['name' => 'api#get_form', 'url' => '/get/form/{formIdOrHash}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_full_form', 'url' => '/get/fullform/{formIdOrHash}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_options', 'url' => '/get/options/{formId}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_shares', 'url' => '/get/shares/{formId}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_event', 'url' => '/get/event/{formId}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_form', 'url' => '/get/form/{formId}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_forms', 'url' => '/get/forms', 'verb' => 'GET'],
|
||||
|
||||
['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' => 'api#newOption', 'url' => 'api/v1/option/', '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'],
|
||||
|
|
|
@ -8,7 +8,7 @@ function sendDataToServer(survey) {
|
|||
form.userId = 'anon_' + Date.now() + '_' + Math.floor(Math.random() * 10000)
|
||||
}
|
||||
form.questions = questions;
|
||||
$.post(OC.generateUrl('apps/forms/insert/vote'), form)
|
||||
$.post(OC.generateUrl('apps/forms/insert/submission'), form)
|
||||
.then((response) => {
|
||||
}, (error) => {
|
||||
/* eslint-disable-next-line no-console */
|
||||
|
@ -34,7 +34,7 @@ function cssUpdate(survey, options){
|
|||
$(document).ready(function () {
|
||||
var formJSON = $('#surveyContainer').attr('form')
|
||||
var questionJSON = $('#surveyContainer').attr('questions')
|
||||
|
||||
|
||||
form = JSON.parse(formJSON)
|
||||
questions = JSON.parse(questionJSON)
|
||||
|
||||
|
@ -45,11 +45,11 @@ $(document).ready(function () {
|
|||
};
|
||||
|
||||
questions.forEach(q => {
|
||||
var ans = []
|
||||
q.answers.forEach(a => {
|
||||
ans.push(a.text);
|
||||
var qChoices = []
|
||||
q.options.forEach(o => {
|
||||
qChoices.push(o.text);
|
||||
});
|
||||
surveyJSON.questions.push({type: q.type, name: q.text, choices: ans, isRequired: 'true'});
|
||||
surveyJSON.questions.push({type: q.type, name: q.text, choices: qChoices, isRequired: 'true'});
|
||||
});
|
||||
|
||||
$('#surveyContainer').Survey({
|
|
@ -41,14 +41,17 @@ use OCP\IUser;
|
|||
use OCP\IUserManager;
|
||||
use OCP\Security\ISecureRandom;
|
||||
|
||||
use OCA\Forms\Db\Event;
|
||||
use OCA\Forms\Db\EventMapper;
|
||||
use OCA\Forms\Db\VoteMapper;
|
||||
use OCA\Forms\Db\Form;
|
||||
use OCA\Forms\Db\FormMapper;
|
||||
use OCA\Forms\Db\Submission;
|
||||
use OCA\Forms\Db\SubmissionMapper;
|
||||
use OCA\Forms\Db\Answer;
|
||||
use OCA\Forms\Db\AnswerMapper;
|
||||
|
||||
use OCA\Forms\Db\Question;
|
||||
use OCA\Forms\Db\QuestionMapper;
|
||||
use OCA\Forms\Db\Answer;
|
||||
use OCA\Forms\Db\AnswerMapper;
|
||||
use OCA\Forms\Db\Option;
|
||||
use OCA\Forms\Db\OptionMapper;
|
||||
|
||||
use OCP\Util;
|
||||
|
||||
|
@ -56,10 +59,11 @@ class ApiController extends Controller {
|
|||
|
||||
private $groupManager;
|
||||
private $userManager;
|
||||
private $eventMapper;
|
||||
private $voteMapper;
|
||||
private $questionMapper;
|
||||
private $formMapper;
|
||||
private $submissionMapper;
|
||||
private $answerMapper;
|
||||
private $questionMapper;
|
||||
private $optionMapper;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
@ -74,10 +78,11 @@ class ApiController extends Controller {
|
|||
* @param IRequest $request
|
||||
* @param IUserManager $userManager
|
||||
* @param string $userId
|
||||
* @param EventMapper $eventMapper
|
||||
* @param VoteMapper $voteMapper
|
||||
* @param QuestionMapper $questionMapper
|
||||
* @param FormMapper $formMapper
|
||||
* @param SubmissionMapper $submissionMapper
|
||||
* @param AnswerMapper $answerMapper
|
||||
* @param QuestionMapper $questionMapper
|
||||
* @param OptionMapper $optionMapper
|
||||
*/
|
||||
public function __construct(
|
||||
$appName,
|
||||
|
@ -85,20 +90,22 @@ class ApiController extends Controller {
|
|||
IRequest $request,
|
||||
IUserManager $userManager,
|
||||
$userId,
|
||||
EventMapper $eventMapper,
|
||||
VoteMapper $voteMapper,
|
||||
QuestionMapper $questionMapper,
|
||||
FormMapper $formMapper,
|
||||
SubmissionMapper $submissionMapper,
|
||||
AnswerMapper $answerMapper,
|
||||
QuestionMapper $questionMapper,
|
||||
OptionMapper $optionMapper,
|
||||
ILogger $logger
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->userId = $userId;
|
||||
$this->groupManager = $groupManager;
|
||||
$this->userManager = $userManager;
|
||||
$this->eventMapper = $eventMapper;
|
||||
$this->voteMapper = $voteMapper;
|
||||
$this->questionMapper = $questionMapper;
|
||||
$this->formMapper = $formMapper;
|
||||
$this->submissionMapper = $submissionMapper;
|
||||
$this->answerMapper = $answerMapper;
|
||||
$this->questionMapper = $questionMapper;
|
||||
$this->optionMapper = $optionMapper;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
@ -108,8 +115,8 @@ class ApiController extends Controller {
|
|||
* @param string $item
|
||||
* @return Array
|
||||
*/
|
||||
private function convertAccessList($item) {
|
||||
$split = array();
|
||||
private function convertAccessList($item) : array {
|
||||
$split = [];
|
||||
if (strpos($item, 'user_') === 0) {
|
||||
$user = $this->userManager->get(substr($item, 5));
|
||||
$split = [
|
||||
|
@ -172,11 +179,11 @@ class ApiController extends Controller {
|
|||
|
||||
/**
|
||||
* Set the access right of the current user for the form
|
||||
* @param Array $event
|
||||
* @param Array $form
|
||||
* @param Array $shares
|
||||
* @return String
|
||||
*/
|
||||
private function grantAccessAs($event, $shares) {
|
||||
private function grantAccessAs($form, $shares) {
|
||||
if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
|
||||
$currentUser = '';
|
||||
} else {
|
||||
|
@ -185,13 +192,13 @@ class ApiController extends Controller {
|
|||
|
||||
$grantAccessAs = 'none';
|
||||
|
||||
if ($event['owner'] === $currentUser) {
|
||||
if ($form['ownerId'] === $currentUser) {
|
||||
$grantAccessAs = 'owner';
|
||||
} elseif ($event['access'] === 'public') {
|
||||
} elseif ($form['access'] === 'public') {
|
||||
$grantAccessAs = 'public';
|
||||
} elseif ($event['access'] === 'registered' && \OC::$server->getUserSession()->getUser() instanceof IUser) {
|
||||
} elseif ($form['access'] === 'registered' && \OC::$server->getUserSession()->getUser() instanceof IUser) {
|
||||
$grantAccessAs = 'registered';
|
||||
} elseif ($event['access'] === 'hidden' && ($event['owner'] === \OC::$server->getUserSession()->getUser())) {
|
||||
} elseif ($form['access'] === 'hidden' && ($form['ownerId'] === \OC::$server->getUserSession()->getUser())) {
|
||||
$grantAccessAs = 'hidden';
|
||||
} elseif ($this->checkUserAccess($shares)) {
|
||||
$grantAccessAs = 'userInvitation';
|
||||
|
@ -210,11 +217,11 @@ class ApiController extends Controller {
|
|||
* @param Integer $formId
|
||||
* @return Array
|
||||
*/
|
||||
public function getEvent($formId) {
|
||||
public function getForm($formId) {
|
||||
|
||||
$data = array();
|
||||
try {
|
||||
$data = $this->eventMapper->find($formId)->read();
|
||||
$data = $this->formMapper->find($formId)->read();
|
||||
} catch (DoesNotExistException $e) {
|
||||
// return silently
|
||||
} finally {
|
||||
|
@ -234,7 +241,7 @@ class ApiController extends Controller {
|
|||
$accessList = array();
|
||||
|
||||
try {
|
||||
$form = $this->eventMapper->find($formId);
|
||||
$form = $this->formMapper->find($formId);
|
||||
if (!strpos('|public|hidden|registered', $form->getAccess())) {
|
||||
$accessList = explode(';', $form->getAccess());
|
||||
$accessList = array_filter($accessList);
|
||||
|
@ -248,14 +255,14 @@ class ApiController extends Controller {
|
|||
|
||||
}
|
||||
|
||||
public function getQuestions($formId) {
|
||||
$questionList = array();
|
||||
public function getQuestions($formId) : array {
|
||||
$questionList = [];
|
||||
try{
|
||||
$questions = $this->questionMapper->findByForm($formId);
|
||||
foreach ($questions as $questionElement) {
|
||||
$temp = $questionElement->read();
|
||||
$temp['answers'] = $this->getAnswers($formId, $temp['id']);
|
||||
$questionList[] = $temp;
|
||||
$questionEntities = $this->questionMapper->findByForm($formId);
|
||||
foreach ($questionEntities as $questionEntity) {
|
||||
$question = $questionEntity->read();
|
||||
$question['options'] = $this->getOptions($question['id']);
|
||||
$questionList[] = $question;
|
||||
}
|
||||
|
||||
} catch (DoesNotExistException $e) {
|
||||
|
@ -265,18 +272,18 @@ class ApiController extends Controller {
|
|||
}
|
||||
}
|
||||
|
||||
public function getAnswers($formId, $questionId) {
|
||||
$answerList = array();
|
||||
public function getOptions($questionId) : array {
|
||||
$optionList = [];
|
||||
try{
|
||||
$answers = $this->answerMapper->findByForm($formId, $questionId);
|
||||
foreach ($answers as $answerElement) {
|
||||
$answerList[] = $answerElement->read();
|
||||
$optionEntities = $this->optionMapper->findByQuestion($questionId);
|
||||
foreach ($optionEntities as $optionEntity) {
|
||||
$optionList[] = $optionEntity->read();
|
||||
}
|
||||
|
||||
} catch (DoesNotExistException $e) {
|
||||
//handle silently
|
||||
}finally{
|
||||
return $answerList;
|
||||
return $optionList;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,7 +293,7 @@ class ApiController extends Controller {
|
|||
* @param String $formIdOrHash form id or hash
|
||||
* @return Array
|
||||
*/
|
||||
public function getForm($formIdOrHash) {
|
||||
public function getFullForm($formIdOrHash) {
|
||||
|
||||
if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
|
||||
$currentUser = '';
|
||||
|
@ -299,32 +306,30 @@ class ApiController extends Controller {
|
|||
try {
|
||||
|
||||
if (is_numeric($formIdOrHash)) {
|
||||
$formId = $this->eventMapper->find(intval($formIdOrHash))->id;
|
||||
$formId = $this->formMapper->find(intval($formIdOrHash))->id;
|
||||
$result = 'foundById';
|
||||
} else {
|
||||
$formId = $this->eventMapper->findByHash($formIdOrHash)->id;
|
||||
$formId = $this->formMapper->findByHash($formIdOrHash)->id;
|
||||
$result = 'foundByHash';
|
||||
}
|
||||
|
||||
$event = $this->getEvent($formId);
|
||||
$shares = $this->getShares($event['id']);
|
||||
$form = $this->getForm($formId);
|
||||
$shares = $this->getShares($form['id']);
|
||||
|
||||
if ($event['owner'] !== $currentUser && !$this->groupManager->isAdmin($currentUser)) {
|
||||
if ($form['ownerId'] !== $currentUser && !$this->groupManager->isAdmin($currentUser)) {
|
||||
$mode = 'create';
|
||||
} else {
|
||||
$mode = 'edit';
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $event['id'],
|
||||
'id' => $form['id'],
|
||||
'result' => $result,
|
||||
'grantedAs' => $this->grantAccessAs($event, $shares),
|
||||
'grantedAs' => $this->grantAccessAs($form, $shares),
|
||||
'mode' => $mode,
|
||||
'event' => $event,
|
||||
'form' => $form,
|
||||
'shares' => $shares,
|
||||
'options' => [
|
||||
'formQuizQuestions' => $this->getQuestions($event['id'])
|
||||
]
|
||||
'questions' => $this->getQuestions($form['id']),
|
||||
];
|
||||
} catch (DoesNotExistException $e) {
|
||||
$data['form'] = ['result' => 'notFound'];
|
||||
|
@ -345,21 +350,20 @@ class ApiController extends Controller {
|
|||
}
|
||||
|
||||
try {
|
||||
$events = $this->eventMapper->findAll();
|
||||
$forms = $this->formMapper->findAll();
|
||||
} catch (DoesNotExistException $e) {
|
||||
return new DataResponse($e, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
$eventsList = array();
|
||||
|
||||
foreach ($events as $eventElement) {
|
||||
$event = $this->getForm($eventElement->id);
|
||||
//if ($event['grantedAs'] !== 'none') {
|
||||
$eventsList[] = $event;
|
||||
$formsList = array();
|
||||
foreach ($forms as $formElement) {
|
||||
$form = $this->getFullForm($formElement->id);
|
||||
//if ($form['grantedAs'] !== 'none') {
|
||||
$formsList[] = $form;
|
||||
//}
|
||||
}
|
||||
|
||||
return new DataResponse($eventsList, Http::STATUS_OK);
|
||||
return new DataResponse($formsList, Http::STATUS_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -370,17 +374,16 @@ class ApiController extends Controller {
|
|||
*/
|
||||
public function deleteForm(int $id) {
|
||||
try {
|
||||
$formToDelete = $this->eventMapper->find($id);
|
||||
$formToDelete = $this->formMapper->find($id);
|
||||
} catch (DoesNotExistException $e) {
|
||||
return new Http\JSONResponse([], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
if ($this->userId !== $formToDelete->getOwner() && !$this->groupManager->isAdmin($this->userId)) {
|
||||
if ($this->userId !== $formToDelete->getOwnerId() && !$this->groupManager->isAdmin($this->userId)) {
|
||||
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
$this->voteMapper->deleteByForm($id);
|
||||
$this->submissionMapper->deleteByForm($id);
|
||||
$this->questionMapper->deleteByForm($id);
|
||||
$this->answerMapper->deleteByForm($id);
|
||||
$this->eventMapper->delete($formToDelete);
|
||||
$this->formMapper->delete($formToDelete);
|
||||
return new DataResponse(array(
|
||||
'id' => $id,
|
||||
'action' => 'deleted'
|
||||
|
@ -391,30 +394,30 @@ class ApiController extends Controller {
|
|||
/**
|
||||
* Write form (create/update)
|
||||
* @NoAdminRequired
|
||||
* @param Array $event
|
||||
* @param Array $form
|
||||
* @param Array $options
|
||||
* @param Array $shares
|
||||
* @param String $mode
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function writeForm($event, $options, $shares, $mode) {
|
||||
public function writeForm($form, $questions, $shares, $mode) {
|
||||
if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
|
||||
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
|
||||
} else {
|
||||
$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
|
||||
$AdminAccess = $this->groupManager->isAdmin($currentUser);
|
||||
$adminAccess = $this->groupManager->isAdmin($currentUser);
|
||||
}
|
||||
|
||||
$newEvent = new Event();
|
||||
$newForm = new Form();
|
||||
|
||||
// Set the configuration options entered by the user
|
||||
$newEvent->setTitle($event['title']);
|
||||
$newEvent->setDescription($event['description']);
|
||||
$newForm->setTitle($form['title']);
|
||||
$newForm->setDescription($form['description']);
|
||||
|
||||
$newEvent->setIsAnonymous($event['isAnonymous']);
|
||||
$newEvent->setUnique($event['unique']);
|
||||
$newForm->setIsAnonymous($form['isAnonymous']);
|
||||
$newForm->setSubmitOnce($form['submitOnce']);
|
||||
|
||||
if ($event['access'] === 'select') {
|
||||
if ($form['access'] === 'select') {
|
||||
$shareAccess = '';
|
||||
foreach ($shares as $shareElement) {
|
||||
if ($shareElement['type'] === 'user') {
|
||||
|
@ -423,50 +426,50 @@ class ApiController extends Controller {
|
|||
$shareAccess = $shareAccess . 'group_' . $shareElement['id'] . ';';
|
||||
}
|
||||
}
|
||||
$newEvent->setAccess(rtrim($shareAccess, ';'));
|
||||
$newForm->setAccess(rtrim($shareAccess, ';'));
|
||||
} else {
|
||||
$newEvent->setAccess($event['access']);
|
||||
$newForm->setAccess($form['access']);
|
||||
}
|
||||
|
||||
if ($event['expiration']) {
|
||||
$newEvent->setExpire(date('Y-m-d H:i:s', strtotime($event['expirationDate'])));
|
||||
if ($form['expires']) {
|
||||
$newForm->setExpirationDate(date('Y-m-d H:i:s', strtotime($form['expirationDate'])));
|
||||
} else {
|
||||
$newEvent->setExpire(null);
|
||||
$newForm->setExpirationDate(null);
|
||||
}
|
||||
|
||||
if ($mode === 'edit') {
|
||||
// Edit existing form
|
||||
$oldForm = $this->eventMapper->findByHash($event['hash']);
|
||||
$oldForm = $this->formMapper->findByHash($form['hash']);
|
||||
|
||||
// Check if current user is allowed to edit existing form
|
||||
if ($oldForm->getOwner() !== $currentUser && !$AdminAccess) {
|
||||
if ($oldForm->getOwnerId() !== $currentUser && !$adminAccess) {
|
||||
// If current user is not owner of existing form deny access
|
||||
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// else take owner, hash and id of existing form
|
||||
$newEvent->setOwner($oldForm->getOwner());
|
||||
$newEvent->setHash($oldForm->getHash());
|
||||
$newEvent->setId($oldForm->getId());
|
||||
$this->eventMapper->update($newEvent);
|
||||
$newForm->setOwnerId($oldForm->getOwnerId());
|
||||
$newForm->setHash($oldForm->getHash());
|
||||
$newForm->setId($oldForm->getId());
|
||||
$this->formMapper->update($newForm);
|
||||
|
||||
} elseif ($mode === 'create') {
|
||||
// Create new form
|
||||
// Define current user as owner, set new creation date and create a new hash
|
||||
$newEvent->setOwner($currentUser);
|
||||
$newEvent->setCreated(date('Y-m-d H:i:s'));
|
||||
$newEvent->setHash(\OC::$server->getSecureRandom()->generate(
|
||||
$newForm->setOwnerId($currentUser);
|
||||
$newForm->setCreated(date('Y-m-d H:i:s'));
|
||||
$newForm->setHash(\OC::$server->getSecureRandom()->generate(
|
||||
16,
|
||||
ISecureRandom::CHAR_DIGITS .
|
||||
ISecureRandom::CHAR_LOWER .
|
||||
ISecureRandom::CHAR_UPPER
|
||||
));
|
||||
$newEvent = $this->eventMapper->insert($newEvent);
|
||||
$newForm = $this->formMapper->insert($newForm);
|
||||
}
|
||||
|
||||
return new DataResponse(array(
|
||||
'id' => $newEvent->getId(),
|
||||
'hash' => $newEvent->getHash()
|
||||
'id' => $newForm->getId(),
|
||||
'hash' => $newForm->getHash()
|
||||
), Http::STATUS_OK);
|
||||
|
||||
}
|
||||
|
@ -475,22 +478,22 @@ class ApiController extends Controller {
|
|||
* @NoAdminRequired
|
||||
*/
|
||||
public function newForm(): Http\JSONResponse {
|
||||
$event = new Event();
|
||||
$form = new Form();
|
||||
|
||||
$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
|
||||
$event->setOwner($currentUser);
|
||||
$event->setCreated(date('Y-m-d H:i:s'));
|
||||
$event->setHash(\OC::$server->getSecureRandom()->generate(
|
||||
$form->setOwnerId($currentUser);
|
||||
$form->setCreated(date('Y-m-d H:i:s'));
|
||||
$form->setHash(\OC::$server->getSecureRandom()->generate(
|
||||
16,
|
||||
ISecureRandom::CHAR_HUMAN_READABLE
|
||||
));
|
||||
$event->setTitle('New form');
|
||||
$event->setDescription('');
|
||||
$event->setAccess('public');
|
||||
$form->setTitle('New form');
|
||||
$form->setDescription('');
|
||||
$form->setAccess('public');
|
||||
|
||||
$this->eventMapper->insert($event);
|
||||
$this->formMapper->insert($form);
|
||||
|
||||
return new Http\JSONResponse($this->getForm($event->getHash()));
|
||||
return new Http\JSONResponse($this->getFullForm($form->getHash()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -504,13 +507,13 @@ class ApiController extends Controller {
|
|||
]);
|
||||
|
||||
try {
|
||||
$form = $this->eventMapper->find($formId);
|
||||
$form = $this->formMapper->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) {
|
||||
if ($form->getOwnerId() !== $this->userId) {
|
||||
$this->logger->debug('This form is not owned by the current user');
|
||||
return new Http\JSONResponse([], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
@ -518,8 +521,8 @@ class ApiController extends Controller {
|
|||
$question = new Question();
|
||||
|
||||
$question->setFormId($formId);
|
||||
$question->setFormQuestionType($type);
|
||||
$question->setFormQuestionText($text);
|
||||
$question->setType($type);
|
||||
$question->setText($text);
|
||||
|
||||
$question = $this->questionMapper->insert($question);
|
||||
|
||||
|
@ -536,18 +539,18 @@ class ApiController extends Controller {
|
|||
|
||||
try {
|
||||
$question = $this->questionMapper->findById($id);
|
||||
$form = $this->eventMapper->find($question->getFormId());
|
||||
$form = $this->formMapper->find($question->getFormId());
|
||||
} catch (IMapperException $e) {
|
||||
$this->logger->debug('Could not find form or question of this answer');
|
||||
$this->logger->debug('Could not find form or question');
|
||||
return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($form->getOwner() !== $this->userId) {
|
||||
if ($form->getOwnerId() !== $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->optionMapper->deleteByQuestion($id);
|
||||
$this->questionMapper->delete($question);
|
||||
|
||||
return new Http\JSONResponse($id);
|
||||
|
@ -556,64 +559,64 @@ class ApiController extends Controller {
|
|||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function newAnswer(int $formId, int $questionId, string $text): Http\JSONResponse {
|
||||
$this->logger->debug('Adding new answer: formId: {formId}, questoinId: {questionId}, text: {text}', [
|
||||
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,
|
||||
'questionId' => $questionId,
|
||||
'text' => $text,
|
||||
]);
|
||||
|
||||
try {
|
||||
$form = $this->eventMapper->find($formId);
|
||||
$form = $this->formMapper->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');
|
||||
$this->logger->debug('Could not find form or question so option can\'t be added');
|
||||
return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($form->getOwner() !== $this->userId) {
|
||||
if ($form->getOwnerId() !== $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');
|
||||
$this->logger->debug('This question is not part of the current form');
|
||||
return new Http\JSONResponse([], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
$answer = new Answer();
|
||||
$option = new Option();
|
||||
|
||||
$answer->setFormId($formId);
|
||||
$answer->setQuestionId($questionId);
|
||||
$answer->setText($text);
|
||||
$option->setQuestionId($questionId);
|
||||
$option->setText($text);
|
||||
|
||||
$answer = $this->answerMapper->insert($answer);
|
||||
$option = $this->optionMapper->insert($option);
|
||||
|
||||
return new Http\JSONResponse($answer->getId());
|
||||
return new Http\JSONResponse($option->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function deleteAnswer(int $id): Http\JSONResponse {
|
||||
$this->logger->debug('Deleting answer: {id}', [
|
||||
public function deleteOption(int $id): Http\JSONResponse {
|
||||
$this->logger->debug('Deleting option: {id}', [
|
||||
'id' => $id
|
||||
]);
|
||||
|
||||
try {
|
||||
$answer = $this->answerMapper->findById($id);
|
||||
$form = $this->eventMapper->find($answer->getFormId());
|
||||
$option = $this->optionMapper->findById($id);
|
||||
$question = $this->questionMapper->findById($option->getQuestionId());
|
||||
$form = $this->formMapper->find($question->getFormId());
|
||||
} catch (IMapperException $e) {
|
||||
$this->logger->debug('Could not find form or answer');
|
||||
$this->logger->debug('Could not find form or option');
|
||||
return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($form->getOwner() !== $this->userId) {
|
||||
if ($form->getOwnerId() !== $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);
|
||||
$this->optionMapper->delete($option);
|
||||
|
||||
//TODO useful response
|
||||
return new Http\JSONResponse($id);
|
||||
|
@ -624,20 +627,30 @@ class ApiController extends Controller {
|
|||
*/
|
||||
public function getSubmissions(string $hash): Http\JSONResponse {
|
||||
try {
|
||||
$form = $this->eventMapper->findByHash($hash);
|
||||
$form = $this->formMapper->findByHash($hash);
|
||||
} catch (IMapperException $e) {
|
||||
return new Http\JSONResponse([], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($form->getOwner() !== $this->userId) {
|
||||
if ($form->getOwnerId() !== $this->userId) {
|
||||
return new Http\JSONResponse([], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
$votes = $this->voteMapper->findByForm($form->getId());
|
||||
|
||||
$result = [];
|
||||
foreach ($votes as $vote) {
|
||||
$result[] = $vote->read();
|
||||
$submissionList = $this->submissionMapper->findByForm($form->getId());
|
||||
foreach ($submissionList as $submissionEntity) {
|
||||
$answerList = $this->answerMapper->findBySubmission($submissionEntity->id);
|
||||
foreach ($answerList as $answerEntity) {
|
||||
$answer = $answerEntity->read();
|
||||
//Temporary Adapt Data to be usable by old Results-View
|
||||
$answer['userId'] = $submissionEntity->getUserId();
|
||||
|
||||
$question = $this->questionMapper->findById($answer['questionId']);
|
||||
$answer['questionText'] = $question->getText();
|
||||
$answer['questionType'] = $question->getType();
|
||||
|
||||
$result[] = $answer;
|
||||
}
|
||||
}
|
||||
|
||||
return new Http\JSONResponse($result);
|
||||
|
|
|
@ -29,12 +29,14 @@
|
|||
namespace OCA\Forms\Controller;
|
||||
|
||||
use OCA\Forms\AppInfo\Application;
|
||||
use OCA\Forms\Db\Event;
|
||||
use OCA\Forms\Db\EventMapper;
|
||||
use OCA\Forms\Db\Vote;
|
||||
use OCA\Forms\Db\VoteMapper;
|
||||
|
||||
use OCA\Forms\Db\Form;
|
||||
use OCA\Forms\Db\FormMapper;
|
||||
use OCA\Forms\Db\Submission;
|
||||
use OCA\Forms\Db\SubmissionMapper;
|
||||
use OCA\Forms\Db\Answer;
|
||||
use OCA\Forms\Db\AnswerMapper;
|
||||
|
||||
use OCA\Forms\Db\OptionMapper;
|
||||
use OCA\Forms\Db\QuestionMapper;
|
||||
|
||||
use OCP\AppFramework\Controller;
|
||||
|
@ -53,11 +55,12 @@ use OCP\Util;
|
|||
class PageController extends Controller {
|
||||
|
||||
private $userId;
|
||||
private $eventMapper;
|
||||
private $voteMapper;
|
||||
private $formMapper;
|
||||
private $submissionMapper;
|
||||
private $answerMapper;
|
||||
|
||||
private $questionMapper;
|
||||
private $answerMapper;
|
||||
private $optionMapper;
|
||||
|
||||
private $urlGenerator;
|
||||
private $userMgr;
|
||||
|
@ -69,21 +72,24 @@ class PageController extends Controller {
|
|||
IGroupManager $groupManager,
|
||||
IURLGenerator $urlGenerator,
|
||||
$userId,
|
||||
EventMapper $eventMapper,
|
||||
FormMapper $formMapper,
|
||||
|
||||
QuestionMapper $questionMapper,
|
||||
AnswerMapper $answerMapper,
|
||||
VoteMapper $VoteMapper
|
||||
OptionMapper $optionMapper,
|
||||
SubmissionMapper $SubmissionMapper,
|
||||
AnswerMapper $AnswerMapper
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
$this->userMgr = $userMgr;
|
||||
$this->groupManager = $groupManager;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->userId = $userId;
|
||||
$this->eventMapper = $eventMapper;
|
||||
$this->formMapper = $formMapper;
|
||||
|
||||
$this->questionMapper = $questionMapper;
|
||||
$this->answerMapper = $answerMapper;
|
||||
$this->voteMapper = $VoteMapper;
|
||||
$this->optionMapper = $optionMapper;
|
||||
$this->submissionMapper = $SubmissionMapper;
|
||||
$this->answerMapper = $AnswerMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,15 +161,15 @@ class PageController extends Controller {
|
|||
*/
|
||||
public function gotoForm($hash): ?TemplateResponse {
|
||||
try {
|
||||
$form = $this->eventMapper->findByHash($hash);
|
||||
$form = $this->formMapper->findByHash($hash);
|
||||
} catch (DoesNotExistException $e) {
|
||||
return new TemplateResponse('forms', 'no.acc.tmpl', []);
|
||||
}
|
||||
|
||||
if ($form->getExpire() === null) {
|
||||
if ($form->getExpirationDate() === null) {
|
||||
$expired = false;
|
||||
} else {
|
||||
$expired = time() > strtotime($form->getExpire());
|
||||
$expired = time() > strtotime($form->getExpirationDate());
|
||||
}
|
||||
|
||||
if ($expired) {
|
||||
|
@ -172,7 +178,7 @@ class PageController extends Controller {
|
|||
|
||||
if ($this->hasUserAccess($form)) {
|
||||
$renderAs = $this->userId !== null ? 'user' : 'public';
|
||||
$res = new TemplateResponse('forms', 'vote.tmpl', [
|
||||
$res = new TemplateResponse('forms', 'submit.tmpl', [
|
||||
'form' => $form,
|
||||
'questions' => $this->getQuestions($form->getId()),
|
||||
], $renderAs);
|
||||
|
@ -192,11 +198,11 @@ class PageController extends Controller {
|
|||
public function getQuestions(int $formId): array {
|
||||
$questionList = [];
|
||||
try{
|
||||
$questions = $this->questionMapper->findByForm($formId);
|
||||
foreach ($questions as $questionElement) {
|
||||
$temp = $questionElement->read();
|
||||
$temp['answers'] = $this->getAnswers($formId, $temp['id']);
|
||||
$questionList[] = $temp;
|
||||
$questionEntities = $this->questionMapper->findByForm($formId);
|
||||
foreach ($questionEntities as $questionEntity) {
|
||||
$question = $questionEntity->read();
|
||||
$question['options'] = $this->getOptions($question['id']);
|
||||
$questionList[] = $question;
|
||||
}
|
||||
} catch (DoesNotExistException $e) {
|
||||
//handle silently
|
||||
|
@ -208,20 +214,20 @@ class PageController extends Controller {
|
|||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function getAnswers(int $formId, int $questionId): array {
|
||||
$answerList = [];
|
||||
public function getOptions(int $questionId): array {
|
||||
$optionList = [];
|
||||
|
||||
try{
|
||||
$answers = $this->answerMapper->findByForm($formId, $questionId);
|
||||
foreach ($answers as $answerElement) {
|
||||
$answerList[] = $answerElement->read();
|
||||
$optionEntities = $this->optionMapper->findByQuestion($questionId);
|
||||
foreach ($optionEntities as $optionEntity) {
|
||||
$optionList[] = $optionEntity->read();
|
||||
}
|
||||
|
||||
} catch (DoesNotExistException $e) {
|
||||
//handle silently
|
||||
}
|
||||
|
||||
return $answerList;
|
||||
return $optionList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,14 +236,14 @@ class PageController extends Controller {
|
|||
* @return TemplateResponse|RedirectResponse
|
||||
*/
|
||||
public function deleteForm($formId) {
|
||||
$formToDelete = $this->eventMapper->find($formId);
|
||||
if ($this->userId !== $formToDelete->getOwner() && !$this->groupManager->isAdmin($this->userId)) {
|
||||
$formToDelete = $this->formMapper->find($formId);
|
||||
if ($this->userId !== $formToDelete->getOwnerId() && !$this->groupManager->isAdmin($this->userId)) {
|
||||
return new TemplateResponse('forms', 'no.delete.tmpl');
|
||||
}
|
||||
$form = new Event();
|
||||
$form = new Form();
|
||||
$form->setId($formId);
|
||||
$this->voteMapper->deleteByForm($formId);
|
||||
$this->eventMapper->delete($form);
|
||||
$this->submissionMapper->deleteByForm($formId);
|
||||
$this->formMapper->delete($form);
|
||||
$url = $this->urlGenerator->linkToRoute('forms.page.index');
|
||||
return new RedirectResponse($url);
|
||||
}
|
||||
|
@ -247,51 +253,47 @@ class PageController extends Controller {
|
|||
* @PublicPage
|
||||
* @param int $formId
|
||||
* @param string $userId
|
||||
* @param string $answers
|
||||
* @param string $options question id
|
||||
* @param bool $changed
|
||||
* @param array $answers
|
||||
* @param array $questions
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function insertVote($id, $userId, $answers, $questions) {
|
||||
public function insertSubmission($id, $userId, $answers, $questions) {
|
||||
|
||||
$form = $this->eventMapper->find($id);
|
||||
$count_answers = count($answers);
|
||||
$count = 1;
|
||||
$form = $this->formMapper->find($id);
|
||||
$anonID = "anon-user-". hash('md5', (time() + rand()));
|
||||
|
||||
for ($i = 0; $i < $count_answers; $i++) {
|
||||
if($questions[$i]['type'] === "checkbox"){
|
||||
foreach (($answers[$questions[$i]['text']]) as $value) {
|
||||
$vote = new Vote();
|
||||
$vote->setFormId($id);
|
||||
if($form->getIsAnonymous()){
|
||||
$vote->setUserId($anonID);
|
||||
//Insert Submission
|
||||
$submission = new Submission();
|
||||
$submission->setFormId($id);
|
||||
if($form->getIsAnonymous()){
|
||||
$submission->setUserId($anonID);
|
||||
|
||||
}else{
|
||||
$vote->setUserId($userId);
|
||||
}
|
||||
$vote->setVoteOptionText(htmlspecialchars($questions[$i]['text']));
|
||||
$vote->setVoteAnswer($value);
|
||||
$vote->setVoteOptionId($count);
|
||||
$vote->setVoteOptionType($questions[$i]['type']);
|
||||
$this->voteMapper->insert($vote);
|
||||
}else{
|
||||
$submission->setUserId($userId);
|
||||
}
|
||||
$submission->setTimestamp(date('Y-m-d H:i:s'));
|
||||
$this->submissionMapper->insert($submission);
|
||||
$submissionId = $submission->getId();
|
||||
|
||||
//Insert Answers
|
||||
foreach($questions as $question) {
|
||||
if($question['type'] === "checkbox"){
|
||||
foreach(($answers[$question['text']]) as $ansText) {
|
||||
$answer = new Answer();
|
||||
$answer->setSubmissionId($submissionId);
|
||||
$answer->setQuestionId($question['id']);
|
||||
$answer->setText($ansText);
|
||||
$this->answerMapper->insert($answer);
|
||||
}
|
||||
$count++;
|
||||
} else {
|
||||
$vote = new Vote();
|
||||
$vote->setFormId($id);
|
||||
if($form->getIsAnonymous()){
|
||||
$vote->setUserId($anonID);
|
||||
}else{
|
||||
$vote->setUserId($userId);
|
||||
}
|
||||
$vote->setVoteOptionText(htmlspecialchars($questions[$i]['text']));
|
||||
$vote->setVoteAnswer($answers[$questions[$i]['text']]);
|
||||
$vote->setVoteOptionId($count++);
|
||||
$vote->setVoteOptionType($questions[$i]['type']);
|
||||
$this->voteMapper->insert($vote);
|
||||
$answer = new Answer();
|
||||
$answer->setSubmissionId($submissionId);
|
||||
$answer->setQuestionId($question['id']);
|
||||
$answer->setText($answers[$question['text']]);
|
||||
$this->answerMapper->insert($answer);
|
||||
}
|
||||
}
|
||||
|
||||
$hash = $form->getHash();
|
||||
$url = $this->urlGenerator->linkToRoute('forms.page.goto_form', ['hash' => $hash]);
|
||||
return new RedirectResponse($url);
|
||||
|
@ -379,12 +381,12 @@ class PageController extends Controller {
|
|||
/**
|
||||
* Check if user has access to this form
|
||||
*
|
||||
* @param Event $form
|
||||
* @param Form $form
|
||||
* @return bool
|
||||
*/
|
||||
private function hasUserAccess($form) {
|
||||
$access = $form->getAccess();
|
||||
$owner = $form->getOwner();
|
||||
$ownerId = $form->getOwnerId();
|
||||
if ($access === 'public' || $access === 'hidden') {
|
||||
return true;
|
||||
}
|
||||
|
@ -392,8 +394,8 @@ class PageController extends Controller {
|
|||
return false;
|
||||
}
|
||||
if ($access === 'registered') {
|
||||
if ($form->getUnique()) {
|
||||
$participants = $this->voteMapper->findParticipantsByForm($form->getId());
|
||||
if ($form->getSubmitOnce()) {
|
||||
$participants = $this->submissionMapper->findParticipantsByForm($form->getId());
|
||||
foreach($participants as $participant) {
|
||||
// Don't allow access if user has already taken part
|
||||
if ($participant->getUserId() === $this->userId) return false;
|
||||
|
@ -401,7 +403,7 @@ class PageController extends Controller {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if ($owner === $this->userId) {
|
||||
if ($ownerId === $this->userId) {
|
||||
return true;
|
||||
}
|
||||
Util::writeLog('forms', $this->userId, Util::ERROR);
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
* @copyright Copyright (c) 2020 Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @author Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
* @author Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
@ -28,46 +28,33 @@ namespace OCA\Forms\Db;
|
|||
use OCP\AppFramework\Db\Entity;
|
||||
|
||||
/**
|
||||
* @method integer getFormId()
|
||||
* @method void setFormId(integer $value)
|
||||
* @method integer getSubmissionId()
|
||||
* @method void setSubmissionId(integer $value)
|
||||
* @method integer getQuestionId()
|
||||
* @method void setQuestionId(integer $value)
|
||||
* @method string getText()
|
||||
* @method void setText(string $value)
|
||||
* @method integer getTimestamp()
|
||||
* @method void setTimestamp(integer $value)
|
||||
*/
|
||||
class Answer extends Entity {
|
||||
|
||||
/** @var int */
|
||||
protected $formId;
|
||||
|
||||
/** @var int */
|
||||
protected $submissionId;
|
||||
protected $questionId;
|
||||
|
||||
/** @var string */
|
||||
protected $text;
|
||||
|
||||
/** @var int */
|
||||
protected $timestamp;
|
||||
|
||||
/**
|
||||
* Answer constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->addType('id', 'integer');
|
||||
$this->addType('formId', 'integer');
|
||||
$this->addType('submissionId', 'integer');
|
||||
$this->addType('questionId', 'integer');
|
||||
$this->addType('timestamp', 'integer');
|
||||
}
|
||||
|
||||
public function read(): array {
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'formId' => $this->getFormId(),
|
||||
'submissionId' => $this->getSubmissionId(),
|
||||
'questionId' => $this->getQuestionId(),
|
||||
'text' => htmlspecialchars_decode($this->getText()),
|
||||
'timestamp' => $this->getTimestamp()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
*
|
||||
* @author Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
* @author Natalie Gilbert <ngilb634@umd.edu>
|
||||
* @copyright Copyright (c) 2020 Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @author Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -33,89 +30,43 @@ use OCP\AppFramework\Db\QBMapper;
|
|||
class AnswerMapper extends QBMapper {
|
||||
|
||||
/**
|
||||
* TextMapper constructor.
|
||||
* AnswerMapper constructor.
|
||||
* @param IDBConnection $db
|
||||
*/
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'forms_answers', Answer::class);
|
||||
parent::__construct($db, 'forms_v2_answers', Answer::class);
|
||||
}
|
||||
|
||||
// TODO: Change below functions to search by form and question id
|
||||
|
||||
/**
|
||||
* @param int $formId
|
||||
* @param int $questionId
|
||||
* @param int $submissionId
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
|
||||
* @return Answer[]
|
||||
*/
|
||||
|
||||
public function findByForm(int $formId, int $questionId): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT))
|
||||
)
|
||||
->andWhere(
|
||||
$qb->expr()->eq('question_id', $qb->createNamedParameter($questionId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $formId
|
||||
* @param int $questionId
|
||||
*/
|
||||
public function deleteByFormAndQuestion(int $formId, int $questionId): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->delete($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT))
|
||||
)
|
||||
->andWhere(
|
||||
$qb->expr()->eq('question_id', $qb->createNamedParameter($questionId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
$qb->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $formId
|
||||
*/
|
||||
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->execute();
|
||||
}
|
||||
|
||||
public function findById(int $answerId): Answer {
|
||||
public function findBySubmission(int $submissionId): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('id', $qb->createNamedParameter($answerId))
|
||||
$qb->expr()->eq('submission_id', $qb->createNamedParameter($submissionId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
return $this->findEntity($qb);
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
public function deleteByQuestion(int $questionId): void {
|
||||
/**
|
||||
* @param int $submissionId
|
||||
*/
|
||||
public function deleteBySubmission(int $submissionId): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->delete($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('question_id', $qb->createNamedParameter($questionId))
|
||||
);
|
||||
->where(
|
||||
$qb->expr()->eq('submission_id', $qb->createNamedParameter($submissionId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
$qb->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,44 +29,43 @@ namespace OCA\Forms\Db;
|
|||
use OCP\AppFramework\Db\Entity;
|
||||
|
||||
/**
|
||||
* @method string getHash()
|
||||
* @method void setHash(string $value)
|
||||
* @method string getTitle()
|
||||
* @method void setTitle(string $value)
|
||||
* @method string getDescription()
|
||||
* @method void setDescription(string $value)
|
||||
* @method string getOwner()
|
||||
* @method void setOwner(string $value)
|
||||
* @method string getCreated()
|
||||
* @method void setCreated(string $value)
|
||||
* @method string getOwnerId()
|
||||
* @method void setOwnerId(string $value)
|
||||
* @method string getAccess()
|
||||
* @method void setAccess(string $value)
|
||||
* @method string getExpire()
|
||||
* @method void setExpire(string $value)
|
||||
* @method string getHash()
|
||||
* @method void setHash(string $value)
|
||||
* @method string getCreated()
|
||||
* @method void setCreated(string $value)
|
||||
* @method string getExpirationDate()
|
||||
* @method void setExpirationDate(string $value)
|
||||
* @method integer getIsAnonymous()
|
||||
* @method void setIsAnonymous(integer $value)
|
||||
* @method integer getUnique()
|
||||
* @method void setUnique(integer $value)
|
||||
* @method void setIsAnonymous(bool $value)
|
||||
* @method integer getSubmitOnce()
|
||||
* @method void setSubmitOnce(bool $value)
|
||||
*/
|
||||
class Event extends Entity {
|
||||
class Form extends Entity {
|
||||
|
||||
protected $hash;
|
||||
protected $title;
|
||||
protected $description;
|
||||
protected $owner;
|
||||
protected $created;
|
||||
protected $ownerId;
|
||||
protected $access;
|
||||
protected $expire;
|
||||
protected $hash;
|
||||
protected $created;
|
||||
protected $expirationDate;
|
||||
protected $isAnonymous;
|
||||
protected $fullAnonymous;
|
||||
protected $allowMaybe;
|
||||
protected $unique;
|
||||
protected $submitOnce;
|
||||
|
||||
/**
|
||||
* Event constructor.
|
||||
* Form constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->addType('isAnonymous', 'integer');
|
||||
$this->addType('unique', 'integer');
|
||||
$this->addType('isAnonymous', 'bool');
|
||||
$this->addType('submitOnce', 'bool');
|
||||
}
|
||||
|
||||
public function read() {
|
||||
|
@ -74,12 +73,12 @@ class Event extends Entity {
|
|||
if (!strpos('|public|hidden|registered', $accessType)) {
|
||||
$accessType = 'select';
|
||||
}
|
||||
if ($this->getExpire() === null) {
|
||||
if ($this->getExpirationDate() === null) {
|
||||
$expired = false;
|
||||
$expiration = false;
|
||||
$expires = false;
|
||||
} else {
|
||||
$expired = time() > strtotime($this->getExpire());
|
||||
$expiration = true;
|
||||
$expired = time() > strtotime($this->getExpirationDate());
|
||||
$expires = true;
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -87,15 +86,15 @@ class Event extends Entity {
|
|||
'hash' => $this->getHash(),
|
||||
'title' => $this->getTitle(),
|
||||
'description' => $this->getDescription(),
|
||||
'owner' => $this->getOwner(),
|
||||
'ownerDisplayName' => \OC_User::getDisplayName($this->getOwner()),
|
||||
'ownerId' => $this->getOwnerId(),
|
||||
'ownerDisplayName' => \OC_User::getDisplayName($this->getOwnerId()),
|
||||
'created' => $this->getCreated(),
|
||||
'access' => $accessType,
|
||||
'expiration' => $expiration,
|
||||
'expires' => $expires,
|
||||
'expired' => $expired,
|
||||
'expirationDate' => $this->getExpire(),
|
||||
'expirationDate' => $this->getExpirationDate(),
|
||||
'isAnonymous' => $this->getIsAnonymous(),
|
||||
'unique' => $this->getUnique()
|
||||
'submitOnce' => $this->getSubmitOnce()
|
||||
];
|
||||
}
|
||||
}
|
|
@ -28,63 +28,63 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
|
|||
use OCP\IDBConnection;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
|
||||
class EventMapper extends QBMapper {
|
||||
class FormMapper extends QBMapper {
|
||||
|
||||
/**
|
||||
* EventMapper constructor.
|
||||
* FormMapper constructor.
|
||||
* @param IDBConnection $db
|
||||
*/
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'forms_events', Event::class);
|
||||
parent::__construct($db, 'forms_v2_forms', Form::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Integer $id
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
|
||||
* @return Event
|
||||
* @return Form
|
||||
*/
|
||||
public function find(int $id): Event {
|
||||
public function find(int $id): Form {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
$qb->select('*')
|
||||
->from($this->tableName)
|
||||
->where(
|
||||
$qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
return $this->findEntity($qb);
|
||||
return $this->findEntity($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $hash
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
|
||||
* @return Event
|
||||
* @return Form
|
||||
*/
|
||||
public function findByHash(string $hash): Event {
|
||||
public function findByHash(string $hash): Form {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('hash', $qb->createNamedParameter($hash, IQueryBuilder::PARAM_STR))
|
||||
);
|
||||
$qb->select('*')
|
||||
->from($this->tableName)
|
||||
->where(
|
||||
$qb->expr()->eq('hash', $qb->createNamedParameter($hash, IQueryBuilder::PARAM_STR))
|
||||
);
|
||||
|
||||
return $this->findEntity($qb);
|
||||
return $this->findEntity($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
|
||||
* @return Event[]
|
||||
* @return Form[]
|
||||
*/
|
||||
public function findAll(): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName());
|
||||
$qb->select('*')
|
||||
->from($this->tableName);
|
||||
|
||||
return $this->findEntities($qb);
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
}
|
58
lib/Db/Option.php
Normal file
58
lib/Db/Option.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
*
|
||||
* @author Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Forms\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
|
||||
/**
|
||||
* @method integer getQuestionId()
|
||||
* @method void setQuestionId(integer $value)
|
||||
* @method string getText()
|
||||
* @method void setText(string $value)
|
||||
*/
|
||||
class Option extends Entity {
|
||||
|
||||
/** @var int */
|
||||
protected $questionId;
|
||||
/** @var string */
|
||||
protected $text;
|
||||
|
||||
/**
|
||||
* Option constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->addType('questionId', 'integer');
|
||||
$this->addType('text', 'string');
|
||||
}
|
||||
|
||||
public function read(): array {
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'questionId' => $this->getQuestionId(),
|
||||
'text' => htmlspecialchars_decode($this->getText()),
|
||||
];
|
||||
}
|
||||
}
|
84
lib/Db/OptionMapper.php
Normal file
84
lib/Db/OptionMapper.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
*
|
||||
* @author Inigo Jiron <ijiron@terpmail.umd.edu>
|
||||
* @author Natalie Gilbert <ngilb634@umd.edu>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Forms\Db;
|
||||
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
|
||||
class OptionMapper extends QBMapper {
|
||||
|
||||
/**
|
||||
* OptionMapper constructor.
|
||||
* @param IDBConnection $db
|
||||
*/
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'forms_v2_options', Option::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $questionId
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
|
||||
* @return Option[]
|
||||
*/
|
||||
|
||||
public function findByQuestion(int $questionId): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('question_id', $qb->createNamedParameter($questionId))
|
||||
);
|
||||
|
||||
return $this->findEntities($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();
|
||||
}
|
||||
|
||||
public function findById(int $optionId): Option {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('id', $qb->createNamedParameter($optionId))
|
||||
);
|
||||
|
||||
return $this->findEntity($qb);
|
||||
}
|
||||
|
||||
}
|
|
@ -29,39 +29,34 @@ use OCP\AppFramework\Db\Entity;
|
|||
/**
|
||||
* @method integer getFormId()
|
||||
* @method void setFormId(integer $value)
|
||||
* @method string getFormQuestionType()
|
||||
* @method void setFormQuestionType(string $value)
|
||||
* @method string getFormQuestionText()
|
||||
* @method void setFormQuestionText(string $value)
|
||||
* @method integer getTimestamp()
|
||||
* @method void setTimestamp(integer $value)
|
||||
* @method string getType()
|
||||
* @method void setType(string $value)
|
||||
* @method string getText()
|
||||
* @method void setText(string $value)
|
||||
*/
|
||||
class Question extends Entity {
|
||||
protected $formId;
|
||||
protected $formQuestionType;
|
||||
protected $formQuestionText;
|
||||
protected $timestamp;
|
||||
protected $type;
|
||||
protected $mandatory;
|
||||
protected $text;
|
||||
|
||||
/**
|
||||
* Question constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->addType('formId', 'integer');
|
||||
$this->addType('timestamp', 'integer');
|
||||
$this->addType('type', 'string');
|
||||
$this->addType('mandatory', 'bool');
|
||||
$this->addType('text', 'string');
|
||||
}
|
||||
|
||||
public function read(): array {
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'formId' => $this->getFormId(),
|
||||
'type' => htmlspecialchars_decode($this->getFormQuestionType()),
|
||||
'text' => htmlspecialchars_decode($this->getFormQuestionText()),
|
||||
'timestamp' => $this->getTimestamp()
|
||||
'type' => htmlspecialchars_decode($this->getType()),
|
||||
'mandatory' => $this->getMandatory(),
|
||||
'text' => htmlspecialchars_decode($this->getText()),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -28,16 +28,22 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
|
|||
use OCP\IDBConnection;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
|
||||
use OCA\Forms\Db\OptionMapper;
|
||||
|
||||
class QuestionMapper extends QBMapper {
|
||||
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'forms_questions', Question::class);
|
||||
private $optionMapper;
|
||||
|
||||
public function __construct(IDBConnection $db, OptionMapper $optionMapper) {
|
||||
parent::__construct($db, 'forms_v2_questions', Question::class);
|
||||
|
||||
$this->optionMapper = $optionMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $formId
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
|
||||
* @return Option[]
|
||||
* @return Question[]
|
||||
*/
|
||||
|
||||
public function findByForm(int $formId): array {
|
||||
|
@ -58,6 +64,13 @@ class QuestionMapper extends QBMapper {
|
|||
public function deleteByForm(int $formId): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
// First delete corresponding options.
|
||||
$questionEntities = $this->findByForm($formId);
|
||||
foreach ($questionEntities as $questionEntity) {
|
||||
$this->optionMapper->deleteByQuestion($questionEntity->id);
|
||||
}
|
||||
|
||||
// Delete Questions
|
||||
$qb->delete($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT))
|
||||
|
@ -72,7 +85,7 @@ class QuestionMapper extends QBMapper {
|
|||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('id', $qb->createNamedParameter($questionId))
|
||||
$qb->expr()->eq('id', $qb->createNamedParameter($questionId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
return $this->findEntity($qb);
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
|
||||
* @copyright Copyright (c) 2020 Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @author Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @author Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
|
||||
* @author Kai Schröer <git@schroeer.co>
|
||||
* @author René Gieling <github@dartcafe.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -34,39 +32,27 @@ use OCP\AppFramework\Db\Entity;
|
|||
* @method void setFormId(integer $value)
|
||||
* @method string getUserId()
|
||||
* @method void setUserId(string $value)
|
||||
* @method integer getVoteOptionId()
|
||||
* @method void setVoteOptionId(integer $value)
|
||||
* @method string getVoteOptionText()
|
||||
* @method void setVoteOptionText(string $value)
|
||||
* @method string getVoteAnswer()
|
||||
* @method void setVoteAnswer(string $value)
|
||||
* @method string getVoteOptionType()
|
||||
* @method void setVoteOptionType(string $value)
|
||||
* @method string getTimestamp()
|
||||
* @method void setTimestamp(string $value)
|
||||
*/
|
||||
class Vote extends Entity {
|
||||
class Submission extends Entity {
|
||||
protected $formId;
|
||||
protected $userId;
|
||||
protected $voteOptionId;
|
||||
protected $voteOptionText;
|
||||
protected $voteAnswer;
|
||||
protected $voteOptionType;
|
||||
protected $timestamp;
|
||||
|
||||
/**
|
||||
* Options constructor.
|
||||
* Submission constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->addType('formId', 'integer');
|
||||
$this->addType('voteOptionId', 'integer');
|
||||
}
|
||||
|
||||
public function read(): array {
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'formId' => $this->getFormId(),
|
||||
'userId' => $this->getUserId(),
|
||||
'voteOptionId' => $this->getVoteOptionId(),
|
||||
'voteOptionText' => htmlspecialchars_decode($this->getVoteOptionText()),
|
||||
'voteAnswer' => $this->getVoteAnswer(),
|
||||
'voteOptionType' => $this->getVoteOptionType()
|
||||
'timestamp' => $this->getTimestamp(),
|
||||
];
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
|
||||
* @copyright Copyright (c) 2020 Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @author Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @author Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
|
||||
* @author René Gieling <github@dartcafe.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -28,31 +27,38 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
|
|||
use OCP\IDBConnection;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
|
||||
class VoteMapper extends QBMapper {
|
||||
use OCA\Forms\Db\AnswerMapper;
|
||||
|
||||
class SubmissionMapper extends QBMapper {
|
||||
|
||||
private $answerMapper;
|
||||
|
||||
/**
|
||||
* VoteMapper constructor.
|
||||
* SubmissionMapper constructor.
|
||||
* @param IDBConnection $db
|
||||
* @param AnswerMapper $answerMapper
|
||||
*/
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'forms_votes', Vote::class);
|
||||
public function __construct(IDBConnection $db, AnswerMapper $answerMapper) {
|
||||
parent::__construct($db, 'forms_v2_submissions', Submission::class);
|
||||
|
||||
$this->answerMapper = $answerMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $formId
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
|
||||
* @return Vote[]
|
||||
* @return Submission[]
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,31 +69,13 @@ class VoteMapper extends QBMapper {
|
|||
public function findParticipantsByForm(int $formId, $limit = null, $offset = null): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('user_id')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
$qb->select('user_id')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $formId
|
||||
* @param string $userId
|
||||
*/
|
||||
public function deleteByFormAndUser(int $formId, string $userId): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->delete($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT))
|
||||
)
|
||||
->andWhere(
|
||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
|
||||
);
|
||||
|
||||
$qb->execute();
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,6 +84,13 @@ class VoteMapper extends QBMapper {
|
|||
public function deleteByForm(int $formId): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
// First delete corresponding answers.
|
||||
$submissionEntities = $this->findByForm($formId);
|
||||
foreach ($submissionEntities as $submissionEntity) {
|
||||
$this->answerMapper->deleteBySubmission($submissionEntity->id);
|
||||
}
|
||||
|
||||
//Delete Submissions
|
||||
$qb->delete($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('form_id', $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT))
|
|
@ -1,210 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 René Gieling <github@dartcafe.de>
|
||||
*
|
||||
* @author René Gieling <github@dartcafe.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Forms\Migration;
|
||||
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use OCP\Migration\IOutput;
|
||||
|
||||
/**
|
||||
* Installation class for the forms app.
|
||||
* Initial db creation
|
||||
*/
|
||||
class Version0009Date20190000000006 extends SimpleMigrationStep {
|
||||
|
||||
/** @var IDBConnection */
|
||||
protected $connection;
|
||||
|
||||
/** @var IConfig */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param IDBConnection $connection
|
||||
* @param IConfig $config
|
||||
*/
|
||||
public function __construct(IDBConnection $connection, IConfig $config) {
|
||||
$this->connection = $connection;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
||||
* @param array $options
|
||||
* @return null|ISchemaWrapper
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
if (!$schema->hasTable('forms_events')) {
|
||||
$table = $schema->createTable('forms_events');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('hash', Type::STRING, [
|
||||
'notnull' => false,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->addColumn('title', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 128,
|
||||
]);
|
||||
$table->addColumn('description', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 1024,
|
||||
]);
|
||||
$table->addColumn('owner', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->addColumn('created', Type::DATETIME, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('access', Type::STRING, [
|
||||
'notnull' => false,
|
||||
'length' => 1024,
|
||||
]);
|
||||
$table->addColumn('expire', Type::DATETIME, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('is_anonymous', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
'default' => 0,
|
||||
]);
|
||||
$table->addColumn('full_anonymous', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
'default' => 0,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_questions')) {
|
||||
$table = $schema->createTable('forms_questions');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('form_id', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('form_question_type', Type::STRING, [
|
||||
'notnull' => false, // maybe true?
|
||||
'length' => 256,
|
||||
]);
|
||||
$table->addColumn('form_question_text', Type::STRING, [
|
||||
'notnull' => false, // maybe true?
|
||||
'length' => 4096,
|
||||
]);
|
||||
$table->addColumn('timestamp', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
'default' => 0
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_answers')) {
|
||||
$table = $schema->createTable('forms_answers');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('form_id', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('question_id', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('text', Type::STRING, [
|
||||
'notnull' => false, // maybe true?
|
||||
'length' => 4096,
|
||||
]);
|
||||
$table->addColumn('timestamp', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
'default' => 0
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_votes')) {
|
||||
$table = $schema->createTable('forms_votes');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('form_id', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('user_id', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->addColumn('vote_option_id', Type::INTEGER, [
|
||||
'notnull' => true,
|
||||
'default' => 0,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->addColumn('vote_option_text', Type::STRING, [
|
||||
'notnull' => false, // maybe true?
|
||||
'length' => 4096,
|
||||
]);
|
||||
$table->addColumn('vote_answer', Type::STRING, [
|
||||
'notnull' => false,
|
||||
'length' => 4096,
|
||||
]);
|
||||
$table->addColumn('vote_option_type', Type::STRING, [
|
||||
'notnull' => false,
|
||||
'length' => 256,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_notif')) {
|
||||
$table = $schema->createTable('forms_notif');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('form_id', Type::INTEGER, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('user_id', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
|
@ -23,7 +23,9 @@ class Version010102Date20200323120846 extends SimpleMigrationStep {
|
|||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
$schema->dropTable('forms_notif');
|
||||
if ($schema->hasTable('forms_notif')) {
|
||||
$schema->dropTable('forms_notif');
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
|
352
lib/Migration/Version010200Date2020323141300.php
Normal file
352
lib/Migration/Version010200Date2020323141300.php
Normal file
|
@ -0,0 +1,352 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2020 Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @author Jonas Rittershofer <jotoeri@users.noreply.github.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Forms\Migration;
|
||||
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use OCP\Migration\IOutput;
|
||||
|
||||
/**
|
||||
* Installation class for the forms app.
|
||||
* Initial db creation
|
||||
*/
|
||||
class Version010200Date2020323141300 extends SimpleMigrationStep {
|
||||
|
||||
/** @var IDBConnection */
|
||||
protected $connection;
|
||||
|
||||
/** @var IConfig */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param IDBConnection $connection
|
||||
* @param IConfig $config
|
||||
*/
|
||||
public function __construct(IDBConnection $connection, IConfig $config) {
|
||||
$this->connection = $connection;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
||||
* @param array $options
|
||||
* @return null|ISchemaWrapper
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
if (!$schema->hasTable('forms_v2_forms')) {
|
||||
$table = $schema->createTable('forms_v2_forms');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('hash', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->addColumn('title', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 256,
|
||||
]);
|
||||
$table->addColumn('description', Type::STRING, [
|
||||
'notnull' => false,
|
||||
'length' => 2048,
|
||||
]);
|
||||
$table->addColumn('owner_id', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->addColumn('access', Type::STRING, [
|
||||
'notnull' => false,
|
||||
'length' => 1024,
|
||||
]);
|
||||
$table->addColumn('created', Type::DATETIME, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('expiration_date', Type::DATETIME, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->addColumn('is_anonymous', Type::BOOLEAN, [
|
||||
'notnull' => true,
|
||||
'default' => 0,
|
||||
]);
|
||||
$table->addColumn('submit_once', Type::BOOLEAN, [
|
||||
'notnull' => true,
|
||||
'default' => 0,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_v2_questions')) {
|
||||
$table = $schema->createTable('forms_v2_questions');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('form_id', Type::INTEGER, [
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('type', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 256,
|
||||
]);
|
||||
$table->addColumn('mandatory', Type::BOOLEAN, [
|
||||
'notnull' => true,
|
||||
'default' => 1,
|
||||
]);
|
||||
$table->addColumn('text', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 2048,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_v2_options')) {
|
||||
$table = $schema->createTable('forms_v2_options');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('question_id', Type::INTEGER, [
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('text', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 1024,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_v2_submissions')) {
|
||||
$table = $schema->createTable('forms_v2_submissions');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('form_id', Type::INTEGER, [
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('user_id', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 64,
|
||||
]);
|
||||
$table->addColumn('timestamp', Type::DATETIME, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
if (!$schema->hasTable('forms_v2_answers')) {
|
||||
$table = $schema->createTable('forms_v2_answers');
|
||||
$table->addColumn('id', Type::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('submission_id', Type::INTEGER, [
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('question_id', Type::INTEGER, [
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('text', Type::STRING, [
|
||||
'notnull' => true,
|
||||
'length' => 2048,
|
||||
]);
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
// if Database exists.
|
||||
if( $schema->hasTable('forms_events') ){
|
||||
$id_mapping = [];
|
||||
$id_mapping['events'] = []; // Maps oldevent-id => newevent-id
|
||||
$id_mapping['questions'] = []; // Maps oldquestion-id => newquestion-id
|
||||
|
||||
//Fetch & Restore Events
|
||||
$qb_fetch = $this->connection->getQueryBuilder();
|
||||
$qb_restore = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb_fetch->select('id', 'hash', 'title', 'description', 'owner', 'created', 'access', 'expire', 'is_anonymous', 'unique')
|
||||
->from('forms_events');
|
||||
$cursor = $qb_fetch->execute();
|
||||
while( $event = $cursor->fetch() ){
|
||||
$qb_restore->insert('forms_v2_forms')
|
||||
->values([
|
||||
'hash' => $qb_restore->createNamedParameter($event['hash'], IQueryBuilder::PARAM_STR),
|
||||
'title' => $qb_restore->createNamedParameter($event['title'], IQueryBuilder::PARAM_STR),
|
||||
'description' => $qb_restore->createNamedParameter($event['description'], IQueryBuilder::PARAM_STR),
|
||||
'owner_id' => $qb_restore->createNamedParameter($event['owner'], IQueryBuilder::PARAM_STR),
|
||||
'access' => $qb_restore->createNamedParameter($event['access'], IQueryBuilder::PARAM_STR),
|
||||
'created' => $qb_restore->createNamedParameter($event['created'], IQueryBuilder::PARAM_STR),
|
||||
'expiration_date' => $qb_restore->createNamedParameter($event['expire'], IQueryBuilder::PARAM_STR),
|
||||
'is_anonymous' => $qb_restore->createNamedParameter($event['is_anonymous'], IQueryBuilder::PARAM_BOOL),
|
||||
'submit_once' => $qb_restore->createNamedParameter($event['unique'], IQueryBuilder::PARAM_BOOL)
|
||||
]);
|
||||
$qb_restore->execute();
|
||||
$id_mapping['events'][$event['id']] = $qb_restore->getLastInsertId(); //Store new form-id to connect questions to new form.
|
||||
}
|
||||
$cursor->closeCursor();
|
||||
|
||||
//Fetch & restore Questions
|
||||
$qb_fetch = $this->connection->getQueryBuilder();
|
||||
$qb_restore = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb_fetch->select('id', 'form_id', 'form_question_type', 'form_question_text')
|
||||
->from('forms_questions');
|
||||
$cursor = $qb_fetch->execute();
|
||||
while( $question = $cursor->fetch() ){
|
||||
//In case the old Question would have been longer than current possible length, create a warning and shorten text to avoid Error on upgrade.
|
||||
if(strlen($question['form_question_text']) > 2048) {
|
||||
$output->warning("Question-text is too long for new Database: '" . $question['form_question_text'] . "'");
|
||||
$question['form_question_text'] = substr($question['form_question_text'], 0, 2048);
|
||||
}
|
||||
|
||||
$qb_restore->insert('forms_v2_questions')
|
||||
->values([
|
||||
'form_id' => $qb_restore->createNamedParameter($id_mapping['events'][$question['form_id']], IQueryBuilder::PARAM_INT),
|
||||
'type' => $qb_restore->createNamedParameter($question['form_question_type'], IQueryBuilder::PARAM_STR),
|
||||
'text' => $qb_restore->createNamedParameter($question['form_question_text'], IQueryBuilder::PARAM_STR)
|
||||
]);
|
||||
$qb_restore->execute();
|
||||
$id_mapping['questions'][$question['id']] = $qb_restore->getLastInsertId(); //Store new question-id to connect options to new question.
|
||||
}
|
||||
$cursor->closeCursor();
|
||||
|
||||
//Fetch all Answers and restore to Options
|
||||
$qb_fetch = $this->connection->getQueryBuilder();
|
||||
$qb_restore = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb_fetch->select('question_id', 'text')
|
||||
->from('forms_answers');
|
||||
$cursor = $qb_fetch->execute();
|
||||
while( $answer = $cursor->fetch() ){
|
||||
//In case the old Answer would have been longer than current possible length, create a warning and shorten text to avoid Error on upgrade.
|
||||
if(strlen($answer['text']) > 1024) {
|
||||
$output->warning("Option-text is too long for new Database: '" . $answer['text'] . "'");
|
||||
$answer['text'] = substr($answer['text'], 0, 1024);
|
||||
}
|
||||
|
||||
$qb_restore->insert('forms_v2_options')
|
||||
->values([
|
||||
'question_id' => $qb_restore->createNamedParameter($id_mapping['questions'][$answer['question_id']], IQueryBuilder::PARAM_INT),
|
||||
'text' => $qb_restore->createNamedParameter($answer['text'], IQueryBuilder::PARAM_STR)
|
||||
]);
|
||||
$qb_restore->execute();
|
||||
}
|
||||
$cursor->closeCursor();
|
||||
|
||||
/* Fetch old id_structure of event-ids and question-ids
|
||||
* This is necessary to restore the $oldQuestionId, as the vote_option_ids do not use the true question_ids
|
||||
*/
|
||||
$event_structure = [];
|
||||
$qb_fetch = $this->connection->getQueryBuilder();
|
||||
$qb_fetch->select('id')
|
||||
->from('forms_events');
|
||||
$cursor = $qb_fetch->execute();
|
||||
while( $tmp = $cursor->fetch() ){
|
||||
$event_structure[$tmp['id']] = $tmp;
|
||||
}
|
||||
$cursor->closeCursor();
|
||||
|
||||
foreach ($event_structure as $eventkey => $event) {
|
||||
$event_structure[$eventkey]['questions'] = [];
|
||||
$qb_fetch = $this->connection->getQueryBuilder();
|
||||
$qb_fetch->select('id', 'form_question_text')
|
||||
->from('forms_questions')
|
||||
->where($qb_fetch->expr()->eq('form_id', $qb_fetch->createNamedParameter($event['id'], IQueryBuilder::PARAM_INT)));
|
||||
$cursor = $qb_fetch->execute();
|
||||
while( $tmp = $cursor->fetch() ) {
|
||||
$event_structure[$event['id']]['questions'][] = $tmp;
|
||||
}
|
||||
$cursor->closeCursor();
|
||||
}
|
||||
|
||||
//Fetch Votes and restore to Submissions & Answers
|
||||
$qb_fetch = $this->connection->getQueryBuilder();
|
||||
$qb_restore = $this->connection->getQueryBuilder();
|
||||
//initialize $last_vote
|
||||
$last_vote = [];
|
||||
$last_vote['form_id'] = 0;
|
||||
$last_vote['user_id'] = '';
|
||||
$last_vote['vote_option_id'] = 0;
|
||||
|
||||
$qb_fetch->select('id', 'form_id', 'user_id', 'vote_option_id', 'vote_option_text', 'vote_answer')
|
||||
->from('forms_votes');
|
||||
$cursor = $qb_fetch->execute();
|
||||
while( $vote = $cursor->fetch() ){
|
||||
//If the form changed, if the user changed or if vote_option_id became smaller than last one, then a new submission is interpreted.
|
||||
if ( ($vote['form_id'] != $last_vote['form_id']) || ($vote['user_id'] != $last_vote['user_id']) || ($vote['vote_option_id'] < $last_vote['vote_option_id'])) {
|
||||
$qb_restore->insert('forms_v2_submissions')
|
||||
->values([
|
||||
'form_id' => $qb_restore->createNamedParameter($id_mapping['events'][$vote['form_id']], IQueryBuilder::PARAM_INT),
|
||||
'user_id' => $qb_restore->createNamedParameter($vote['user_id'], IQueryBuilder::PARAM_STR),
|
||||
'timestamp' => $qb_restore->createNamedParameter(date('Y-m-d H:i:s'), IQueryBuilder::PARAM_STR) //Information not available. Just using Migration-Timestamp.
|
||||
]);
|
||||
$qb_restore->execute();
|
||||
$id_mapping['currentSubmission'] = $qb_restore->getLastInsertId(); //Store submission-id to connect answers to submission.
|
||||
}
|
||||
$last_vote = $vote;
|
||||
|
||||
//In case the old Answer would have been longer than current possible length, create a warning and shorten text to avoid Error on upgrade.
|
||||
if(strlen($vote['vote_answer']) > 2048) {
|
||||
$output->warning("Answer-text is too long for new Database: '" . $vote['vote_answer'] . "'");
|
||||
$vote['vote_answer'] = substr($vote['vote_answer'], 0, 2048);
|
||||
}
|
||||
|
||||
/* Due to the unconventional storing fo vote_option_ids, the vote_option_id needs to get mapped onto old question-id and from there to new question-id.
|
||||
* vote_option_ids count from 1 to x for the questions of a form. So the question at point [$vote[vote_option_id] - 1] within the id-structure is the corresponding question.
|
||||
*/
|
||||
$oldQuestionId = $event_structure[$vote['form_id']]['questions'][$vote['vote_option_id']-1]['id'];
|
||||
//Just throw an Error, if aboves QuestionId-Mapping went wrong. Double-Checked by Question-Text.
|
||||
if ($event_structure[$vote['form_id']]['questions'][$vote['vote_option_id']-1]['form_question_text'] != $vote['vote_option_text']) {
|
||||
$output->warning("Some Question-Mapping went wrong within Submission-Mapping to new Database. On 'vote_id': " . $vote['id'] . " - 'vote_option_text': '" . $vote['vote_option_text'] . "'");
|
||||
}
|
||||
|
||||
$qb_restore->insert('forms_v2_answers')
|
||||
->values([
|
||||
'submission_id' => $qb_restore->createNamedParameter($id_mapping['currentSubmission'], IQueryBuilder::PARAM_INT),
|
||||
'question_id' => $qb_restore->createNamedParameter($id_mapping['questions'][$oldQuestionId], IQueryBuilder::PARAM_STR),
|
||||
'text' => $qb_restore->createNamedParameter($vote['vote_answer'], IQueryBuilder::PARAM_STR)
|
||||
]);
|
||||
$qb_restore->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -107,7 +107,7 @@ export default {
|
|||
|
||||
selectedForm() {
|
||||
// TODO: replace with form.hash
|
||||
return this.forms.find(form => form.event.hash === this.hash)
|
||||
return this.forms.find(form => form.form.hash === this.hash)
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -141,7 +141,7 @@ export default {
|
|||
const response = await axios.post(generateUrl('/apps/forms/api/v1/form'))
|
||||
const newForm = response.data
|
||||
this.forms.push(newForm)
|
||||
this.$router.push({ name: 'edit', params: { hash: newForm.event.hash } })
|
||||
this.$router.push({ name: 'edit', params: { hash: newForm.form.hash } })
|
||||
} catch (error) {
|
||||
showError(t('forms', 'Unable to create a new form'))
|
||||
console.error(error)
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
<span v-if="options.expired" class="expired">
|
||||
{{ t('forms', 'Expired') }}
|
||||
</span>
|
||||
<span v-if="options.expiration" class="open">
|
||||
{{ t('forms', 'Expires %n', 1, expirationdate) }}
|
||||
<span v-if="options.expires" class="open">
|
||||
{{ t('forms', 'Expires %n', 1, expirationDate) }}
|
||||
</span>
|
||||
<span v-else class="open">
|
||||
{{ t('forms', 'Expires never') }}
|
||||
|
@ -39,12 +39,6 @@
|
|||
<span v-if="options.isAnonymous" class="information">
|
||||
{{ t('forms', 'Anonymous form') }}
|
||||
</span>
|
||||
<span v-if="options.fullAnonymous" class="information">
|
||||
{{ t('forms', 'Usernames hidden to Owner') }}
|
||||
</span>
|
||||
<span v-if="options.isAnonymous & !options.fullAnonymous" class="information">
|
||||
{{ t('forms', 'Usernames visible to Owner') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -61,7 +55,7 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
expirationdate() {
|
||||
expirationDate() {
|
||||
const date = moment(this.options.expirationDate, moment.localeData().longDateFormat('L')).fromNow()
|
||||
return date
|
||||
},
|
||||
|
|
|
@ -72,12 +72,12 @@
|
|||
<img class="icontwo">
|
||||
</div>
|
||||
<div class="symbol icon-voted" />
|
||||
<a :href="voteUrl" class="wrapper group-1-1">
|
||||
<a :href="submitUrl" class="wrapper group-1-1">
|
||||
<div class="name">
|
||||
{{ form.event.title }}
|
||||
{{ form.form.title }}
|
||||
</div>
|
||||
<div class="description">
|
||||
{{ form.event.description }}
|
||||
{{ form.form.description }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -102,18 +102,18 @@
|
|||
</div>
|
||||
|
||||
<div class="wrapper group-2-1">
|
||||
<div v-tooltip="accessType" class="thumbnail access" :class="form.event.access">
|
||||
<div v-tooltip="accessType" class="thumbnail access" :class="form.form.access">
|
||||
{{ accessType }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="owner">
|
||||
<UserDiv :user-id="form.event.owner" :display-name="form.event.ownerDisplayName" />
|
||||
<UserDiv :user-id="form.form.ownerId" :display-name="form.form.ownerDisplayName" />
|
||||
</div>
|
||||
<div class="wrapper group-2-2">
|
||||
<div class="created ">
|
||||
{{ timeSpanCreated }}
|
||||
</div>
|
||||
<div class="expiry" :class="{ expired : form.event.expired }">
|
||||
<div class="expiry" :class="{ expired : form.form.expired }">
|
||||
{{ timeSpanExpiration }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -150,13 +150,13 @@ export default {
|
|||
|
||||
computed: {
|
||||
accessType() {
|
||||
if (this.form.event.access === 'public') {
|
||||
if (this.form.form.access === 'public') {
|
||||
return t('forms', 'Public access')
|
||||
} else if (this.form.event.access === 'select') {
|
||||
} else if (this.form.form.access === 'select') {
|
||||
return t('forms', 'Only shared')
|
||||
} else if (this.form.event.access === 'registered') {
|
||||
} else if (this.form.form.access === 'registered') {
|
||||
return t('forms', 'Registered users only')
|
||||
} else if (this.form.event.access === 'hidden') {
|
||||
} else if (this.form.form.access === 'hidden') {
|
||||
return t('forms', 'Hidden form')
|
||||
} else {
|
||||
return ''
|
||||
|
@ -164,12 +164,12 @@ export default {
|
|||
},
|
||||
|
||||
timeSpanCreated() {
|
||||
return moment(this.form.event.created, 'YYYY-MM-DD HH:mm')
|
||||
return moment(this.form.form.created, 'YYYY-MM-DD HH:mm')
|
||||
},
|
||||
|
||||
timeSpanExpiration() {
|
||||
if (this.form.event.expiration) {
|
||||
return moment(this.form.event.expirationDate)
|
||||
if (this.form.form.expires) {
|
||||
return moment(this.form.form.expirationDate)
|
||||
} else {
|
||||
return t('forms', 'never')
|
||||
}
|
||||
|
@ -179,8 +179,8 @@ export default {
|
|||
return this.form.shares.length
|
||||
},
|
||||
|
||||
voteUrl() {
|
||||
return OC.generateUrl('apps/forms/form/') + this.form.event.hash
|
||||
submitUrl() {
|
||||
return OC.generateUrl('apps/forms/form/') + this.form.form.hash
|
||||
},
|
||||
|
||||
},
|
||||
|
@ -196,7 +196,7 @@ export default {
|
|||
|
||||
copyLink() {
|
||||
// this.$emit('copyLink')
|
||||
this.$copyText(window.location.origin + this.voteUrl).then(
|
||||
this.$copyText(window.location.origin + this.submitUrl).then(
|
||||
function(e) {
|
||||
OC.Notification.showTemporary(t('forms', 'Link copied to clipboard'))
|
||||
},
|
||||
|
@ -217,6 +217,7 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$row-padding: 15px;
|
||||
$table-padding: 4px;
|
||||
|
@ -293,8 +294,6 @@ $mediabreak-3: $group-1-width + $owner-width + max($group-2-1-width, $group-2-2-
|
|||
align-items: center;
|
||||
position: relative;
|
||||
flex-grow: 0;
|
||||
div {
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
|
|
|
@ -24,21 +24,20 @@
|
|||
<div>{{ question.text }}</div>
|
||||
<div>
|
||||
<input v-show="(question.type != 'text') && (question.type != 'comment')"
|
||||
v-model="newQuizAnswer"
|
||||
v-model="newOption"
|
||||
style="height:30px;"
|
||||
:placeholder=" t('forms', 'Add Answer')"
|
||||
@keyup.enter="emitNewAnswer(question)">
|
||||
:placeholder=" t('forms', 'Add Option')"
|
||||
@keyup.enter="emitNewOption(question)">
|
||||
<transitionGroup
|
||||
id="form-list"
|
||||
name="list"
|
||||
tag="ul"
|
||||
class="form-table">
|
||||
<TextFormItem
|
||||
v-for="(answer, index) in answers"
|
||||
:key="answer.id"
|
||||
:option="answer"
|
||||
@remove="emitRemoveAnswer(question, answer, index)"
|
||||
@delete="question.answers.splice(index, 1)" />
|
||||
v-for="(opt, index) in options"
|
||||
:key="opt.id"
|
||||
:option="opt"
|
||||
@remove="emitRemoveOption(question, opt, index)" />
|
||||
</transitionGroup>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -61,25 +60,25 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
nextQuizAnswerId: 1,
|
||||
newQuizAnswer: '',
|
||||
nextOptionId: 1,
|
||||
newOption: '',
|
||||
type: '',
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
answers() {
|
||||
return this.question.answers || []
|
||||
options() {
|
||||
return this.question.options || []
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
emitNewAnswer(question) {
|
||||
this.$emit('add-answer', this, question)
|
||||
emitNewOption(question) {
|
||||
this.$emit('addOption', this, question)
|
||||
},
|
||||
|
||||
emitRemoveAnswer(question, answer, index) {
|
||||
this.$emit('remove-answer', question, answer, index)
|
||||
emitRemoveOption(question, option, index) {
|
||||
this.$emit('deleteOption', question, option, index)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
</div>
|
||||
<div class="wrapper group-2">
|
||||
<div class="ans">
|
||||
{{ answers }}
|
||||
{{ answerText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,7 +83,7 @@ export default {
|
|||
type: Object,
|
||||
default: undefined,
|
||||
},
|
||||
vote: {
|
||||
answer: {
|
||||
type: Object,
|
||||
default: undefined,
|
||||
},
|
||||
|
@ -98,16 +98,16 @@ export default {
|
|||
|
||||
computed: {
|
||||
participants() {
|
||||
return this.vote.userId
|
||||
return this.answer.userId
|
||||
},
|
||||
questionText() {
|
||||
return this.vote.voteOptionText
|
||||
return this.answer.questionText
|
||||
},
|
||||
answers() {
|
||||
return this.vote.voteAnswer
|
||||
answerText() {
|
||||
return this.answer.text
|
||||
},
|
||||
questionNum() {
|
||||
return this.vote.voteOptionId
|
||||
return this.answer.questionId
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -27,17 +27,10 @@
|
|||
*/
|
||||
const formatForm = function(form) {
|
||||
// clone form
|
||||
const newForm = Object.assign({}, form, form.event)
|
||||
|
||||
// migrate object architecture
|
||||
Object.assign(newForm, {
|
||||
questions: form.options && form.options.formQuizQuestions,
|
||||
})
|
||||
const newForm = Object.assign({}, form, form.form)
|
||||
|
||||
// cleanup
|
||||
delete newForm.options
|
||||
delete newForm.event
|
||||
|
||||
return newForm
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,12 @@
|
|||
|
||||
<label>{{ t('forms', 'Title') }}</label>
|
||||
<input id="formTitle"
|
||||
v-model="form.event.title"
|
||||
v-model="form.form.title"
|
||||
:class="{ error: titleEmpty }"
|
||||
type="text">
|
||||
|
||||
<label>{{ t('forms', 'Description') }}</label>
|
||||
<textarea id="formDesc" v-model="form.event.description" style="resize: vertical; width: 100%;" />
|
||||
<textarea id="formDesc" v-model="form.form.description" style="resize: vertical; width: 100%;" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
@ -50,11 +50,15 @@
|
|||
<option value="" disabled>
|
||||
Select
|
||||
</option>
|
||||
<option v-for="option in options" :key="option.value" :value="option.value">
|
||||
{{ option.text }}
|
||||
<option v-for="type in questionTypes" :key="type.value" :value="type.value">
|
||||
{{ type.text }}
|
||||
</option>
|
||||
</select>
|
||||
<input v-model="newQuizQuestion" :placeholder="t('forms', 'Add Question')" @keyup.enter="addQuestion()">
|
||||
<input
|
||||
v-model="newQuestion"
|
||||
:placeholder=" t('forms', 'Add Question') "
|
||||
maxlength="2048"
|
||||
@keyup.enter="addQuestion()">
|
||||
<button id="questButton"
|
||||
@click="addQuestion()">
|
||||
{{ t('forms', 'Add Question') }}
|
||||
|
@ -67,12 +71,12 @@
|
|||
tag="ul"
|
||||
class="form-table">
|
||||
<QuizFormItem
|
||||
v-for="(question, index) in form.options.formQuizQuestions"
|
||||
v-for="(question, index) in form.questions"
|
||||
:key="question.id"
|
||||
:question="question"
|
||||
:type="question.type"
|
||||
@add-answer="addAnswer"
|
||||
@remove-answer="deleteAnswer"
|
||||
@addOption="addOption"
|
||||
@deleteOption="deleteOption"
|
||||
@deleteQuestion="deleteQuestion(question, index)" />
|
||||
</transitionGroup>
|
||||
</div>
|
||||
|
@ -105,18 +109,18 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
placeholder: '',
|
||||
newQuizAnswer: '',
|
||||
newQuizQuestion: '',
|
||||
nextQuizAnswerId: 1,
|
||||
nextQuizQuestionId: 1,
|
||||
newOption: '',
|
||||
newQuestion: '',
|
||||
nextOptionId: 1,
|
||||
nextQuestionId: 1,
|
||||
writingForm: false,
|
||||
loadingForm: true,
|
||||
titleEmpty: false,
|
||||
selected: '',
|
||||
uniqueName: false,
|
||||
uniqueAns: false,
|
||||
haveAns: false,
|
||||
options: [
|
||||
uniqueQuestionText: false,
|
||||
uniqueOptionText: false,
|
||||
allHaveOpt: false,
|
||||
questionTypes: [
|
||||
{ text: 'Radio Buttons', value: 'radiogroup' },
|
||||
{ text: 'Checkboxes', value: 'checkbox' },
|
||||
{ text: 'Short Response', value: 'text' },
|
||||
|
@ -132,10 +136,10 @@ export default {
|
|||
},
|
||||
|
||||
title() {
|
||||
if (this.form.event.title === '') {
|
||||
if (this.form.form.title === '') {
|
||||
return t('forms', 'Create new form')
|
||||
} else {
|
||||
return this.form.event.title
|
||||
return this.form.form.title
|
||||
|
||||
}
|
||||
},
|
||||
|
@ -173,7 +177,7 @@ export default {
|
|||
created() {
|
||||
if (this.$route.name === 'create') {
|
||||
// TODO: manage this from Forms.vue, request a new form to the server
|
||||
this.form.event.owner = OC.getCurrentUser().uid
|
||||
this.form.form.owner = OC.getCurrentUser().uid
|
||||
this.loadingForm = false
|
||||
} else if (this.$route.name === 'edit') {
|
||||
// TODO: fetch & update form?
|
||||
|
@ -189,81 +193,81 @@ export default {
|
|||
this.sidebar = !this.sidebar
|
||||
},
|
||||
|
||||
checkNames() {
|
||||
this.uniqueName = true
|
||||
this.form.options.formQuizQuestions.forEach(q => {
|
||||
if (q.text === this.newQuizQuestion) {
|
||||
this.uniqueName = false
|
||||
checkQuestionText() {
|
||||
this.uniqueQuestionText = true
|
||||
this.form.questions.forEach(q => {
|
||||
if (q.text === this.newQuestion) {
|
||||
this.uniqueQuestionText = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async addQuestion() {
|
||||
this.checkNames()
|
||||
this.checkQuestionText()
|
||||
if (this.selected === '') {
|
||||
showError(t('forms', 'Select a question type!'), { duration: 3000 })
|
||||
} else if (!this.uniqueName) {
|
||||
} else if (!this.uniqueQuestionText) {
|
||||
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 })
|
||||
if (this.newQuestion !== null & this.newQuestion !== '' & (/\S/.test(this.newQuestion))) {
|
||||
const response = await axios.post(generateUrl('/apps/forms/api/v1/question/'), { formId: this.form.id, type: this.selected, text: this.newQuestion })
|
||||
const questionId = response.data
|
||||
|
||||
this.form.options.formQuizQuestions.push({
|
||||
this.form.questions.push({
|
||||
id: questionId,
|
||||
text: this.newQuizQuestion,
|
||||
text: this.newQuestion,
|
||||
type: this.selected,
|
||||
answers: [],
|
||||
options: [],
|
||||
})
|
||||
}
|
||||
this.newQuizQuestion = ''
|
||||
this.newQuestion = ''
|
||||
}
|
||||
},
|
||||
|
||||
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)
|
||||
this.form.questions.splice(index, 1)
|
||||
},
|
||||
|
||||
checkAnsNames(item, question) {
|
||||
this.uniqueAnsName = true
|
||||
question.answers.forEach(q => {
|
||||
if (q.text === item.newQuizAnswer) {
|
||||
this.uniqueAnsName = false
|
||||
checkOptionText(item, question) {
|
||||
this.uniqueOptionText = true
|
||||
question.options.forEach(o => {
|
||||
if (o.text === item.newOption) {
|
||||
this.uniqueOptionText = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async addAnswer(item, question) {
|
||||
this.checkAnsNames(item, question)
|
||||
if (!this.uniqueAnsName) {
|
||||
showError(t('forms', 'Two answers cannot be the same!'), { duration: 3000 })
|
||||
async addOption(item, question) {
|
||||
this.checkOptionText(item, question)
|
||||
if (!this.uniqueOptionText) {
|
||||
showError(t('forms', 'Two options cannot be the same!'), { duration: 3000 })
|
||||
} else {
|
||||
if (item.newQuizAnswer !== null & item.newQuizAnswer !== '' & (/\S/.test(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
|
||||
if (item.newOption !== null & item.newOption !== '' & (/\S/.test(item.newOption))) {
|
||||
const response = await axios.post(generateUrl('/apps/forms/api/v1/option/'), { formId: this.form.id, questionId: question.id, text: item.newOption })
|
||||
const optionId = response.data
|
||||
|
||||
question.answers.push({
|
||||
id: answerId,
|
||||
text: item.newQuizAnswer,
|
||||
question.options.push({
|
||||
id: optionId,
|
||||
text: item.newOption,
|
||||
})
|
||||
}
|
||||
item.newQuizAnswer = ''
|
||||
item.newOption = ''
|
||||
}
|
||||
},
|
||||
|
||||
async deleteAnswer(question, answer, index) {
|
||||
await axios.delete(generateUrl('/apps/forms/api/v1/answer/{id}', { id: answer.id }))
|
||||
async deleteOption(question, option, index) {
|
||||
await axios.delete(generateUrl('/apps/forms/api/v1/option/{id}', { id: option.id }))
|
||||
// TODO catch errors
|
||||
question.answers.splice(index, 1)
|
||||
question.options.splice(index, 1)
|
||||
},
|
||||
|
||||
allHaveAns() {
|
||||
this.haveAns = true
|
||||
this.form.options.formQuizQuestions.forEach(q => {
|
||||
if (q.type !== 'text' && q.type !== 'comment' && q.answers.length === 0) {
|
||||
this.haveAns = false
|
||||
checkAllHaveOpt() {
|
||||
this.allHaveOpt = true
|
||||
this.form.questions.forEach(q => {
|
||||
if (q.type !== 'text' && q.type !== 'comment' && q.options.length === 0) {
|
||||
this.allHaveOpt = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -273,13 +277,13 @@ export default {
|
|||
}, 200),
|
||||
|
||||
writeForm() {
|
||||
this.allHaveAns()
|
||||
if (this.form.event.title.length === 0 | !(/\S/.test(this.form.event.title))) {
|
||||
this.checkAllHaveOpt()
|
||||
if (this.form.form.title.length === 0 | !(/\S/.test(this.form.form.title))) {
|
||||
this.titleEmpty = true
|
||||
showError(t('forms', 'Title must not be empty!'), { duration: 3000 })
|
||||
} else if (!this.haveAns) {
|
||||
} else if (!this.allHaveOpt) {
|
||||
showError(t('forms', 'All questions need answers!'), { duration: 3000 })
|
||||
} else if (this.form.event.expiration & this.form.event.expirationDate === '') {
|
||||
} else if (this.form.form.expires & this.form.form.expirationDate === '') {
|
||||
showError(t('forms', 'Need to pick an expiration date!'), { duration: 3000 })
|
||||
} else {
|
||||
this.writingForm = true
|
||||
|
@ -288,12 +292,12 @@ export default {
|
|||
axios.post(OC.generateUrl('apps/forms/write/form'), this.form)
|
||||
.then((response) => {
|
||||
this.form.mode = 'edit'
|
||||
this.form.event.hash = response.data.hash
|
||||
this.form.event.id = response.data.id
|
||||
this.form.form.hash = response.data.hash
|
||||
this.form.form.id = response.data.id
|
||||
this.writingForm = false
|
||||
showSuccess(t('forms', '%n successfully saved', 1, this.form.event.title), { duration: 3000 })
|
||||
showSuccess(t('forms', '%n successfully saved', 1, this.form.form.title), { duration: 3000 })
|
||||
}, (error) => {
|
||||
this.form.event.hash = ''
|
||||
this.form.form.hash = ''
|
||||
this.writingForm = false
|
||||
showError(t('forms', 'Error on saving form, see console'))
|
||||
/* eslint-disable-next-line no-console */
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
v-for="(form, index) in forms"
|
||||
:key="form.id"
|
||||
:form="form"
|
||||
@deleteForm="removeForm(index, form.event)"
|
||||
@viewResults="viewFormResults(index, form.event, 'results')" />
|
||||
@deleteForm="removeForm(index, form.form)"
|
||||
@viewResults="viewFormResults(index, form.form, 'results')" />
|
||||
</transition-group>
|
||||
<LoadingOverlay v-if="loading" />
|
||||
<modal-dialog />
|
||||
|
@ -110,29 +110,28 @@ export default {
|
|||
helpPage() {
|
||||
window.open('https://github.com/nextcloud/forms/blob/master/Forms_Support.md')
|
||||
},
|
||||
|
||||
viewFormResults(index, event, name) {
|
||||
viewFormResults(index, form, name) {
|
||||
this.$router.push({
|
||||
name: name,
|
||||
params: {
|
||||
hash: event.id,
|
||||
hash: form.id,
|
||||
},
|
||||
})
|
||||
},
|
||||
removeForm(index, event) {
|
||||
removeForm(index, form) {
|
||||
const params = {
|
||||
title: t('forms', 'Delete form'),
|
||||
text: t('forms', 'Do you want to delete "%n"?', 1, event.title),
|
||||
text: t('forms', 'Do you want to delete "%n"?', 1, form.title),
|
||||
buttonHideText: t('forms', 'No, keep form.'),
|
||||
buttonConfirmText: t('forms', 'Yes, delete form.'),
|
||||
onConfirm: () => {
|
||||
// this.deleteForm(index, event)
|
||||
axios.delete(OC.generateUrl('apps/forms/forms/{id}', { id: event.id }))
|
||||
// this.deleteForm(index, form)
|
||||
axios.delete(OC.generateUrl('apps/forms/forms/{id}', { id: form.id }))
|
||||
.then((response) => {
|
||||
this.forms.splice(index, 1)
|
||||
OC.Notification.showTemporary(t('forms', 'Form "%n" deleted', 1, event.title))
|
||||
OC.Notification.showTemporary(t('forms', 'Form "%n" deleted', 1, form.title))
|
||||
}, (error) => {
|
||||
OC.Notification.showTemporary(t('forms', 'Error while deleting Form "%n"', 1, event.title))
|
||||
OC.Notification.showTemporary(t('forms', 'Error while deleting Form "%n"', 1, form.title))
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.log(error.response)
|
||||
}
|
||||
|
|
|
@ -43,10 +43,10 @@
|
|||
:header="true" />
|
||||
<li
|
||||
is="resultItem"
|
||||
v-for="(vote, index) in votes"
|
||||
:key="vote.id"
|
||||
:vote="vote"
|
||||
@viewResults="viewFormResults(index, form.event, 'results')" />
|
||||
v-for="(answer, index) in answers"
|
||||
:key="answer.id"
|
||||
:answer="answer"
|
||||
@viewResults="viewFormResults(index, form.form, 'results')" />
|
||||
</transition-group>
|
||||
<LoadingOverlay v-if="loading" />
|
||||
<modal-dialog />
|
||||
|
@ -77,7 +77,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
votes: [],
|
||||
answers: [],
|
||||
|
||||
}
|
||||
},
|
||||
|
@ -86,29 +86,29 @@ export default {
|
|||
stats() {
|
||||
const sums = []
|
||||
|
||||
if (this.votes != null) {
|
||||
if (this.answers != null) {
|
||||
const uniqueAns = []
|
||||
const uniqueQs = []
|
||||
const ansToQ = new Map()
|
||||
for (let i = 0; i < this.votes.length; i++) {
|
||||
if (this.votes[i].voteOptionType === 'radiogroup' || this.votes[i].voteOptionType === 'dropdown') {
|
||||
if (uniqueAns.includes(this.votes[i].voteAnswer) === false) {
|
||||
uniqueAns.push(this.votes[i].voteAnswer)
|
||||
ansToQ.set(this.votes[i].voteAnswer, this.votes[i].voteOptionId)
|
||||
for (let i = 0; i < this.answers.length; i++) {
|
||||
if (this.answers[i].questionType === 'radiogroup' || this.answers[i].questionType === 'dropdown') {
|
||||
if (uniqueAns.includes(this.answers[i].text) === false) {
|
||||
uniqueAns.push(this.answers[i].text)
|
||||
ansToQ.set(this.answers[i].text, this.answers[i].questionId)
|
||||
}
|
||||
if (uniqueQs.includes(this.votes[i].voteOptionId) === false) {
|
||||
uniqueQs.push(this.votes[i].voteOptionId)
|
||||
if (uniqueQs.includes(this.answers[i].questionId) === false) {
|
||||
uniqueQs.push(this.answers[i].questionId)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < uniqueAns.length; i++) {
|
||||
sums[i] = 0
|
||||
}
|
||||
for (let i = 0; i < this.votes.length; i++) {
|
||||
sums[uniqueAns.indexOf(this.votes[i].voteAnswer)]++
|
||||
for (let i = 0; i < this.answers.length; i++) {
|
||||
sums[uniqueAns.indexOf(this.answers[i].text)]++
|
||||
}
|
||||
for (let i = 0; i < sums.length; i++) {
|
||||
sums[i] = 'Question ' + ansToQ.get(uniqueAns[i]) + ': ' + (sums[i] / ((this.votes.length / uniqueQs.length)) * 100).toFixed(2) + '%' + ' of respondents voted for answer choice: ' + uniqueAns[i]
|
||||
sums[i] = 'Question ' + ansToQ.get(uniqueAns[i]) + ': ' + (sums[i] / ((this.answers.length / uniqueQs.length)) * 100).toFixed(2) + '%' + ' of respondents voted for answer choice: ' + uniqueAns[i]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,10 +127,10 @@ export default {
|
|||
axios.get(generateUrl('apps/forms/api/v1/submissions/{hash}', { hash: this.$route.params.hash }))
|
||||
.then((response) => {
|
||||
if (response.data == null) {
|
||||
this.votes = null
|
||||
this.answers = null
|
||||
OC.Notification.showTemporary('Access Denied')
|
||||
} else {
|
||||
this.votes = response.data
|
||||
this.answers = response.data
|
||||
}
|
||||
this.loading = false
|
||||
}, (error) => {
|
||||
|
@ -139,22 +139,31 @@ export default {
|
|||
this.loading = false
|
||||
})
|
||||
},
|
||||
viewFormResults(index, event, name) {
|
||||
viewFormResults(index, form, name) {
|
||||
this.$router.push({
|
||||
name: name,
|
||||
params: {
|
||||
hash: event.id,
|
||||
hash: form.id,
|
||||
},
|
||||
})
|
||||
},
|
||||
download() {
|
||||
|
||||
this.loading = true
|
||||
axios.get(OC.generateUrl('apps/forms/get/event/' + this.$route.params.hash))
|
||||
axios.get(OC.generateUrl('apps/forms/get/form/' + this.$route.params.hash))
|
||||
.then((response) => {
|
||||
this.json2csvParser = ['userId', 'voteOptionId', 'voteOptionText', 'voteAnswer']
|
||||
this.json2csvParser = ['userId', 'questionId', 'questionText', 'Answer'] // TODO Is this one necessary??
|
||||
const formattedAns = []
|
||||
this.answers.forEach(ans => {
|
||||
formattedAns.push({
|
||||
userId: ans['userId'],
|
||||
questionId: ans['questionId'],
|
||||
questionText: ans['questionText'],
|
||||
answer: ans['text'],
|
||||
})
|
||||
})
|
||||
const element = document.createElement('a')
|
||||
element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(json2csvParser.parse(this.votes)))
|
||||
element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(json2csvParser.parse(formattedAns)))
|
||||
element.setAttribute('download', response.data.title + '.csv')
|
||||
|
||||
element.style.display = 'none'
|
||||
|
|
|
@ -21,47 +21,41 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<AppSidebar :title="form.event.title">
|
||||
<AppSidebar :title="form.form.title">
|
||||
<div class="configBox ">
|
||||
<label class="title icon-settings">
|
||||
{{ t('forms', 'Form configurations') }}
|
||||
</label>
|
||||
|
||||
<input id="anonymous"
|
||||
v-model="form.event.isAnonymous"
|
||||
<input id="isAnonymous"
|
||||
v-model="form.form.isAnonymous"
|
||||
|
||||
type="checkbox"
|
||||
class="checkbox">
|
||||
<label for="anonymous" class="title">
|
||||
<label for="isAnonymous" class="title">
|
||||
{{ t('forms', 'Anonymous form') }}
|
||||
</label>
|
||||
|
||||
<input id="unique"
|
||||
v-model="form.event.unique"
|
||||
:disabled="form.event.access !== 'registered' || form.event.isAnonymous"
|
||||
<input id="submitOnce"
|
||||
v-model="form.form.submitOnce"
|
||||
:disabled="form.form.access !== 'registered' || form.form.isAnonymous"
|
||||
type="checkbox"
|
||||
class="checkbox">
|
||||
<label for="unique" class="title">
|
||||
<label for="submitOnce" class="title">
|
||||
<span>{{ t('forms', 'Only allow one submission per user') }}</span>
|
||||
</label>
|
||||
|
||||
<input v-show="form.event.isAnonymous"
|
||||
id="trueAnonymous"
|
||||
v-model="form.event.fullAnonymous"
|
||||
<input id="expires"
|
||||
v-model="form.form.expires"
|
||||
|
||||
type="checkbox"
|
||||
class="checkbox">
|
||||
<input id="expiration"
|
||||
v-model="form.event.expiration"
|
||||
|
||||
type="checkbox"
|
||||
class="checkbox">
|
||||
<label class="title" for="expiration">
|
||||
<label class="title" for="expires">
|
||||
{{ t('forms', 'Expires') }}
|
||||
</label>
|
||||
|
||||
<DatetimePicker v-show="form.event.expiration"
|
||||
v-model="form.event.expirationDate"
|
||||
<DatetimePicker v-show="form.form.expires"
|
||||
v-model="form.form.expirationDate"
|
||||
v-bind="expirationDatePicker"
|
||||
|
||||
:time-picker-options="{ start: '00:00', step: '00:05', end: '23:55' }"
|
||||
|
@ -73,7 +67,7 @@
|
|||
{{ t('forms', 'Access') }}
|
||||
</label>
|
||||
<input id="private"
|
||||
v-model="form.event.access"
|
||||
v-model="form.form.access"
|
||||
|
||||
type="radio"
|
||||
value="registered"
|
||||
|
@ -83,7 +77,7 @@
|
|||
<span>{{ t('forms', 'Registered users only') }}</span>
|
||||
</label>
|
||||
<input id="public"
|
||||
v-model="form.event.access"
|
||||
v-model="form.form.access"
|
||||
|
||||
type="radio"
|
||||
value="public"
|
||||
|
@ -93,7 +87,7 @@
|
|||
<span>{{ t('forms', 'Public access') }}</span>
|
||||
</label>
|
||||
<input id="select"
|
||||
v-model="form.event.access"
|
||||
v-model="form.form.access"
|
||||
|
||||
type="radio"
|
||||
value="select"
|
||||
|
@ -104,7 +98,7 @@
|
|||
</label>
|
||||
</div>
|
||||
|
||||
<ShareDiv v-show="form.event.access === 'select'"
|
||||
<ShareDiv v-show="form.form.access === 'select'"
|
||||
:active-shares="form.shares"
|
||||
:placeholder="t('forms', 'Name of user or group')"
|
||||
:hide-names="true"
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
|
||||
use OCP\Util;
|
||||
|
||||
Util::addStyle('forms', 'vote');
|
||||
Util::addStyle('forms', 'submit');
|
||||
|
||||
Util::addScript('forms', 'vote');
|
||||
Util::addScript('forms', 'submit');
|
||||
Util::addScript('forms', 'survey.jquery.min');
|
||||
|
||||
/** @var \OCA\Forms\Db\Event $form */
|
||||
/** @var \OCA\Forms\Db\Form $form */
|
||||
$form = $_['form'];
|
||||
/** @var OCA\Forms\Db\Question[] $questions */
|
||||
$questions = $_['questions'];
|
Loading…
Reference in a new issue