* * @author Vinzenz Rosenkranz * @author René Gieling * @author Inigo Jiron * @author Natalie Gilbert * @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 . * */ 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\AnswerMapper; use OCA\Forms\Db\QuestionMapper; use OCP\AppFramework\Controller; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\IGroup; use OCP\IGroupManager; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserManager; use OCP\User; //To do: replace according to API use OCP\Util; class PageController extends Controller { private $userId; private $eventMapper; private $voteMapper; private $questionMapper; private $answerMapper; private $urlGenerator; private $userMgr; private $groupManager; public function __construct( IRequest $request, IUserManager $userMgr, IGroupManager $groupManager, IURLGenerator $urlGenerator, $userId, EventMapper $eventMapper, QuestionMapper $questionMapper, AnswerMapper $answerMapper, VoteMapper $VoteMapper ) { parent::__construct(Application::APP_ID, $request); $this->userMgr = $userMgr; $this->groupManager = $groupManager; $this->urlGenerator = $urlGenerator; $this->userId = $userId; $this->eventMapper = $eventMapper; $this->questionMapper = $questionMapper; $this->answerMapper = $answerMapper; $this->voteMapper = $VoteMapper; } /** * @NoAdminRequired * @NoCSRFRequired */ public function index(): TemplateResponse { return new TemplateResponse('forms', 'forms.tmpl', ['urlGenerator' => $this->urlGenerator]); } /** * @NoAdminRequired */ public function createForm(): TemplateResponse { return new TemplateResponse('forms', 'forms.tmpl', ['urlGenerator' => $this->urlGenerator]); } /** * @NoAdminRequired */ public function cloneForm(): TemplateResponse { return new TemplateResponse('forms', 'forms.tmpl', ['urlGenerator' => $this->urlGenerator]); } /** * @NoAdminRequired * @param string $hash * @return TemplateResponse */ public function editForm($hash): TemplateResponse { return new TemplateResponse('forms', 'forms.tmpl', [ 'urlGenerator' => $this->urlGenerator, 'hash' => $hash ]); } /** * @NoAdminRequired * @NoCSRFRequired * @PublicPage * @param string $hash * @return TemplateResponse */ public function gotoForm($hash): ?TemplateResponse { try { $form = $this->eventMapper->findByHash($hash); } catch (DoesNotExistException $e) { return new TemplateResponse('forms', 'no.acc.tmpl', []); } if ($form->getExpire() === null) { $expired = false; } else { $expired = time() > strtotime($form->getExpire()); } if ($expired) { return new TemplateResponse('forms', 'expired.tmpl'); } if ($this->hasUserAccess($form)) { $renderAs = $this->userId !== null ? 'user' : 'public'; $res = new TemplateResponse('forms', 'vote.tmpl', [ 'form' => $form, 'questions' => $this->getQuestions($form->getId()), ], $renderAs); $csp = new ContentSecurityPolicy(); $csp->allowEvalScript(true); $res->setContentSecurityPolicy($csp); return $res; } User::checkLoggedIn(); return new TemplateResponse('forms', 'no.acc.tmpl', []); } /** * @NoAdminRequired */ 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; } } catch (DoesNotExistException $e) { //handle silently } return $questionList; } /** * @NoAdminRequired */ public function getAnswers(int $formId, int $questionId): array { $answerList = []; try{ $answers = $this->answerMapper->findByForm($formId, $questionId); foreach ($answers as $answerElement) { $answerList[] = $answerElement->read(); } } catch (DoesNotExistException $e) { //handle silently } return $answerList; } /** * @NoAdminRequired * @param int $formId * @return TemplateResponse|RedirectResponse */ public function deleteForm($formId) { $formToDelete = $this->eventMapper->find($formId); if ($this->userId !== $formToDelete->getOwner() && !$this->groupManager->isAdmin($this->userId)) { return new TemplateResponse('forms', 'no.delete.tmpl'); } $form = new Event(); $form->setId($formId); $this->voteMapper->deleteByForm($formId); $this->eventMapper->delete($form); $url = $this->urlGenerator->linkToRoute('forms.page.index'); return new RedirectResponse($url); } /** * @NoAdminRequired * @PublicPage * @param int $formId * @param string $userId * @param string $answers * @param string $options question id * @param bool $changed * @return RedirectResponse */ public function insertVote($id, $userId, $answers, $questions) { $form = $this->eventMapper->find($id); $count_answers = count($answers); $count = 1; $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); }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); } $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); } } $hash = $form->getHash(); $url = $this->urlGenerator->linkToRoute('forms.page.goto_form', ['hash' => $hash]); return new RedirectResponse($url); } /** * @NoAdminRequired * @param string $searchTerm * @param string $groups * @param string $users * @return array */ public function search($searchTerm, $groups, $users) { return array_merge($this->searchForGroups($searchTerm, $groups), $this->searchForUsers($searchTerm, $users)); } /** * @NoAdminRequired * @param string $searchTerm * @param string $groups * @return array */ public function searchForGroups($searchTerm, $groups) { $selectedGroups = json_decode($groups); $groups = $this->groupManager->search($searchTerm); $gids = []; $sgids = []; foreach ($selectedGroups as $sg) { $sgids[] = str_replace('group_', '', $sg); } foreach ($groups as $g) { $gids[] = $g->getGID(); } $diffGids = array_diff($gids, $sgids); $gids = []; foreach ($diffGids as $g) { $gids[] = ['gid' => $g, 'isGroup' => true]; } return $gids; } /** * @NoAdminRequired * @param string $searchTerm * @param string $users * @return array */ public function searchForUsers($searchTerm, $users) { $selectedUsers = json_decode($users); Util::writeLog('forms', print_r($selectedUsers, true), Util::ERROR); $userNames = $this->userMgr->searchDisplayName($searchTerm); $users = []; $sUsers = []; foreach ($selectedUsers as $su) { $sUsers[] = str_replace('user_', '', $su); } foreach ($userNames as $u) { $allreadyAdded = false; foreach ($sUsers as &$su) { if ($su === $u->getUID()) { unset($su); $allreadyAdded = true; break; } } if (!$allreadyAdded) { $users[] = ['uid' => $u->getUID(), 'displayName' => $u->getDisplayName(), 'isGroup' => false]; } else { continue; } } return $users; } /** * @return \OCP\IGroup[] */ private function getGroups() { $groups = $this->groupManager->getUserGroups(\OC::$server->getUserSession()->getUser()); return array_map(function(IGroup $group) { return $group->getGID(); }, $groups); } /** * Check if user has access to this form * * @param Event $form * @return bool */ private function hasUserAccess($form) { $access = $form->getAccess(); $owner = $form->getOwner(); if ($access === 'public' || $access === 'hidden') { return true; } if ($this->userId === null) { return false; } if ($access === 'registered') { if ($form->getUnique()) { $participants = $this->voteMapper->findParticipantsByForm($form->getId()); foreach($participants as $participant) { // Don't allow access if user has already taken part if ($participant->getUserId() === $this->userId) return false; } } return true; } if ($owner === $this->userId) { return true; } Util::writeLog('forms', $this->userId, Util::ERROR); $userGroups = $this->getGroups(); $arr = explode(';', $access); foreach ($arr as $item) { if (strpos($item, 'group_') === 0) { $grp = substr($item, 6); foreach ($userGroups as $userGroup) { if ($userGroup === $grp) { return true; } } } else { if (strpos($item, 'user_') === 0) { $usr = substr($item, 5); if ($usr === $this->userId) { return true; } } } } return false; } /** * @NoAdminRequired * @param int $id * @return TemplateResponse */ public function getResult(int $id): TemplateResponse { return new TemplateResponse('forms', 'forms.tmpl'); } }