forms/lib/Controller/ApiController.php
2019-05-14 03:03:59 -04:00

522 lines
14 KiB
PHP

<?php
/**
* @copyright Copyright (c) 2017 Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
*
* @author René Gieling <github@dartcafe.de>
* @author Natalie Gilbert <ngilb634@umd.edu>
* @author Inigo Jiron
* @author Affan Hussain
*
* @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\Controller;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Security\ISecureRandom;
use OCA\Forms\Db\Event;
use OCA\Forms\Db\EventMapper;
use OCA\Forms\Db\Vote;
use OCA\Forms\Db\VoteMapper;
use OCA\Forms\Db\Notification;
use OCA\Forms\Db\NotificationMapper;
use OCA\Forms\Db\Question;
use OCA\Forms\Db\QuestionMapper;
use OCA\Forms\Db\Answer;
use OCA\Forms\Db\AnswerMapper;
class ApiController extends Controller {
private $groupManager;
private $userManager;
private $eventMapper;
private $voteMapper;
private $questionMapper;
private $answerMapper;
/**
* PageController constructor.
* @param string $appName
* @param IGroupManager $groupManager
* @param IRequest $request
* @param IUserManager $userManager
* @param string $userId
* @param EventMapper $eventMapper
* @param VoteMapper $voteMapper
* @param QuestionMapper $questionMapper
* @param AnswerMapper $answerMapper
*/
public function __construct(
$appName,
IGroupManager $groupManager,
IRequest $request,
IUserManager $userManager,
$userId,
EventMapper $eventMapper,
VoteMapper $voteMapper,
QuestionMapper $questionMapper,
AnswerMapper $answerMapper
) {
parent::__construct($appName, $request);
$this->userId = $userId;
$this->groupManager = $groupManager;
$this->userManager = $userManager;
$this->eventMapper = $eventMapper;
$this->voteMapper = $voteMapper;
$this->questionMapper = $questionMapper;
$this->answerMapper = $answerMapper;
}
/**
* Transforms a string with user and group names to an array
* of nextcloud users and groups
* @param string $item
* @return Array
*/
private function convertAccessList($item) {
$split = array();
if (strpos($item, 'user_') === 0) {
$user = $this->userManager->get(substr($item, 5));
$split = [
'id' => $user->getUID(),
'user' => $user->getUID(),
'type' => 'user',
'desc' => 'user',
'icon' => 'icon-user',
'displayName' => $user->getDisplayName(),
'avatarURL' => '',
'lastLogin' => $user->getLastLogin(),
'cloudId' => $user->getCloudId()
];
} elseif (strpos($item, 'group_') === 0) {
$group = substr($item, 6);
$group = $this->groupManager->get($group);
$split = [
'id' => $group->getGID(),
'user' => $group->getGID(),
'type' => 'group',
'desc' => 'group',
'icon' => 'icon-group',
'displayName' => $group->getDisplayName(),
'avatarURL' => '',
];
}
return($split);
}
/**
* Check if current user is in the access list
* @param Array $accessList
* @return Boolean
*/
private function checkUserAccess($accessList) {
foreach ($accessList as $accessItem ) {
if ($accessItem['type'] === 'user' && $accessItem['id'] === \OC::$server->getUserSession()->getUser()->getUID()) {
return true;
}
}
return false;
}
/**
* Check If current user is member of a group in the access list
* @param Array $accessList
* @return Boolean
*/
private function checkGroupAccess($accessList) {
foreach ($accessList as $accessItem ) {
if ($accessItem['type'] === 'group' && $this->groupManager->isInGroup(\OC::$server->getUserSession()->getUser()->getUID(),$accessItem['id'])) {
return true;
}
}
return false;
}
/**
* Set the access right of the current user for the form
* @param Array $event
* @param Array $shares
* @return String
*/
private function grantAccessAs($event, $shares) {
if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
$currentUser = '';
} else {
$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
}
$grantAccessAs = 'none';
if ($event['owner'] === $currentUser) {
$grantAccessAs = 'owner';
} elseif ($event['access'] === 'public') {
$grantAccessAs = 'public';
} elseif ($event['access'] === 'registered' && \OC::$server->getUserSession()->getUser() instanceof IUser) {
$grantAccessAs = 'registered';
} elseif ($event['access'] === 'hidden' && ($event['owner'] === \OC::$server->getUserSession()->getUser())) {
$grantAccessAs = 'hidden';
} elseif ($this->checkUserAccess($shares)) {
$grantAccessAs = 'userInvitation';
} elseif ($this->checkGroupAccess($shares)) {
$grantAccessAs = 'groupInvitation';
} elseif ($this->groupManager->isAdmin($currentUser)) {
$grantAccessAs = 'admin';
}
return $grantAccessAs;
}
/**
* Read all votes of a form based on the form id
* @NoAdminRequired
* @NoCSRFRequired
* @param Integer $formId
* @return Array
*/
public function getVotes($formId) {
if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
$currentUser = '';
} else {
$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
}
$event = $this->getEvent($formId);
$accessList = $this->convertAccessList($event['access']);
if ($event['owner'] == $currentUser) {
$votesList = array();
$votes = $this->voteMapper->findByForm($formId);
foreach ($votes as $voteElement) {
$votesList[] = $voteElement->read();
}
return $votesList;
}
return NULL;
}
/**
* Read an entire form based on form id
* @NoAdminRequired
* @NoCSRFRequired
* @param Integer $formId
* @return Array
*/
public function getEvent($formId) {
$data = array();
try {
$data = $this->eventMapper->find($formId)->read();
} catch (DoesNotExistException $e) {
// return silently
} finally {
return $data;
}
}
/**
* Read all shares (users and groups with access) of a form based on the form id
* @NoAdminRequired
* @NoCSRFRequired
* @param Integer $formId
* @return Array
*/
public function getShares($formId) {
$accessList = array();
try {
$form = $this->eventMapper->find($formId);
if (!strpos('|public|hidden|registered', $form->getAccess())) {
$accessList = explode(';', $form->getAccess());
$accessList = array_filter($accessList);
$accessList = array_map(array($this, 'convertAccessList'), $accessList);
}
} catch (DoesNotExistException $e) {
// return silently
} finally {
return $accessList;
}
}
public function getQuestions($formId) {
$questionList = array();
try{
$questions = $this->questionMapper->findByForm($formId);
foreach ($questions as $questionElement) {
$temp = $questionElement->read();
$temp['answers'] = $this->getAnswers($formId, $temp['id']);
$questionList[] = $temp;
}
} catch (DoesNotExistException $e) {
//handle silently
}finally{
return $questionList;
}
}
public function getAnswers($formId, $questionId) {
$answerList = array();
try{
$answers = $this->answerMapper->findByForm($formId, $questionId);
foreach ($answers as $answerElement) {
$answerList[] = $answerElement->read();
}
} catch (DoesNotExistException $e) {
//handle silently
}finally{
return $answerList;
}
}
/**
* Read an entire form based on the form id or hash
* @NoAdminRequired
* @NoCSRFRequired
* @param String $formIdOrHash form id or hash
* @return Array
*/
public function getForm($formIdOrHash) {
if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
$currentUser = '';
} else {
$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
}
$data = array();
try {
if (is_numeric($formIdOrHash)) {
$formId = $this->eventMapper->find(intval($formIdOrHash))->id;
$result = 'foundById';
} else {
$formId = $this->eventMapper->findByHash($formIdOrHash)->id;
$result = 'foundByHash';
}
$event = $this->getEvent($formId);
$shares = $this->getShares($event['id']);
if ($event['owner'] !== $currentUser && !$this->groupManager->isAdmin($currentUser)) {
$mode = 'create';
} else {
$mode = 'edit';
}
$data = [
'id' => $event['id'],
'result' => $result,
'grantedAs' => $this->grantAccessAs($event, $shares),
'mode' => $mode,
'event' => $event,
'votes' => $this->getVotes($event['id']),
'shares' => $shares,
'options' => [
'formQuizQuestions' => $this->getQuestions($event['id'])
]
];
} catch (DoesNotExistException $e) {
$data['form'] = ['result' => 'notFound'];
} finally {
return $data;
}
}
/**
* Get all forms
* @NoAdminRequired
* @NoCSRFRequired
* @return DataResponse
*/
public function getForms() {
if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
}
try {
$events = $this->eventMapper->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;
//}
}
return new DataResponse($eventsList, Http::STATUS_OK);
}
/**
* @NoAdminRequired
* @param int $formId
* @return DataResponse
*/
public function removeForm($id) {
$formToDelete = $this->eventMapper->find($id);
if ($this->userId !== $formToDelete->getOwner() && !$this->groupManager->isAdmin($this->userId)) {
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
}
$this->voteMapper->deleteByForm($id);
// $this->notificationMapper->deleteByForm($id);
$this->questionMapper->deleteByForm($id);
$this->answerMapper->deleteByForm($id);
$this->eventMapper->delete($formToDelete);
return new DataResponse(array(
'id' => $id,
'action' => 'deleted'
), Http::STATUS_OK);
}
/**
* Write form (create/update)
* @NoAdminRequired
* @param Array $event
* @param Array $options
* @param Array $shares
* @param String $mode
* @return DataResponse
*/
public function writeForm($event, $options, $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);
}
$newEvent = new Event();
// Set the configuration options entered by the user
$newEvent->setTitle($event['title']);
$newEvent->setDescription($event['description']);
$newEvent->setIsAnonymous($event['isAnonymous']);
if ($event['access'] === 'select') {
$shareAccess = '';
foreach ($shares as $shareElement) {
if ($shareElement['type'] === 'user') {
$shareAccess = $shareAccess . 'user_' . $shareElement['id'] . ';';
} elseif ($shareElement['type'] === 'group') {
$shareAccess = $shareAccess . 'group_' . $shareElement['id'] . ';';
}
}
$newEvent->setAccess(rtrim($shareAccess, ';'));
} else {
$newEvent->setAccess($event['access']);
}
if ($event['expiration']) {
$newEvent->setExpire(date('Y-m-d H:i:s', strtotime($event['expirationDate'])));
} else {
$newEvent->setExpire(null);
}
if ($mode === 'edit') {
// Edit existing form
$oldForm = $this->eventMapper->findByHash($event['hash']);
// Check if current user is allowed to edit existing form
if ($oldForm->getOwner() !== $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);
$this->questionMapper->deleteByForm($newEvent->getId());
} 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(
16,
ISecureRandom::CHAR_DIGITS .
ISecureRandom::CHAR_LOWER .
ISecureRandom::CHAR_UPPER
));
$newEvent = $this->eventMapper->insert($newEvent);
}
// Update options
$qId = 1;
foreach($options['formQuizQuestions'] as $questionElement){
$newQuestion = new Question();
$newQuestion->setFormId($newEvent->getId());
$newQuestion->setFormQuestionType($questionElement['type']);
$newQuestion->setFormQuestionText(trim(htmlspecialchars($questionElement['text'])));
$newQuestion = $this->questionMapper->insert($newQuestion);
foreach($questionElement['answers'] as $answer){
$newAnswer = new Answer();
$newAnswer->setFormId($newEvent->getId());
$newAnswer->setQuestionId($newQuestion->getId());
$newAnswer->setText($answer['text']);
$newAnswer = $this->answerMapper->insert($newAnswer);
}
}
return new DataResponse(array(
'id' => $newEvent->getId(),
'hash' => $newEvent->getHash()
), Http::STATUS_OK);
}
}