* @copyright 2014 Heinrich-Heine-Universität Düsseldorf * @license http://www.gnu.org/licenses/gpl.html * @link https://bitbucket.org/coderkun/the-legend-of-z */ namespace hhu\z\controllers; /** * Controller of the QuestsAgent to display Quests. * * @author Oliver Hanraths */ class QuestsController extends \hhu\z\controllers\SeminaryController { /** * Required models * * @var array */ public $models = array('seminaries', 'questgroups', 'quests', 'questtexts', 'media', 'questtypes', 'questgroupshierarchy', 'xplevels'); /** * Required components * * @var array */ public $components = array('validation'); /** * User permissions * * @var array */ public $permissions = array( 'index' => array('admin', 'moderator', 'user'), 'quest' => array('admin', 'moderator', 'user'), 'submissions' => array('admin', 'moderator', 'user'), 'submission' => array('admin', 'moderator', 'user'), 'create' => array('admin', 'moderator', 'user'), 'edit' => array('admin', 'moderator', 'user'), 'edittexts' => array('admin', 'moderator', 'user'), 'edittask' => array('admin', 'moderator', 'user'), 'delete' => array('admin', 'moderator', 'user') ); /** * User seminary permissions * * @var array */ public $seminaryPermissions = array( 'index' => array('admin', 'moderator'), 'quest' => array('admin', 'moderator', 'user'), 'submissions' => array('admin', 'moderator'), 'submission' => array('admin', 'moderator'), 'create' => array('admin', 'moderator'), 'edit' => array('admin', 'moderator'), 'edittexts' => array('admin', 'moderator'), 'edittask' => array('admin', 'moderator'), 'delete' => array('admin') ); /** * Prefilter that is executed before running the Controller. * * @param \nre\core\Request $request Current request * @param \nre\core\Response $response Current response */ public function preFilter(\nre\core\Request $request, \nre\core\Response $response) { parent::preFilter($request, $response); $this->checkAchievements($request, array('character', 'quest')); $this->checkAchievements($request, 'achievement'); } /** * Action: index. * * List all Quests for a Seminary. * * @param string $seminaryUrl URL-Title of Seminary * @param string $all Show all Quests */ public function index($seminaryUrl, $all=null) { // Get seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Set filters $selectedQuestgroup = null; $selectedQuesttype = null; $selectedTitle = null; $page = 1; if($this->request->getRequestMethod() == 'GET') { $selectedQuestgroup = $this->request->getGetParam('questgroup'); $selectedQuestgroup = !empty($selectedQuestgroup) ? $selectedQuestgroup : null; $selectedQuesttype = $this->request->getGetParam('questtype'); $selectedQuesttype = !empty($selectedQuesttype) ? $selectedQuesttype : null; $selectedTitle = $this->request->getGetParam('title'); $selectedTitle = !empty($selectedTitle) ? $selectedTitle : null; $page = $this->request->getGetParam('page'); $page = !empty($page) ? intval($page) : 1; } // Get Quests $limit = ($all != 'all') ? \nre\configs\AppConfig::$misc['lists_limit'] : null; $offset = ($all != 'all') ? max((intval($page) - 1), 0) * $limit : 0; $questsCount = $this->Quests->getCountForQuestsForSeminaryByOpenSubmissions($seminary['id'], $selectedQuestgroup, $selectedQuesttype, $selectedTitle); $quests = $this->Quests->getQuestsForSeminaryByOpenSubmissions($seminary['id'], $selectedQuestgroup, $selectedQuesttype, $selectedTitle, $limit, $offset); foreach($quests as &$quest) { // Get Questtype $quest['questtype'] = $this->Questtypes->getQuesttypeById($quest['questtype_id']); } // Get filter values $questgroups = $this->Questgroups->getQuestgroupsForSeminary($seminary['id']); $questtypes = $this->Questtypes->getQuesttypes(); // Set titile $this->addTitleLocalized('Quests'); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroups', $questgroups); $this->set('questtypes', $questtypes); $this->set('selectedQuestgroup', $selectedQuestgroup); $this->set('selectedQuesttype', $selectedQuesttype); $this->set('selectedTitle', $selectedTitle); $this->set('quests', $quests); $this->set('questsCount', $questsCount); $this->set('all', $all); $this->set('page', $page); $this->set('limit', $limit); } /** * Action: quest. * * Show a quest and its task. * * @throws \nre\exceptions\IdNotFoundException * @param string $seminaryUrl URL-Title of Seminary * @param string $questgroupUrl URL-Title of Questgroup * @param string $questUrl URL-Title of Quest * @param string $questtexttypeUrl URL-Title of Questtexttype * @param int $questtextPos Position of Questtext */ public function quest($seminaryUrl, $questgroupUrl, $questUrl, $questtexttypeUrl=null, $questtextPos=1) { // Get seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['picture'] = null; if(!is_null($questgroup['questgroupspicture_id'])) { $questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']); } // Get Quest $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl); // Get Character $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']); // Check permissions if(count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) == 0) { // Previous Questgroup $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($seminary['id'], $questgroup['id']); if(!is_null($previousQuestgroup) && !$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) { throw new \nre\exceptions\AccessDeniedException(); } // Previous parents of previous Questgroup $parentQuestgroup = $previousQuestgroup; $parentQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($parentQuestgroup['id']); while(!is_null($parentQuestgroup['hierarchy']['parent_questgroup_id'])) { $parentQuestgroup = $this->Questgroups->getQuestgroupById($parentQuestgroup['hierarchy']['parent_questgroup_id']); $parentQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($parentQuestgroup['id']); try { $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($seminary['id'], $parentQuestgroup['id']); if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) { throw new \nre\exceptions\AccessDeniedException(); } } catch(\nre\exceptions\IdNotFoundException $e) { } } // Previous Quests $previousQuests = $this->Quests->getPreviousQuests($quest['id']); if(count($previousQuests) > 0) { // Previous Quests // One previous Quest has to be solved and no other // following Quest of ones has to be entered // except it is also an previous Quest of the current Quest $solved = false; $tried = false; foreach($previousQuests as &$previousQuest) { // Check previous Quest if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id'])) { $solved = true; // Check following Quests $followingQuests = $this->Quests->getNextQuests($previousQuest['id']); foreach($followingQuests as $followingQuest) { // Check following Quest if($followingQuest['id'] != $quest['id'] && $this->Quests->hasCharacterEnteredQuest($followingQuest['id'], $character['id'])) { $followingFollowingQuests = $this->Quests->getNextQuests($followingQuest['id']); if(!in_array($quest['id'], array_map(function($q) { return $q['id']; }, $followingFollowingQuests))) { $tried = true; break; } } } break; } } if(!$solved || $tried) { throw new \nre\exceptions\AccessDeniedException(); } } } // Set status “entered” $this->Quests->setQuestEntered($quest['id'], $character['id']); // Has Character solved quest? $solved = $this->Quests->hasCharacterSolvedQuest($quest['id'], $character['id']); // Get Questtexts $questtexts = array(); $questtexts['Prolog'] = $this->Questtexts->getQuesttextsOfQuest($quest['id'], 'Prolog'); if($solved || count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) > 0) { $questtexts['Epilog'] = $this->Questtexts->getQuesttextsOfQuest($quest['id'], 'Epilog'); } foreach($questtexts as &$questtextList) { foreach($questtextList as &$questtext) { // Questtext media if(!is_null($questtext['questsmedia_id'])) { $questtext['media'] = $this->Media->getSeminaryMediaById($questtext['questsmedia_id']); } // Related Questgroups $questtext['relatedQuestsgroups'] = $this->Questgroups->getRelatedQuestsgroupsOfQuesttext($questtext['id']); } } // Quest status $questStatus = $this->request->getGetParam('status'); // Quest media $questmedia = null; if(!is_null($quest['questsmedia_id'])) { $questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']); } // Task $task = null; $questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']); if(!is_null($questtype['classname'])) { $task = $this->renderTask($questtype['classname'], $seminary, $questgroup, $quest, $character); } else { // Mark Quest as solved $this->Quests->setQuestSolved($quest['id'], $character['id']); $solved = true; } // Get (related) Questtexts $relatedQuesttexts = $this->Questtexts->getRelatedQuesttextsForQuestgroup($questgroup['id']); $relatedQuesttext = $this->Questtexts->pickQuesttextLastEnteredByCharacter($character['id'], $relatedQuesttexts); if(!is_null($relatedQuesttext)) { $relatedQuesttext['quest'] = $this->Quests->getQuestById($relatedQuesttext['quest_id']); if(!empty($relatedQuesttext['quest'])) { $relatedQuesttext['quest']['questgroup_url'] = $this->Questgroups->getQuestgroupById($relatedQuesttext['quest']['questgroup_id'])['url']; } } // Next Quest/Questgroup $nextQuests = null; $charactedHasChoosenNextQuest = false; $nextQuestgroup = null; if($solved || count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) > 0) { // Next Quest $nextQuests = $this->Quests->getNextQuests($quest['id']); foreach($nextQuests as &$nextQuest) { // Set entered status of Quest $nextQuest['entered'] = $this->Quests->hasCharacterEnteredQuest($nextQuest['id'], $character['id']); if($nextQuest['entered']) { $charactedHasChoosenNextQuest = true; } } // Next Questgroup if(empty($nextQuests)) { if(is_null($relatedQuesttext)) { $nextQuestgroup = $this->Questgroups->getNextQuestgroup($seminary['id'], $questgroup['id']); if(!is_null($nextQuestgroup)) { $nextQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($nextQuestgroup['id']); } } else { // Related (Main-) Quest $nextQuest = $relatedQuesttext['quest']; $nextQuest['entered'] = true; $nextQuests = array($nextQuest); } } } // Set titile $this->addTitle($quest['title']); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('questtexts', $questtexts); $this->set('quest', $quest); $this->set('queststatus', $questStatus); $this->set('relatedquesttext', $relatedQuesttext); $this->set('nextquests', $nextQuests); $this->set('charactedHasChoosenNextQuest', $charactedHasChoosenNextQuest); $this->set('nextquestgroup', $nextQuestgroup); $this->set('task', $task); $this->set('media', $questmedia); $this->set('solved', $solved); } /** * List Character submissions for a Quest. * * @throws \nre\exceptions\IdNotFoundException * @param string $seminaryUrl URL-Title of Seminary * @param string $questgroupUrl URL-Title of Questgroup * @param string $questUrl URL-Title of Quest */ public function submissions($seminaryUrl, $questgroupUrl, $questUrl) { // Get seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['picture'] = null; if(!is_null($questgroup['questgroupspicture_id'])) { $questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']); } // Get Quest $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl); // Get submitted Character submissions waiting for approval $submittedSubmissionCharacters = $this->Characters->getCharactersSubmittedQuest($quest['id']); // Get unsolved Character submissions $unsolvedSubmissionCharacters = $this->Characters->getCharactersUnsolvedQuest($quest['id']); // Get solved Character submissions $solvedSubmissionCharacters = $this->Characters->getCharactersSolvedQuest($quest['id']); // Set titile $this->addTitleLocalized('Submissions'); $this->addTitle($quest['title']); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('quest', $quest); $this->set('submittedSubmissionCharacters', $submittedSubmissionCharacters); $this->set('unsolvedSubmissionCharacters', $unsolvedSubmissionCharacters); $this->set('solvedSubmissionCharacters', $solvedSubmissionCharacters); } /** * Show and handle the submission of a Character for a Quest. * * @throws \nre\exceptions\IdNotFoundException * @param string $seminaryUrl URL-Title of Seminary * @param string $questgroupUrl URL-Title of Questgroup * @param string $questUrl URL-Title of Quest * @param string $characterUrl URL-Title of Character */ public function submission($seminaryUrl, $questgroupUrl, $questUrl, $characterUrl) { // Get seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['picture'] = null; if(!is_null($questgroup['questgroupspicture_id'])) { $questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']); } // Get Quest $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl); // Character $character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl); // Questtype $questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']); // Render Questtype output $output = $this->renderTaskSubmission($questtype['classname'], $seminary, $questgroup, $quest, $character); // Set titile $this->addTitleLocalized('Submission of %s', $character['name']); $this->addTitle($quest['title']); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('quest', $quest); $this->set('character', $character); $this->set('output', $output); } /** * Action: create. * * Create a new Quest. * * @param string $seminaryUrl URL-Title of a Seminary * @param string $questgroupUrl URL-Title of Questgroup */ public function create($seminaryUrl, $questgroupUrl) { // Get seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroup['id']); $questgroup['picture'] = (!is_null($questgroup['questgroupspicture_id'])) ? $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']) : null; // Get Quest types $questtypes = $this->Questtypes->getQuesttypes(); foreach($questtypes as &$questtype) { $questtype['selected'] = false; } // Get allowed mimetypes $mimetypes = \nre\configs\AppConfig::$mimetypes['moodpics']; // Values $title = ''; $xps = 0; $task = ''; $entryText = ''; $wrongText = ''; $fields = array('title', 'xps'); $validation = array(); // Check request method if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create'))) { // Get params and validate them $validation = $this->Validation->validateParams($this->request->getPostParams(), $fields); $title = $this->request->getPostParam('title'); if($this->Quests->questTitleExists($title, $seminary['id'])) { $validation = $this->Validation->addValidationResult($validation, 'title', 'exist', true); } $xps = $this->request->getPostParam('xps'); $task = $this->request->getPostParam('task'); $entryText = $this->request->getPostParam('entrytext'); $wrongText = $this->request->getPostParam('wrongtext'); // Validate Questtype $questtypeIndex = null; foreach($questtypes as $index => &$questtype) { $questtype['selected'] = ($questtype['url'] == $this->request->getPostParam('questtype')); if($questtype['selected']) { $questtypeIndex = $index; } } if(is_null($questtypeIndex)) { throw new \nre\exceptions\ParamsNotValidException($questtype); } // Validate media $media = null; if(!empty($_FILES) && array_key_exists('media', $_FILES) && $_FILES['media']['error'] != UPLOAD_ERR_NO_FILE) { $media = $_FILES['media']; // Check error if($media['error'] !== UPLOAD_ERR_OK) { $validation = $this->Validation->addValidationResult($validation, 'media', 'error', $media['error']); } // Check mimetype $mediaMimetype = null; $media['mimetype'] = \hhu\z\Utils::getMimetype($media['tmp_name'], $media['type']); foreach($mimetypes as &$mimetype) { if($mimetype['mimetype'] == $media['mimetype']) { $mediaMimetype = $mimetype; break; } } if(is_null($mediaMimetype)) { $validation = $this->Validation->addValidationResult($validation, 'media', 'mimetype', $media['mimetype']); } elseif($media['size'] > $mediaMimetype['size']) { $validation = $this->Validation->addValidationResult($validation, 'media', 'size', $mediaMimetype['size']); } } // Create new Quest if($validation === true) { $questId = $this->Quests->createQuest( $this->Auth->getUserId(), $questgroup['id'], $questtypes[$questtypeIndex]['id'], $title, $xps, $task, $entryText, $wrongText ); $quest = $this->Quests->getQuestById($questId); // Update picture if(!is_null($media)) { $questsmediaId = $this->Media->createQuestMedia( $this->Auth->getUserId(), $seminary['id'], $media['name'], $title, $media['type'], $media['tmp_name'] ); if($questsmediaId > 0) { $this->Quests->setQuestmedia($quest['id'], $questsmediaId); } } // Redirect $this->redirect($this->linker->link(array('quest', $seminary['url'], $questgroup['url'], $quest['url']), 1)); } } // Get validation settings $validationSettings = array(); foreach($fields as &$field) { $validationSettings[$field] = \nre\configs\AppConfig::$validation[$field]; } // Set titile $this->addTitleLocalized('Create Quest'); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('mimetypes', $mimetypes); $this->set('questtypes', $questtypes); $this->set('title', $title); $this->set('task', $task); $this->set('entryText', $entryText); $this->set('wrongText', $wrongText); $this->set('xps', $xps); $this->set('questtype_id', $questtype); $this->set('validation', $validation); $this->set('validationSettings', $validationSettings); } /** * Action: edit. * * Edit a Quest of a Seminary. * * @throws \nre\exceptions\IdNotFoundException * @param string $seminaryUrl URL-Title of Seminary * @param string $questgroupUrl URL-Title of Questgroup * @param string $questUrl URL-Title of Quest */ public function edit($seminaryUrl, $questgroupUrl, $questUrl) { // Get Seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroup['id']); $questgroup['picture'] = (!is_null($questgroup['questgroupspicture_id'])) ? $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']) : null; // Get Quest $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl); $quest['type'] = $this->Questtypes->getQuesttypeById($quest['questtype_id']); // Get Quest media $questmedia = null; if(!is_null($quest['questsmedia_id'])) { $questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']); } // Get Quest types $questtypes = $this->Questtypes->getQuesttypes(); foreach($questtypes as &$questtype) { $questtype['selected'] = ($questtype['id'] == $quest['questtype_id']); } // Get allowed mimetypes $mimetypes = \nre\configs\AppConfig::$mimetypes['moodpics']; // Values $title = $quest['title']; $xps = $quest['xps']; $task = $quest['task']; $entryText = $quest['entry_text']; $wrongText = $quest['wrong_text']; $fields = array('title', 'xps'); $validation = array(); // Check request method if($this->request->getRequestMethod() == 'POST' && (!is_null($this->request->getPostParam('edit')) || !is_null($this->request->getPostParam('edit-task')))) { // Get params and validate them $validation = $this->Validation->validateParams($this->request->getPostParams(), $fields); $title = $this->request->getPostParam('title'); if($this->Quests->questTitleExists($title, $seminary['id'], $quest['id'])) { $validation = $this->Validation->addValidationResult($validation, 'title', 'exist', true); } $xps = $this->request->getPostParam('xps'); $task = $this->request->getPostParam('task'); $entryText = $this->request->getPostParam('entrytext'); $wrongText = $this->request->getPostParam('wrongtext'); // Validate Questtype $questtypeIndex = null; foreach($questtypes as $index => &$questtype) { $questtype['selected'] = ($questtype['url'] == $this->request->getPostParam('questtype')); if($questtype['selected']) { $questtypeIndex = $index; } } if(is_null($questtypeIndex)) { throw new \nre\exceptions\ParamsNotValidException($questtype); } // Validate media $media = null; if(!empty($_FILES) && array_key_exists('media', $_FILES) && $_FILES['media']['error'] != UPLOAD_ERR_NO_FILE) { $media = $_FILES['media']; // Check error if($media['error'] !== UPLOAD_ERR_OK) { $validation = $this->Validation->addValidationResult($validation, 'media', 'error', $media['error']); } // Check mimetype $mediaMimetype = null; $media['mimetype'] = \hhu\z\Utils::getMimetype($media['tmp_name'], $media['type']); foreach($mimetypes as &$mimetype) { if($mimetype['mimetype'] == $media['mimetype']) { $mediaMimetype = $mimetype; break; } } if(is_null($mediaMimetype)) { $validation = $this->Validation->addValidationResult($validation, 'media', 'mimetype', $media['mimetype']); } elseif($media['size'] > $mediaMimetype['size']) { $validation = $this->Validation->addValidationResult($validation, 'media', 'size', $mediaMimetype['size']); } } // Edit Quest if($validation === true) { $this->Quests->editQuest( $quest['id'], $questtypes[$questtypeIndex]['id'], $title, $xps, $task, $entryText, $wrongText ); $quest = $this->Quests->getQuestById($quest['id']); // Update picture if(!is_null($media)) { $questsmediaId = $this->Media->createQuestMedia( $this->Auth->getUserId(), $seminary['id'], $media['name'], $title, $media['type'], $media['tmp_name'] ); if($questsmediaId > 0) { $this->Quests->setQuestmedia($quest['id'], $questsmediaId); } } // Redirect if(!is_null($this->request->getPostParam('edit-task'))) { // To task editing $this->redirect($this->linker->link(array('edittask', $seminary['url'], $questgroup['url'], $quest['url']), 1)); } else { // To entry $this->redirect($this->linker->link(array('quest', $seminary['url'], $questgroup['url'], $quest['url']), 1)); } } } // Get validation settings $validationSettings = array(); foreach($fields as &$field) { $validationSettings[$field] = \nre\configs\AppConfig::$validation[$field]; } // Set titile $this->addTitleLocalized('Edit Quest'); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('quest', $quest); $this->set('media', $questmedia); $this->set('mimetypes', $mimetypes); $this->set('questtypes', $questtypes); $this->set('title', $title); $this->set('task', $task); $this->set('entryText', $entryText); $this->set('wrongText', $wrongText); $this->set('xps', $xps); $this->set('questtype_id', $questtype); $this->set('validation', $validation); $this->set('validationSettings', $validationSettings); } /** * Action: edittask. * * Edit the task of a Quest of a Seminary. * * @throws \nre\exceptions\IdNotFoundException * @param string $seminaryUrl URL-Title of Seminary * @param string $questgroupUrl URL-Title of Questgroup * @param string $questUrl URL-Title of Quest */ public function edittask($seminaryUrl, $questgroupUrl, $questUrl) { // Get Seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroup['id']); $questgroup['picture'] = (!is_null($questgroup['questgroupspicture_id'])) ? $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']) : null; // Get Quest $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl); // Render editing task $task = null; $questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']); if(!is_null($questtype['classname'])) { $task = $this->renderTaskEditing($questtype['classname'], $seminary, $questgroup, $quest); } // Set titile $this->addTitleLocalized('Edit Quest task'); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('quest', $quest); $this->set('task', $task); } /** * Action: edittexts. * * Edit the texts of a Quest of a Seminary. * * @throws \nre\exceptions\IdNotFoundException * @param string $seminaryUrl URL-Title of Seminary * @param string $questgroupUrl URL-Title of Questgroup * @param string $questUrl URL-Title of Quest */ public function edittexts($seminaryUrl, $questgroupUrl, $questUrl) { // Get Seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroup['id']); $questgroup['picture'] = (!is_null($questgroup['questgroupspicture_id'])) ? $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']) : null; // Get Quest $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl); // Get Questtexts $questtextTypes = $this->Questtexts->getQuesttexttypes(); foreach($questtextTypes as &$questtextType) { $questtextType['texts'] = $this->Questtexts->getQuesttextsOfQuest($quest['id'], $questtextType['url']); foreach($questtextType['texts'] as &$questtext) { if(!is_null($questtext['questsmedia_id'])) { $questtext['media'] = $this->Media->getSeminaryMediaById($questtext['questsmedia_id']); } } } // Get allowed mimetypes $mimetypes = \nre\configs\AppConfig::$mimetypes['moodpics']; // Check request method $validations = array(); if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('edit'))) { $media = $_FILES['media']; $texts = $this->request->getPostParam('questtexts'); $deleteTexts = $this->request->getPostParam('deletes'); if(!is_array($deleteTexts)) { $deleteTexts = array(); } foreach($questtextTypes as &$type) { // Edit or delete texts if(!array_key_exists($type['url'], $texts)) { continue; } foreach($type['texts'] as &$text) { if(array_key_exists($type['url'], $deleteTexts) && array_key_exists($text['id'], $deleteTexts[$type['url']])) { // Delete text $this->Questtexts->deleteQuesttext($text); //unset($texts[$type['url']][$text['id']]); } elseif(array_key_exists($type['url'], $texts) && array_key_exists($text['id'], $texts[$type['url']])) { // Edit text $this->Questtexts->editQuesttext($text['id'], $texts[$type['url']][$text['id']]); // Validate medium $medium = null; $validation = true; if(!empty($media) && array_key_exists($type['url'], $media['error']) && array_key_exists($text['id'], $media['error'][$type['url']]) && $media['error'][$type['url']][$text['id']] != UPLOAD_ERR_NO_FILE) { $medium = array( 'name' => $media['name'][$type['url']][$text['id']], 'tmp_name' => $media['tmp_name'][$type['url']][$text['id']], 'type' => $media['type'][$type['url']][$text['id']], 'size' => $media['size'][$type['url']][$text['id']], 'error' => $media['error'][$type['url']][$text['id']] ); // Check error if($medium['error'] !== UPLOAD_ERR_OK) { $validation = $this->Validation->addValidationResult($validation, 'media', 'error', $medium); } // Check mimetype $mediaMimetype = null; $medium['mimetype'] = \hhu\z\Utils::getMimetype($medium['tmp_name'], $medium['type']); foreach($mimetypes as &$mimetype) { if($mimetype['mimetype'] == $medium['mimetype']) { $mediaMimetype = $mimetype; break; } } if(is_null($mediaMimetype)) { $validation = $this->Validation->addValidationResult($validation, 'media', 'mimetype', $medium['mimetype']); } elseif($medium['size'] > $mediaMimetype['size']) { $validation = $this->Validation->addValidationResult($validation, 'media', 'size', $mediaMimetype['size']); } } if($validation !== true) { $validations[$type['url']][$text['id']] = $validation; } // Upload medium if(!is_null($medium) && $validation === true) { $questsmediaId = $this->Media->createQuestMedia( $this->Auth->getUserId(), $seminary['id'], sprintf('questtext-%d-%d', $quest['id'], $text['id']), $medium['name'], $medium['type'], $medium['tmp_name'] ); if($questsmediaId > 0) { $this->Questtexts->setQuestmedia($text['id'], $questsmediaId); } } // Remove text from list //unset($texts[$type['url']][$text['id']]); } } // Add new text if(array_key_exists($type['url'], $texts) && array_key_exists('new', $texts[$type['url']])) { $text = $texts[$type['url']]['new']; if(!empty($text)) { // Add text $questtextId = $this->Questtexts->addQuesttextToQuest( $this->Auth->getUserId(), $quest['id'], $type['url'], $text ); // Validate medium $medium = null; $validation = true; if(!empty($media) && array_key_exists($type['url'], $media['error']) && array_key_exists('new', $media['error'][$type['url']]) && $media['error'][$type['url']]['new'] != UPLOAD_ERR_NO_FILE) { $medium = array( 'name' => $media['name'][$type['url']]['new'], 'tmp_name' => $media['tmp_name'][$type['url']]['new'], 'type' => $media['type'][$type['url']]['new'], 'size' => $media['size'][$type['url']]['new'], 'error' => $media['error'][$type['url']]['new'] ); // Check error if($medium['error'] !== UPLOAD_ERR_OK) { $validation = $this->Validation->addValidationResult($validation, 'media', 'error', $medium); } // Check mimetype $mediaMimetype = null; $medium['mimetype'] = \hhu\z\Utils::getMimetype($medium['tmp_name'], $medium['type']); foreach($mimetypes as &$mimetype) { if($mimetype['mimetype'] == $medium['mimetype']) { $mediaMimetype = $mimetype; break; } } if(is_null($mediaMimetype)) { $validation = $this->Validation->addValidationResult($validation, 'media', 'mimetype', $medium['mimetype']); } elseif($medium['size'] > $mediaMimetype['size']) { $validation = $this->Validation->addValidationResult($validation, 'media', 'size', $mediaMimetype['size']); } } if($validation !== true) { $validations[$type['url']]['new'] = $validation; } // Upload medium if(!is_null($medium) && $validation === true) { $questsmediaId = $this->Media->createQuestMedia( $this->Auth->getUserId(), $seminary['id'], sprintf('questtext-%d-%d', $quest['id'], $questtextId), $medium['name'], $medium['type'], $medium['tmp_name'] ); if($questsmediaId > 0) { $this->Questtexts->setQuestmedia($questtextId, $questsmediaId); } } } } // Reload texts $type['texts'] = $this->Questtexts->getQuesttextsOfQuest($quest['id'], $type['url']); foreach($type['texts'] as &$questtext) { if(!is_null($questtext['questsmedia_id'])) { $questtext['media'] = $this->Media->getSeminaryMediaById($questtext['questsmedia_id']); } } } } // Set titile $this->addTitleLocalized('Edit Quest texts'); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('quest', $quest); $this->set('questtexttypes', $questtextTypes); $this->set('mimetypes', $mimetypes); $this->set('validations', $validations); } /** * Action: delete. * * Delete a Quest of a Seminary. * * @throws \nre\exceptions\IdNotFoundException * @param string $seminaryUrl URL-Title of Seminary * @param string $questgroupUrl URL-Title of Questgroup * @param string $questUrl URL-Title of Quest */ public function delete($seminaryUrl, $questgroupUrl, $questUrl) { // Get Seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); // Get Questgroup $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl); $questgroup['picture'] = null; if(!is_null($questgroup['questgroupspicture_id'])) { $questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']); } // Get Quest $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl); // Check request method if($this->request->getRequestMethod() == 'POST') { // Check confirmation if(!is_null($this->request->getPostParam('delete'))) { // Delete seminary $this->Quests->deleteQuest($quest['id']); // Redirect to Questgroup $this->redirect($this->linker->link(array('questgroups', 'questgroup', $seminary['url'], $questgroup['url']))); } // Redirect to entry $this->redirect($this->linker->link(array('quest', $seminary['url'], $questgroup['url'], $quest['url']), 1)); } // Set titile $this->addTitleLocalized('Delete Quest'); $this->addTitle($seminary['title']); // Pass data to view $this->set('seminary', $seminary); $this->set('questgroup', $questgroup); $this->set('quest', $quest); } /** * Render and handle the task of a Quest. * * @param string $questtypeClassname Name of the class for the Questtype of a Quest * @param array $seminary Seminary data * @param array $questgroup Questgroup data * @param array $quest Quest data * @param array $character Character data * @return string Rendered output */ private function renderTask($questtypeClassname, $seminary, $questgroup, $quest, $character) { $task = null; try { // Generate request and response $request = clone $this->request; $response = $this->createQuesttypeResponse('quest', $seminary, $questgroup, $quest, $character); // Load Questtype Agent $questtypeAgent = $this->loadQuesttypeAgent($questtypeClassname, $request, $response); // Solve Quest if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit'))) { // Get user answers $answers = $this->request->getPostParam('answers'); // Save answers in database try { if(!$this->Quests->hasCharacterSolvedQuest($quest['id'], $character['id'])) { $questtypeAgent->saveAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers); } // Match answers with correct ones $status = $questtypeAgent->matchAnswersofCharacter($seminary, $questgroup, $quest, $character, $answers); if($status === true) { // Mark Quest as solved $this->Quests->setQuestSolved($quest['id'], $character['id']); // Notify of XP-level change $newXPLevel = $this->Xplevels->getXPLevelById($character['xplevel_id']); if($newXPLevel['level'] > $character['xplevel']) { $this->Notification->addNotification( \hhu\z\controllers\components\NotificationComponent::TYPE_LEVELUP, $newXPLevel['level'], $this->linker->link(array('characters', 'character', $seminary['url'], $character['url'])) ); } // Redirect $this->redirect($this->linker->link(array(), 5, true, array('status'=>'solved'), false, 'task')); } elseif($status === false) { // Mark Quest as unsolved $this->Quests->setQuestUnsolved($quest['id'], $character['id']); // Redirect $this->redirect($this->linker->link(array(), 5, true, array('status'=>'unsolved'), false, 'task')); } else { // Mark Quest as submitted $this->Quests->setQuestSubmitted($quest['id'], $character['id']); // Send notification mail $this->sendSubmissionMail($seminary, $questgroup, $quest, $character); // Redirect $this->redirect($this->linker->link(array(), 5, true, null, false, 'task')); } } catch(\hhu\z\exceptions\SubmissionNotValidException $e) { $response->addParam($e); } } // Render Task $task = $this->runQuesttypeAgent($questtypeAgent, $request, $response); } catch(\nre\exceptions\ViewNotFoundException $e) { $task = $e->getMessage(); } catch(\nre\exceptions\ActionNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeControllerNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeControllerNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeAgentNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeAgentNotFoundException $e) { $task = $e->getMessage(); } // Return rendered output return $task; } /** * Render and handle a Character submission for a Quest. * * @param string $questtypeClassname Name of the class for the Questtype of a Quest * @param array $seminary Seminary data * @param array $questgroup Questgroup data * @param array $quest Quest data * @param array $character Character data * @return string Rendered output */ private function renderTaskSubmission($questtypeClassname, $seminary, $questgroup, $quest, $character) { $task = null; try { // Generate request and response $request = clone $this->request; $response = $this->createQuesttypeResponse('submission', $seminary, $questgroup, $quest, $character); // Load Questtype Agent $questtypeAgent = $this->loadQuesttypeAgent($questtypeClassname, $request, $response); // Solve Quest if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit'))) { // Set status if($this->request->getPostParam('submit') == _('solved')) { // Mark Quest as solved $this->Quests->setQuestSolved($quest['id'], $character['id']); } else { // Mark Quest as unsolved $this->Quests->setQuestUnsolved($quest['id'], $character['id']); } // Save additional data for Character answers $questtypeAgent->controller->saveDataForCharacterAnswers($seminary, $questgroup, $quest, $character, $this->request->getPostParam('characterdata')); // Send notification $this->sendSubmissionApprovedMail($character, $seminary, $questgroup, $quest); // Redirect $this->redirect($this->linker->link(array('submissions', $seminary['url'], $questgroup['url'], $quest['url']), 1)); } // Render task submissions $task = $this->runQuesttypeAgent($questtypeAgent, $request, $response); } catch(\nre\exceptions\ViewNotFoundException $e) { $task = $e->getMessage(); } catch(\nre\exceptions\ActionNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeControllerNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeControllerNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeAgentNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeAgentNotFoundException $e) { $task = $e->getMessage(); } // Return rendered output return $task; } /** * Render editing of a Quest. * * @param string $questtypeClassname Name of the class for the Questtype of a Quest * @param array $seminary Seminary data * @param array $questgroup Questgroup data * @param array $quest Quest data * @return string Rendered output */ private function renderTaskEditing($questtypeClassname, $seminary, $questgroup, $quest) { $task = null; try { // Generate request and response $request = clone $this->request; $response = $this->createQuesttypeResponse('edittask', $seminary, $questgroup, $quest); // Load Questtype Agent $questtypeAgent = $this->loadQuesttypeAgent($questtypeClassname, $request, $response); // Render Task $task = $this->runQuesttypeAgent($questtypeAgent, $request, $response); } catch(\nre\exceptions\ViewNotFoundException $e) { $task = $e->getMessage(); } catch(\nre\exceptions\ActionNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeControllerNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeControllerNotFoundException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeAgentNotValidException $e) { $task = $e->getMessage(); } catch(\hhu\z\exceptions\QuesttypeAgentNotFoundException $e) { $task = $e->getMessage(); } // Return rendered output return $task; } /** * Create a response for the Questtype rendering. * * @param string $action Action to run * @param mixed $param1 Additional parameters to add to the response * @return \nre\core\Response Generated response */ private function createQuesttypeResponse($action, $param1) { // Clone current response $response = clone $this->response; // Clear parameters $response->clearParams(1); // Add Action $response->addParams( null, $action ); // Add additional parameters foreach(array_slice(func_get_args(), 1) as $param) { $response->addParam($param); } // Return response return $response; } /** * Load and construct the QuesttypeAgent for a Questtype. * * @param string $questtypeClassname Name of the class for the Questtype of a Quest * @param \nre\core\Request $request Request * @param \nre\core\Response $response Response * @return \hhu\z\agents\QuesttypeAgent Questtype Agent */ private function loadQuesttypeAgent($questtypeClassname, $request, $response) { // Load Agent \hhu\z\agents\QuesttypeAgent::load($questtypeClassname); // Construct and return Agent return \hhu\z\agents\QuesttypeAgent::factory($questtypeClassname, $request, $response); } /** * Run and render the Agent for a QuesttypeAgent and return ist output. * * @param \nre\core\Agent $questtypeAgent QuesttypeAgent to run and render * @param \nre\core\Request $request Request * @param \nre\core\Response $response Response * @return string Rendered output */ private function runQuesttypeAgent($questtypeAgent, $request, $response) { // Run Agent $questtypeAgent->run($request, $response); // Render and return output return $questtypeAgent->render(); } /** * Send mail for new Character submission. * * @param array $seminary Seminary which the Quest belongs to * @param array $questgroup Questgroup of Quest * @param array $quest Quest the answer has been submitted for * @param array $character Character that send the submission */ private function sendSubmissionMail($seminary, $questgroup, $quest, $character) { // Get system moderators $moderators = $this->Characters->getCharactersWithCharacterRole($seminary['id'], 'moderator'); // Send notification mail try { foreach($moderators as &$moderator) { $user = $this->Users->getUserById($moderator['user_id']); if($user['mailing']) { \hhu\z\Utils::sendMail( $user['email'], 'charactersubmission', true, array( $user, $seminary, $questgroup, $quest, $character ), $this->linker ); } } } catch(\hhu\z\exceptions\MailingException $e) { $this->log($e->getMessage()); } } /** * Send mail for approval of a Character submission. * * @param array $character Character of submission that has been approved * @param array $seminary Seminary which the Quest belongs to * @param array $questgroup Questgroup of Quest * @param array $quest Quest the submission has been approved for */ private function sendSubmissionApprovedMail($character, $seminary, $questgroup, $quest) { // Get user $user = $this->Users->getUserById($character['user_id']); if(!$user['mailing']) { return; } // Send notification mail try { \hhu\z\Utils::sendMail( $user['email'], 'charactersubmissionapproved', true, array( $user, $seminary, $questgroup, $quest ), $this->linker ); } catch(\hhu\z\exceptions\MailingException $e) { $this->log($e->getMessage()); } } } ?>