Questtype ?Textinput?: add support for field sizes (Issue #252) and general improvements

This commit is contained in:
coderkun 2014-05-19 11:36:36 +02:00
commit 8d903135a5
3476 changed files with 599099 additions and 0 deletions

9
.hgignore Normal file
View file

@ -0,0 +1,9 @@
syntax: regexp
^logs/*
^media/*
^tmp/*
^uploads/*
^seminarymedia/*
^seminaryuploads/*
^www/analytics/config/config.ini.php*
^www/analytics/temp/*

50
.htaccess Normal file
View file

@ -0,0 +1,50 @@
Options -Indexes -MultiViews
ErrorDocument 403 /www/error403.html
ErrorDocument 404 /www/error404.html
ErrorDocument 500 /www/error500.html
<IfModule mod_authz_core.c>
Require all granted
<Files ~ "\.inc$">
Require all denied
</Files>
<Files ~ "\.tpl$">
Require all denied
</Files>
<Files ~ "\.log$">
Require all denied
</Files>
</IfModule>
<IfModule !mod_authz_core.c>
Allow From All
<Files ~ "\.inc$">
Order Deny,Allow
Deny From All
</Files>
<Files ~ "\.tpl$">
Order Deny,Allow
Deny From All
</Files>
<Files ~ "\.log$">
Order Deny,Allow
Deny From All
</Files>
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^(.*)$ www/$1 [L]
</IfModule>

View file

@ -0,0 +1,25 @@
<?php
/**
* NRE
*
* @author coderkun <olli@coderkun.de>
* @copyright 2013 coderkun (http://www.coderkun.de)
* @license http://www.gnu.org/licenses/gpl.html
* @link http://www.coderkun.de/projects/nre
*/
namespace nre\agents;
/**
* The BottomlevelAgent is the standard Agent and can have indefinite
* SubAgents.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class BottomlevelAgent extends \nre\core\Agent
{
}
?>

View file

@ -0,0 +1,48 @@
<?php
/**
* NRE
*
* @author coderkun <olli@coderkun.de>
* @copyright 2013 coderkun (http://www.coderkun.de)
* @license http://www.gnu.org/licenses/gpl.html
* @link http://www.coderkun.de/projects/nre
*/
namespace nre\agents;
/**
* The IntermediateAgent assumes the task of a module. There is only one
* IntermediateAgent per request.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class IntermediateAgent extends \nre\core\Agent
{
/**
* Get the layout if it was explicitly defined.
*
* @return string Layout of the IntermediateAgent
*/
public static function getLayout($agentName)
{
// Determine classname
$className = Autoloader::concatClassNames($agentName, 'Agent');
// Check property
if(isset($className::$layout)) {
return $className::$layout;
}
return null;
}
}
?>

395
agents/ToplevelAgent.inc Normal file
View file

@ -0,0 +1,395 @@
<?php
/**
* NRE
*
* @author coderkun <olli@coderkun.de>
* @copyright 2013 coderkun (http://www.coderkun.de)
* @license http://www.gnu.org/licenses/gpl.html
* @link http://www.coderkun.de/projects/nre
*/
namespace nre\agents;
/**
* The ToplevelAgent assumes the task of a FrontController. There is
* only one per request.
*
* @author coderkun <olli@coderkun.de>
*/
class ToplevelAgent extends \nre\core\Agent
{
/**
* Stage: Load
*
* @var string
*/
const STAGE_LOAD = 'load';
/**
* Stage: Run
*
* @var string
*/
const STAGE_RUN = 'run';
/**
* Current request
*
* @var Request
*/
private $request;
/**
* Current response
*
* @var Response
*/
private $response;
/**
* Layout instace
*
* @var Layout
*/
private $layout = null;
/**
* IntermediateAgent instance
*
* @var IntermediateAgent
*/
private $intermediateAgent = null;
/**
* Construct a ToplevelAgent.
*
* @throws ServiceUnavailableException
* @throws DatamodelException
* @throws DriverNotValidException
* @throws DriverNotFoundException
* @throws ViewNotFoundException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ControllerNotValidException
* @throws ControllerNotFoundException
* @param Request $request Current request
* @param Response $respone Current response
* @param Logger $log Log-system
*/
protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
{
// Store values
$this->request = $request;
$this->response = $response;
// Create response
$response = clone $response;
$response->clearParams(1);
$response->addParams(
null,
\nre\configs\CoreConfig::$defaults['action']
);
// Call parent constructor
parent::__construct($request, $response, $log, true);
// Load IntermediateAgent
$this->loadIntermediateAgent();
}
/**
* Run the Controller of this Agent and its SubAgents.
*
* @throws ServiceUnavailableException
* @param Request $request Current request
* @param Response $response Current response
* @return Exception Last occurred exception of SubAgents
*/
public function run(\nre\core\Request $request, \nre\core\Response $response)
{
try {
return $this->_run($request, $response);
}
catch(\nre\exceptions\AccessDeniedException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_FORBIDDEN, self::STAGE_RUN);
}
catch(\nre\exceptions\ParamsNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
}
catch(\nre\exceptions\IdNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
}
catch(\nre\exceptions\DatamodelException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE, self::STAGE_RUN);
}
catch(\nre\exceptions\ActionNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
}
}
/**
* Generate output of the Controller of this Agent and its
* SubAgents.
*
* @param array $data View data
* @return string Generated output
*/
public function render($data=array())
{
// Render IntermediateAgent
$data = array();
$data['intermediate'] = $this->intermediateAgent->render();
// Render ToplevelAgent
return parent::render($data);
}
/**
* Return the IntermediateAgent.
*
* @return IntermediateAgent IntermediateAgent
*/
public function getIntermediateAgent()
{
return $this->intermediateAgent;
}
/**
* Load a SubAgent and add it.
*
* @throws ServiceUnavailableException
* @throws FatalDatamodelException
* @throws AgentNotFoundException
* @throws AgentNotValidException
* @param string $agentName Name of the Agent to load
* @param mixed Additional parameters for the agent
*/
protected function addSubAgent($agentName)
{
try {
call_user_func_array(
array(
$this,
'_addSubAgent'
),
func_get_args()
);
}
catch(\nre\exceptions\DatamodelException $e) {
throw new \nre\exceptions\FatalDatamodelException($e->getDatamodelMessage(), $e->getDatamodelErrorNumber());
}
}
/**
* Load IntermediateAgent defined by the current request.
*
* @throws ServiceUnavailableException
*/
private function loadIntermediateAgent()
{
try {
$this->_loadIntermediateAgent();
}
catch(\nre\exceptions\ViewNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
}
catch(\nre\exceptions\DatamodelException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\DriverNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\DriverNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ModelNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ModelNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ControllerNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ControllerNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
}
catch(\nre\exceptions\AgentNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\AgentNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
}
}
/**
* Load IntermediateAgent defined by the current request.
*
* @throws ServiceUnavailableException
*/
private function _loadIntermediateAgent()
{
// Determine IntermediateAgent
$agentName = $this->response->getParam(1);
if(is_null($agentName)) {
$agentName = $this->request->getParam(1, 'intermediate');
$this->response->addParam($agentName);
}
// Load IntermediateAgent
IntermediateAgent::load($agentName);
// Determine Action
$action = $this->response->getParam(2);
if(is_null($action)) {
$action = $this->request->getParam(2, 'action');
$this->response->addParam($action);
}
// Construct IntermediateAgent
$this->intermediateAgent = \nre\agents\IntermediateAgent::factory(
$agentName,
$this->request,
$this->response,
$this->log
);
}
/**
* Run the Controller of this Agent and its SubAgents.
*
* @throws AccessDeniedException
* @throws IdNotFoundException
* @throws ServiceUnavailableException
* @throws DatamodelException
* @param Request $request Current request
* @param Response $response Current response
* @return Exception Last occurred exception of SubAgents
*/
private function _run(\nre\core\Request $request, \nre\core\Response $response)
{
// Run IntermediateAgent
$this->runIntermediateAgent();
// TODO Request instead of response?
$response = clone $response;
$response->clearParams(2);
$response->addParam(\nre\configs\CoreConfig::$defaults['action']);
// Run ToplevelAgent
return parent::run($request, $response);
}
/**
* Run IntermediateAgent.
*
* @throws AccessDeniedException
* @throws ParamsNotValidException
* @throws IdNotFoundException
* @throws ServiceUnavailableException
* @throws DatamodelException
*/
private function runIntermediateAgent()
{
$this->intermediateAgent->run(
$this->request,
$this->response
);
}
/**
* Handle an error that occurred during
* loading/cnostructing/running of the IntermediateAgent.
*
* @throws ServiceUnavailableException
* @param Exception $exception Occurred exception
* @param int $httpStatusCode HTTP-statuscode
* @param string $stage Stage of execution
*/
private function error($exception, $httpStatusCode, $stage=self::STAGE_LOAD)
{
// Log error
$this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
try {
// Define ErrorAgent
$this->response->clearParams(1);
$this->response->addParams(
\nre\configs\AppConfig::$defaults['intermediate-error'],
\nre\configs\CoreConfig::$defaults['action'],
$httpStatusCode
);
// Load ErrorAgent
$this->_loadIntermediateAgent();
// Run ErrorAgent
if($stage == self::STAGE_RUN) {
$this->_run($this->request, $this->response);
}
}
catch(\nre\exceptions\ActionNotFoundException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\DatamodelException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\DriverNotValidException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\DriverNotFoundException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\ModelNotValidException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\ModelNotFoundException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\ViewNotFoundException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\ControllerNotValidException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\ControllerNotFoundException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\AgentNotValidException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(\nre\exceptions\AgentNotFoundException $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
catch(Exception $e) {
throw new \nre\exceptions\ServiceUnavailableException($e);
}
}
}
?>

View file

@ -0,0 +1,37 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\bottomlevel;
/**
* Agent to display a menu.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class MenuAgent extends \nre\agents\BottomlevelAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
// Add Seminary menu
$this->addSubAgent('Seminarymenu');
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\bottomlevel;
/**
* Agent to display the Questgroups hierarchy path.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuestgroupshierarchypathAgent extends \nre\agents\BottomlevelAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\bottomlevel;
/**
* Agent to display a sidebar with Seminary related information.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class SeminarybarAgent extends \nre\agents\BottomlevelAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\bottomlevel;
/**
* Agent to display a menu with Seminary related links.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class SeminarymenuAgent extends \nre\agents\BottomlevelAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\bottomlevel;
/**
* Agent to display and manage userroles.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class UserrolesAgent extends \nre\agents\BottomlevelAgent
{
/**
* Action: user.
*/
public function user(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to list Achievements.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class AchievementsAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to display Character groups.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class CharactergroupsAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to display Character groups Quests.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class CharactergroupsquestsAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,43 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to list registered Characters and their data.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class CharactersAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
/**
* Action: character.
*/
public function character(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to show an error page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class ErrorAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to show an introduction page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class IntroductionAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to list Quest topics.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class LibraryAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to process and show media.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class MediaAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,36 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to display Questgroups.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuestgroupsAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: questgroup.
*/
public function questgroup(\nre\core\Request $request, \nre\core\Response $response)
{
$this->addSubAgent('Questgroupshierarchypath', 'index', $request->getParam(3), $request->getParam(4));
}
}
?>

View file

@ -0,0 +1,54 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to display Quests.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuestsAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: quest.
*/
public function quest(\nre\core\Request $request, \nre\core\Response $response)
{
$this->addSubAgent('Questgroupshierarchypath', 'index', $request->getParam(3), $request->getParam(4), true);
}
/**
* Action: submissions.
*/
public function submissions(\nre\core\Request $request, \nre\core\Response $response)
{
$this->addSubAgent('Questgroupshierarchypath', 'index', $request->getParam(3), $request->getParam(4), true);
}
/**
* Action: submission.
*/
public function submission(\nre\core\Request $request, \nre\core\Response $response)
{
$this->addSubAgent('Questgroupshierarchypath', 'index', $request->getParam(3), $request->getParam(4), true);
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to list registered seminaries.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class SeminariesAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to process and show user uploads.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class UploadsAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,44 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\intermediate;
/**
* Agent to list registered users and their data.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class UsersAgent extends \nre\agents\IntermediateAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
/**
* Action: user.
*/
public function user(\nre\core\Request $request, \nre\core\Response $response)
{
$this->addSubAgent('Userroles', 'user');
}
}
?>

View file

@ -0,0 +1,41 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\toplevel;
/**
* Agent to display binary data (e.g. images).
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class BinaryAgent extends \hhu\z\agents\ToplevelAgent
{
protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
{
parent::__construct($request, $response, $log);
}
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\toplevel;
/**
* Agent to display a toplevel error page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class FaultAgent extends \nre\agents\ToplevelAgent
{
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
}
?>

View file

@ -0,0 +1,70 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents\toplevel;
/**
* Agent to display a HTML-page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class HtmlAgent extends \hhu\z\agents\ToplevelAgent
{
protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
{
parent::__construct($request, $response, $log);
$this->setLanguage($request);
}
/**
* Action: index.
*/
public function index(\nre\core\Request $request, \nre\core\Response $response)
{
// Add menu
$this->addSubAgent('Menu');
// Add Seminary sidebar
$this->addSubAgent('Seminarybar');
}
private function setLanguage(\nre\core\Request $request)
{
// Set domain
$domain = \nre\configs\AppConfig::$app['genericname'];
// Get language
$locale = $request->getGetParam('lang', 'language');
if(is_null($locale)) {
return;
}
// Load translation
putenv("LC_ALL=$locale");
setlocale(LC_ALL, $locale);
bindtextdomain($domain, ROOT.DS.\nre\configs\AppConfig::$dirs['locale']);
textdomain($domain);
}
}
?>

250
apis/WebApi.inc Normal file
View file

@ -0,0 +1,250 @@
<?php
/**
* NRE
*
* @author coderkun <olli@coderkun.de>
* @copyright 2013 coderkun (http://www.coderkun.de)
* @license http://www.gnu.org/licenses/gpl.html
* @link http://www.coderkun.de/projects/nre
*/
namespace nre\apis;
/**
* WebApi-implementation.
*
* This class runs and renders an web-applictaion.
*
* @author coderkun <olli@coderkun.de>
*/
class WebApi extends \nre\core\Api
{
/**
* Construct a new WebApi.
*/
public function __construct()
{
parent::__construct(
new \nre\requests\WebRequest(),
new \nre\responses\WebResponse()
);
// Add routes
$this->addRoutes();
// Disable screen logging for AJAX requests
if($this->request->getParam(0, 'toplevel') == 'ajax') {
$this->log->disableAutoLogToScreen();
}
}
/**
* Run application.
*
* This method runs the application and handles all errors.
*/
public function run()
{
try {
$exception = parent::run();
if(!is_null($exception)) {
$this->errorService($exception);
}
}
catch(\nre\exceptions\ServiceUnavailableException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ActionNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
}
catch(\nre\exceptions\FatalDatamodelException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\DatamodelException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\DriverNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\DriverNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ModelNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ModelNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ViewNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
}
catch(\nre\exceptions\ControllerNotValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\ControllerNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
}
catch(\nre\exceptions\AgentNoaatValidException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
}
catch(\nre\exceptions\AgentNotFoundException $e) {
$this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
}
catch(\nre\exceptions\ClassNotValidException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ClassNotFoundException $e) {
$this->errorService($e);
}
}
/**
* Render output.
*/
public function render()
{
// Generate output
parent::render();
// Set HTTP-header
$this->response->header();
// Show output
echo $this->response->getOutput();
}
/**
* Add routes (normal and reverse) defined in the AppConfig.
*/
private function addRoutes()
{
// Normal routes
if(property_exists('\nre\configs\AppConfig', 'routes')) {
foreach(\nre\configs\AppConfig::$routes as &$route) {
$this->request->addRoute($route[0], $route[1], $route[2]);
}
}
// Reverse routes
if(property_exists('\nre\configs\AppConfig', 'reverseRoutes')) {
foreach(\nre\configs\AppConfig::$reverseRoutes as &$route) {
$this->request->addReverseRoute($route[0], $route[1], $route[2]);
}
}
// Revalidate request
$this->request->revalidate();
}
/**
* Handle an error that orrcurred during the
* loading/constructing/running of the ToplevelAgent.
*
* @param Exception $exception Occurred exception
* @param int $httpStatusCode HTTP-statuscode
*/
private function error(\nre\core\Exception $exception, $httpStatusCode)
{
// Log error message
$this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
try {
// Set agent for handling errors
$this->response->clearParams();
$this->response->addParams(
\nre\configs\AppConfig::$defaults['toplevel-error'],
\nre\configs\AppConfig::$defaults['intermediate-error'],
\nre\configs\CoreConfig::$defaults['action'],
$httpStatusCode
);
// Run this agent
parent::run();
}
catch(\nre\exceptions\ServiceUnavailableException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ActionNotFoundException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\DatamodelException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\DriverNotValidException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\DriverNotFoundException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ModelNotValidException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ModelNotFoundException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ViewNotFoundException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ControllerNotValidException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\ControllerNotFoundException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\AgentNotValidException $e) {
$this->errorService($e);
}
catch(\nre\exceptions\AgentNotFoundException $e) {
$this->errorService($e);
}
catch(Exception $e) {
$this->errorService($e);
}
}
/**
* Handle a error which cannot be handles by the system (and
* HTTP 503).
*
* $param Exception $exception Occurred exception
*/
private function errorService($exception)
{
// Log error message
$this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
// Set HTTP-rtatuscode
$this->response->addHeader(\nre\core\WebUtils::getHttpHeader(503));
// Read and print static error file
$fileName = ROOT.DS.\nre\configs\CoreConfig::getClassDir('views').DS.\nre\configs\CoreConfig::$defaults['errorFile'].\nre\configs\CoreConfig::getFileExt('views');
ob_start();
include($fileName);
$this->response->setOutput(ob_get_clean());
// Prevent further execution
$this->response->setExit();
}
}
?>

106
app/Controller.inc Normal file
View file

@ -0,0 +1,106 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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;
/**
* Abstract class for implementing an application Controller.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
abstract class Controller extends \nre\core\Controller
{
/**
* Required components
*
* @var array
*/
public $components = array('auth');
/**
* Linker instance
*
* @var Linker
*/
protected $linker = null;
/**
* Construct a new application Controller.
*
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ViewNotFoundException
* @param string $layoutName Name of the current Layout
* @param string $action Current Action
* @param Agent $agent Corresponding Agent
*/
public function __construct($layoutName, $action, $agent)
{
parent::__construct($layoutName, $action, $agent);
}
/**
* Prefilter that is executed before running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::preFilter($request, $response);
// Create linker
$this->linker = new \nre\core\Linker($this->request);
// Create text formatter
$this->set('t', new \hhu\z\TextFormatter($this->linker));
// Create date and time and number formatter
$this->set('dateFormatter', new \IntlDateFormatter(
\nre\core\Config::getDefault('locale'),
\IntlDateFormatter::MEDIUM,
\IntlDateFormatter::NONE,
NULL
));
$this->set('timeFormatter', new \IntlDateFormatter(
\nre\core\Config::getDefault('locale'),
\IntlDateFormatter::NONE,
\IntlDateFormatter::SHORT,
NULL
));
$this->set('numberFormatter', new \NumberFormatter(
\nre\core\Config::getDefault('locale'),
\NumberFormatter::DEFAULT_STYLE
));
}
/**
* Postfilter that is executed after running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::postFilter($request, $response);
}
}
?>

42
app/Model.inc Normal file
View file

@ -0,0 +1,42 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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;
/**
* Abstract class for implementing an application Model.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class Model extends \nre\models\DatabaseModel
{
/**
* Construct a new application Model.
*
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
*/
public function __construct()
{
parent::__construct('mysqli', \nre\configs\AppConfig::$database);
}
}
?>

145
app/TextFormatter.inc Normal file
View file

@ -0,0 +1,145 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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;
/**
* Class to format text with different syntax tags.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class TextFormatter
{
/**
* Linker to create links.
*
* @var Linker
*/
private $linker;
/**
* Media-Model to retrieve media data
*
* @static
* @var model
*/
private static $Media = null;
/**
* Create a new text formatter.
*
* @param Linker $linker Linker to create links with
*/
public function __construct(\nre\core\Linker $linker)
{
$this->linker = $linker;
}
/**
* Format a string.
*
* @param string $string String to format
* @return string Formatted string
*/
public function t($string)
{
// Remove chars
$string = htmlspecialchars($string, ENT_NOQUOTES);
// Important text
$string = str_replace('[strong]', '<strong>', $string);
$string = str_replace('[/strong]', '</strong>', $string);
// Create tables
$string = str_replace('[table]', '</p><table>', $string);
$string = str_replace('[/table]', '</table><p>', $string);
$string = str_replace('[tr]', '<tr>', $string);
$string = str_replace('[/tr]', '</tr>', $string);
$string = str_replace('[th]', '<th>', $string);
$string = str_replace('[/th]', '</th>', $string);
$string = str_replace('[td]', '<td>', $string);
$string = str_replace('[/td]', '</td>', $string);
// Create links
$string = preg_replace('!(^|\s)"([^"]+)":(https?://[^\s]+)(\s|$)!i', '$1<a href="$3">$2</a>$4', $string);
$string = preg_replace('!(^|\s)(https?://[^\s]+)(\s|$)!i', '$1<a href="$2">$2</a>$3', $string);
// Handle Seminarymedia
$seminarymedia = array();
preg_match_all('/\[seminarymedia:(\d+)\]/iu', $string, $matches); //, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$seminarymediaIds = array_unique($matches[1]);
foreach($seminarymediaIds as &$seminarymediaId)
{
$replacement = null;
if(!is_null(\hhu\z\controllers\SeminaryController::$seminary) && $this->loadMediaModel())
{
try {
$medium = self::$Media->getSeminaryMediaById($seminarymediaId);
$replacement = sprintf(
'<img src="%s" alt="%s" />',
$this->linker->link(array('media','seminary', \hhu\z\controllers\SeminaryController::$seminary['url'],$medium['url'])),
$medium['description']
);
}
catch(\nre\exceptions\IdNotFoundException $e) {
}
}
$seminarymedia[$seminarymediaId] = $replacement;
}
foreach($seminarymedia as $seminarymediaId => $replacement) {
$string = str_replace("[seminarymedia:$seminarymediaId]", $replacement, $string);
}
// Return processed string
return nl2br($string);
}
/**
* Load the Media-Model if it is not loaded
*
* @return boolean Whether the Media-Model has been loaded or not
*/
private function loadMediaModel()
{
// Do not load Model if it has already been loaded
if(!is_null(self::$Media)) {
return true;
}
try {
// Load class
Model::load('media');
// Construct Model
self::$Media = Model::factory('media');
}
catch(\Exception $e) {
}
// Return whether Media-Model has been loaded or not
return !is_null(self::$Media);
}
}
?>

140
app/Utils.inc Normal file
View file

@ -0,0 +1,140 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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;
/**
* Class for implementing utility methods.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class Utils
{
/**
* Mask HTML-chars for save output.
*
* @static
* @param string $string String to be masked
* @return string Masked string
*/
public static function t($string)
{
return nl2br(htmlspecialchars($string));
}
/**
* htmlspecialchars with support for UTF-8.
*
* @static
* @param string $string String to be masked
* @return string Masked string
*/
public static function htmlspecialchars_utf8($string)
{
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
}
/**
* Cut a string to the given length but only word boundaries.
*
* @static
* @param string $string String to cut
* @param int $length Length to cut string
* @param int $scope Maximum length to cut string regardless word boundaries
* @return string Cutted string
*/
public static function shortenString($string, $length, $scope)
{
// Determine length
$length = min($length, strlen($string));
// Look for word boundary
if(($pos = strpos($string, ' ', $length)) !== false)
{
// Check if boundary is outside of scope
if($pos > $length + $scope) {
$pos = strrpos(substr($string, 0, $pos), ' ');
}
}
else {
$pos = strlen($string);
}
// Cut string and return it
return substr($string, 0, $pos);
}
/**
* Send an email.
*
* @param string $from Sender of mail
* @param mixed $to One (string) or many (array) receivers
* @param string $subject Subject of mail
* @param string $message Message of mail
* @param boolean $html Whether mail should be formatted as HTML or not
* @return Whether mail has been send or not
*/
public static function sendMail($from, $to, $subject, $message, $html=false)
{
// Set receivers
$to = is_array($to) ? implode(',', $to) : $to;
// Set header
$headers = array();
$headers[] = 'Content-type: text/'.($html ? 'html' : 'plain').'; charset=UTF-8';
if(!is_null($from)) {
$headers[] = "From: $from";
}
$header = implode("\r\n", $headers)."\r\n";
// Send mail
return mail($to, $subject, $message, $header);
}
/**
* Detect Mimetype of a file.
*
* @param string $filename Name of file to detect Mimetype of
* @param string $defaultMimetype Default Mimetype to use
* @return string Detected Mimetype of file
*/
public static function getMimetype($filename, $defaultMimetype=null)
{
$mimetype = (!is_null($defaultMimetype)) ? $defaultMimetype : 'application/octet-stream';
// Use Fileinfo
if(class_exists('\finfo'))
{
$finfo = new \finfo(FILEINFO_MIME_TYPE);
if(!is_null($finfo)) {
$mimetype = $finfo->file($filename);
}
}
// Use deprecated mime_content_type()
elseif(function_exists('mime_content_type')) {
$mimetype = mime_content_type($filename);
}
return $mimetype;
}
}
?>

View file

@ -0,0 +1,284 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents;
/**
* Abstract class for implementing a QuesttypeAgent.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
abstract class QuesttypeAgent extends \nre\agents\BottomlevelAgent
{
/**
* Current request
*
* @var Request
*/
private $request;
/**
* Current response
*
* @var Response
*/
private $response;
/**
* Load a QuesttypeAgent.
*
* @static
* @throws QuesttypeAgentNotFoundException
* @throws QuesttypeAgentNotValidException
* @param string $questtypeName Name of the QuesttypeAgent to load
*/
public static function load($questtypeName)
{
// Determine full classname
$className = self::getClassName($questtypeName);
try {
// Load class
static::loadClass($questtypeName, $className);
// Validate class
static::checkClass($className, get_class());
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \hhu\z\exceptions\QuesttypeAgentNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \hhu\z\exceptions\QuesttypeAgentNotFoundException($e->getClassName());
}
}
/**
* Instantiate a QuesttypeAgent (Factory Pattern).
*
* @static
* @throws DatamodelException
* @throws DriverNotValidException
* @throws DriverNotFoundException
* @throws ViewNotFoundException
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
* @throws QuesttypeControllerNotValidException
* @throws QuesttypeControllerNotFoundException
* @param string $questtypeName Name of the QuesttypeAgent to instantiate
* @param Request $request Current request
* @param Response $respone Current respone
* @param Logger $log Log-system
*/
public static function factory($questtypeName, \nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
{
// Determine full classname
$className = self::getClassName($questtypeName);
// Construct and return Questmodule
return new $className($request, $response, $log);
}
/**
* Determine the Agent-classname for the given Questtype-name.
*
* @static
* @param string $questtypeName Questtype-name to get Agent-classname of
* @return string Classname for the Questtype-name
*/
private static function getClassName($questtypeName)
{
$className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'agent');
return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
}
/**
* Determine the classname for the given Agent name.
*
* @static
* @param string $agentName Agent name to get classname of
* @param string $agentType Agent type of given Agent name
* @return string Classname for the Agent name
*/
/*private static function getClassName($agentName, $agentType)
{
$className = ClassLoader::concatClassNames($agentName, 'agent');
return \nre\configs\AppConfig::$app['namespace']."agents\\$agentType\\$className";
}*/
/**
* Load the class of a QuesttypeAgent.
*
* @static
* @throws ClassNotFoundException
* @param string $questtypeName Name of the QuesttypeAgent to load
* @param string $fullClassName Name of the class to load
*/
private static function loadClass($questtypeName, $fullClassName)
{
// Determine folder to look in
$className = explode('\\', $fullClassName);
$className = array_pop($className);
// Determine filename
$fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
// Check file
if(!file_exists($fileName))
{
throw new \nre\exceptions\ClassNotFoundException(
$fullClassName
);
}
// Include file
include_once($fileName);
}
/**
* Check inheritance of the QuesttypeAgent-class.
*
* @static
* @throws ClassNotValidException
* @param string $className Name of the class to check
* @param string $parentClassName Name of the parent class
*/
public static function checkClass($className, $parentClassName)
{
// Check if class is subclass of parent class
if(!is_subclass_of($className, $parentClassName)) {
throw new \nre\exceptions\ClassNotValidException(
$className
);
}
}
/**
* Construct a new QuesttypeAgent.
*
* @throws DatamodelException
* @throws DriverNotValidException
* @throws DriverNotFoundException
* @throws ViewNotFoundException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
* @throws QuesttypeControllerNotValidException
* @throws QuesttypeControllerNotFoundException
* @param Request $request Current request
* @param Response $respone Current response
* @param Logger $log Log-system
*/
protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
{
// Store values
$this->request = $request;
$this->response = $response;
// Call parent constructor
parent::__construct($request, $response, $log);
}
/**
* Save the answers of a Character for a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $answers Character answers for the Quest
*/
public function saveAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers)
{
$this->controller->saveAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers);
}
/**
* Check if answers of a Character for a Quest match the correct ones.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $answers Character answers for the Quest
*/
public function matchAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers)
{
return $this->controller->matchAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers);
}
/**
* Load the Controller of this Agent.
*
* @throws DatamodelException
* @throws DriverNotValidException
* @throws DriverNotFoundException
* @throws ViewNotFoundException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
* @throws QuesttypeControllerNotValidException
* @throws QuesttypeControllerNotFoundException
*/
protected function loadController()
{
// Determine Controller name
$controllerName = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::getClassName(get_class($this)));
// Determine ToplevelAgent
$toplevelAgentName = $this->response->getParam(0);
if(is_null($toplevelAgentName)) {
$toplevelAgentName = $this->request->getParam(0, 'toplevel');
$this->response->addParam($toplevelAgentName);
}
// Determine Action
$action = $this->response->getParam(2);
if(is_null($action)) {
$action = $this->request->getParam(2, 'action');
$this->response->addParam($action);
}
// Load Controller
\hhu\z\controllers\QuesttypeController::load($controllerName);
// Construct Controller
$this->controller = \hhu\z\controllers\QuesttypeController::factory($controllerName, $toplevelAgentName, $action, $this);
}
}
?>

View file

@ -0,0 +1,36 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\agents;
/**
* Abstract class for implementing an application Controller.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
abstract class ToplevelAgent extends \nre\agents\ToplevelAgent
{
protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
{
parent::__construct($request, $response, $log);
// Set timezone
date_default_timezone_set(\nre\configs\AppConfig::$app['timeZone']);
}
}
?>

View file

@ -0,0 +1,195 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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;
/**
* Abstract class for implementing a Controller of an IntermediateAgent.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
abstract class IntermediateController extends \hhu\z\Controller
{
/**
* Required models
*
* @var array
*/
public $models = array('users', 'userroles', 'seminaries', 'characters');
/**
* Current user
*
* @var array
*/
public static $user = null;
/**
* Title information
*
* @var array
*/
private $title = array();
/**
* Construct a new IntermediateController.
*
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ViewNotFoundException
* @param string $layoutName Name of the current Layout
* @param string $action Current Action
* @param Agent $agent Corresponding Agent
*/
public function __construct($layoutName, $action, $agent)
{
parent::__construct($layoutName, $action, $agent);
}
/**
* Prefilter that is executed before running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::preFilter($request, $response);
// Get userdata
try {
self::$user = $this->Users->getUserById($this->Auth->getUserId());
self::$user['roles'] = array_map(function($r) { return $r['name']; }, $this->Userroles->getUserrolesForUserById(self::$user['id']));
}
catch(\nre\exceptions\IdNotFoundException $e) {
}
// Check permissions
$this->checkPermission($request, $response);
// Set userdata
$this->set('loggedUser', self::$user);
}
/**
* Postfilter that is executed after running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::postFilter($request, $response);
}
/**
* Return current title information.
*
* @return string Title information
*/
public function getTitle()
{
return $this->title;
}
/**
* Add a piece of information to the current title.
*
* @param string $title Title information
*/
protected function addTitle($title)
{
$this->title[] = $title;
}
/**
* Add a piece of information to the current title and localize
* it.
*
* @param string $title Title information
*/
protected function addTitleLocalized($title)
{
$title = gettext($title);
$args = func_get_args();
if(count($args) > 0) {
$title = call_user_func_array(
'sprintf',
array_merge(
array($title),
array_slice($args, 1)
)
);
}
$this->title[] = $title;
}
/**
* Check user permissions.
*
* @throws AccessDeniedException
*/
private function checkPermission(\nre\core\Request $request, \nre\core\Response $response)
{
// Determine user
$userRoles = array('guest');
if(!is_null(self::$user)) {
$userRoles = self::$user['roles'];
}
// Do not check error pages
if($response->getParam(0, 'toplevel') == \nre\core\Config::getDefault('toplevel-error')) {
return;
}
if($response->getParam(1, 'intermediate') == \nre\core\Config::getDefault('intermediate-error')) {
return;
}
// Determine permissions of Intermediate Controller for current action
$controller = $this->agent->controller;
$action = $this->request->getParam(2, 'action');
if(!property_exists($controller, 'permissions')) {
return; // Allow if nothing is specified
}
if(!array_key_exists($action, $controller->permissions)) {
return; // Allow if Action is not specified
}
$permissions = $controller->permissions[$action];
// Check permissions
if(count(array_intersect($userRoles, $permissions)) == 0) {
throw new \nre\exceptions\AccessDeniedException();
}
}
}
?>

View file

@ -0,0 +1,308 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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;
/**
* Abstract class for implementing a QuesttypeController.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
abstract class QuesttypeController extends \hhu\z\Controller
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'questgroups', 'quests', 'characters');
/**
* Save the answers of a Character for a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $answers Character answers for the Quest
*/
public abstract function saveAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers);
/**
* Save additional data for the answers of a Character for a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $data Additional (POST-) data
*/
public abstract function saveDataForCharacterAnswers($seminary, $questgroup, $quest, $character, $data);
/**
* Check if answers of a Character for a Quest match the correct ones.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $answers Character answers for the Quest
* @return boolean True/false for a right/wrong answer or null for moderator evaluation
*/
public abstract function matchAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers);
/**
* Action: quest.
*
* Show the task of a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param Exception $exception Character submission exception
*/
public abstract function quest($seminary, $questgroup, $quest, $character, $exception);
/**
* Action: submission.
*
* Show the submission of a Character for a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
*/
public abstract function submission($seminary, $questgroup, $quest, $character);
/**
* Load a QuesttypeController.
*
* @static
* @throws QuesttypeControllerNotFoundException
* @throws QuesttypeControllerNotValidException
* @param string $controllerName Name of the QuesttypeController to load
*/
public static function load($controllerName)
{
// Determine full classname
$className = self::getClassName($controllerName);
try {
// Load class
static::loadClass($controllerName, $className);
// Validate class
static::checkClass($className, get_class());
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \hhu\z\exceptions\QuesttypeControllerNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \hhu\z\exceptions\QuesttypeControllerNotFoundException($e->getClassName());
}
}
/**
* Instantiate a QuesttypeController (Factory Pattern).
*
* @static
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
* @throws ViewNotFoundException
* @param string $controllerName Name of the QuesttypeController to instantiate
* @param string $layoutName Name of the current Layout
* @param string $action Current Action
*/
public static function factory($controllerName, $layoutName, $action, $agent)
{
// Determine full classname
$className = self::getClassName($controllerName);
// Construct and return Controller
return new $className($layoutName, $action, $agent);
}
/**
* Determine the Controller-classname for the given Questtype-name.
*
* @static
* @param string $questtypeName Questtype-name to get Controller-classname of
* @return string Classname for the Questtype-name
*/
private static function getClassName($questtypeName)
{
$className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'controller');
return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
}
/**
* Load the class of a QuesttypeController
*
* @static
* @throws ClassNotFoundException
* @param string $questtypeName Name of the QuesttypeController to load
* @param string $fullClassName Name of the class to load
*/
private static function loadClass($questtypeName, $fullClassName)
{
// Determine folder to look in
$className = explode('\\', $fullClassName);
$className = array_pop($className);
// Determine filename
$fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
// Check file
if(!file_exists($fileName))
{
throw new \nre\exceptions\ClassNotFoundException(
$fullClassName
);
}
// Include file
include_once($fileName);
}
/**
* Check inheritance of the QuesttypeController-class.
*
* @static
* @throws ClassNotValidException
* @param string $className Name of the class to check
* @param string $parentClassName Name of the parent class
*/
public static function checkClass($className, $parentClassName)
{
// Check if class is subclass of parent class
if(!is_subclass_of($className, $parentClassName)) {
throw new \nre\exceptions\ClassNotValidException(
$className
);
}
}
/**
* Construct a new application Controller.
*
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
* @throws ViewNotFoundException
* @param string $layoutName Name of the current Layout
* @param string $action Current Action
* @param Agent $agent Corresponding Agent
*/
public function __construct($layoutName, $action, $agent)
{
parent::__construct($layoutName, $action, $agent);
}
/**
* Load the Models of this Controller.
*
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
*/
protected function loadModels()
{
// Load default models
parent::loadModels();
// Load QuesttypeModel
$this->loadModel();
}
/**
* Load the Model of the Questtype.
*
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
*/
private function loadModel()
{
// Determine Model
$model = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class($this))));
// Load class
\hhu\z\models\QuesttypeModel::load($model);
// Construct Model
$modelName = ucfirst(strtolower($model));
$this->$modelName = \hhu\z\models\QuesttypeModel::factory($model);
}
/**
* Load the View of this QuesttypeController.
*
* @throws ViewNotFoundException
* @param string $layoutName Name of the current Layout
* @param string $action Current Action
*/
protected function loadView($layoutName, $action)
{
// Check Layout name
if(is_null($layoutName)) {
return;
}
// Determine controller name
$controllerName = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::getClassName(get_class($this)));
// Load view
$this->view = \hhu\z\views\QuesttypeView::loadAndFactory($layoutName, $controllerName, $action);
}
}
?>

View file

@ -0,0 +1,315 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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;
/**
* Abstract class for implementing a Controller for a Seminary and its
* concepts.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
abstract class SeminaryController extends \hhu\z\controllers\IntermediateController
{
/**
* Required components
*
* @var array
*/
public $components = array('achievement', 'auth', 'notification');
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'characters', 'characterroles', 'achievements');
/**
* Current Seminary
*
* var array
*/
public static $seminary = null;
/**
* Character of current user and Seminary
*
* @var array
*/
public static $character = null;
/**
* Construct a new Seminary Controller.
*
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ViewNotFoundException
* @param string $layoutName Name of the current Layout
* @param string $action Current Action
* @param Agent $agent Corresponding Agent
*/
public function __construct($layoutName, $action, $agent)
{
parent::__construct($layoutName, $action, $agent);
}
/**
* Prefilter that is executed before running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::preFilter($request, $response);
// Get Seminary and Character data
try {
self::$seminary = $this->Seminaries->getSeminaryByUrl($this->request->getParam(3));
if(!is_null(self::$user))
{
self::$character = $this->Characters->getCharacterForUserAndSeminary(self::$user['id'], self::$seminary['id']);
self::$character['characterroles'] = array_map(function($r) { return $r['name']; }, $this->Characterroles->getCharacterrolesForCharacterById(self::$character['id']));
}
}
catch(\nre\exceptions\IdNotFoundException $e) {
}
// Check permissions
$this->checkPermission($request, $response);
// Check achievements
$this->checkAchievements($request, $response, 'date');
$this->checkAchievements($request, $response, 'achievement');
// Set Seminary and Character data
$this->set('loggedSeminary', self::$seminary);
$this->set('loggedCharacter', self::$character);
}
/**
* Postfilter that is executed after running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::postFilter($request, $response);
}
/**
* Check user permissions.
*
* @throws AccessDeniedException
*/
private function checkPermission(\nre\core\Request $request, \nre\core\Response $response)
{
// Do not check index page
if(is_null($request->getParam(3))) {
return;
}
// Determine permissions for current action
$action = $this->request->getParam(2, 'action');
if(!property_exists($this, 'seminaryPermissions')) {
return; // Allow if nothing is specified
}
if(!array_key_exists($action, $this->seminaryPermissions)) {
return; // Allow if Action is not specified
}
$permissions = $this->seminaryPermissions[$action];
// Check permissions
if(is_null(self::$character) || !array_key_exists('characterroles', self::$character) || count(array_intersect(self::$character['characterroles'], $permissions)) == 0) {
throw new \nre\exceptions\AccessDeniedException();
}
}
/**
* Check for newly achieved Achievements.
*/
protected function checkAchievements(\nre\core\Request $request, \nre\core\Response $response, $checkConditions=null)
{
// Do not check MediaController
if($this->request->getParam(0, 'toplevel') != \nre\configs\AppConfig::$defaults['toplevel']) {
return;
}
// Check if Character is present
if(is_null(self::$character)) {
return;
}
// Set conditions to check
if(!is_null($checkConditions) && !is_array($checkConditions)) {
$checkConditions = array($checkConditions);
}
// Get unachieved Achievments
$achievements = $this->Achievements->getUnachhievedAchievementsForCharacter(self::$seminary['id'], self::$character['id']);
if(in_array('user', self::$character['characterroles'])) {
$achievements = array_merge($achievements, $this->Achievements->getUnachievedOnlyOnceAchievementsForSeminary(self::$seminary['id']));
}
// Check conditions
foreach($achievements as &$achievement)
{
// Check condition to test
if(!is_null($checkConditions) && !in_array($achievement['condition'], $checkConditions)) {
continue;
}
// Check deadline
if(!is_null($achievement['deadline']) && $achievement['deadline'] < date('Y-m-d H:i:s')) {
continue;
}
// Get conditions
$conditions = array();
$progress = 0;
switch($achievement['condition'])
{
// Date conditions
case 'date':
$conditionsDate = $this->Achievements->getAchievementConditionsDate($achievement['id']);
foreach($conditionsDate as &$condition)
{
$conditions[] = array(
'func' => 'checkAchievementConditionDate',
'params' => array(
$condition['select']
)
);
}
break;
// Character conditions
case 'character':
$conditionsCharacter = $this->Achievements->getAchievementConditionsCharacter($achievement['id']);
foreach($conditionsCharacter as &$condition)
{
$conditions[] = array(
'func' => 'checkAchievementConditionCharacter',
'params' => array(
$condition['field'],
$condition['value'],
self::$character['id']
)
);
}
break;
// Quest conditions
case 'quest':
$conditionsQuest = $this->Achievements->getAchievementConditionsQuest($achievement['id']);
foreach($conditionsQuest as &$condition)
{
$conditions[] = array(
'func' => 'checkAchievementConditionQuest',
'params' => array(
$condition['field'],
$condition['count'],
$condition['value'],
$condition['status'],
$condition['groupby'],
$condition['quest_id'],
self::$character['id']
)
);
}
break;
// Achievement conditions
case 'achievement':
$conditionsAchievement = $this->Achievements->getAchievementConditionsAchievement($achievement['id']);
foreach($conditionsAchievement as &$condition)
{
$conditions[] = array(
'func' => 'checkAchievementConditionAchievement',
'params' => array(
$condition['field'],
$condition['count'],
$condition['value'],
$condition['groupby'],
$condition['meta_achievement_id'],
self::$character['id']
)
);
}
break;
}
// Do not achieve Achievements without conditions
if(empty($conditions)) {
continue;
}
// Check conditions
$achieved = ($achievement['all_conditions'] == 1);
foreach($conditions as &$condition)
{
// Calculate result of condition
$result = call_user_func_array(
array(
$this->Achievements,
$condition['func']
),
$condition['params']
);
// The overall result and abort if possible
if($achievement['all_conditions'])
{
if(!$result) {
$achieved = false;
break;
}
}
else
{
if($result) {
$achieved = true;
break;
}
}
}
// Achievement achieved
if($achieved)
{
// Set status
$this->Achievements->setAchievementAchieved($achievement['id'], self::$character['id']);
// Add notification
$this->Notification->addNotification(
\hhu\z\controllers\components\NotificationComponent::TYPE_ACHIEVEMENT,
$achievement['title'],
$this->linker->link(array('achievements', 'index', self::$seminary['url']), 0, true, null, true, $achievement['url']),
(!is_null($achievement['achieved_achievementsmedia_id']) ? $this->linker->link(array('media','achievement',self::$seminary['url'],$achievement['url'])) : null)
);
}
}
}
}
?>

View file

@ -0,0 +1,75 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: File upload went wrong
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class FileUploadException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 203;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'File upload went wrong';
/**
* Nested message
*
* @var string
*/
private $nestedMessage;
/**
* Construct a new exception.
*/
function __construct($nestedMessage=null, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$nestedMessage
);
// Store values
$this->nestedMessage = $nestedMessage;
}
/**
* Get nested message.
*
* @return Nested message
*/
public function getNestedMessage()
{
return $this->nestedMessage;
}
}
?>

View file

@ -0,0 +1,51 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: File exceeds size maximum.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class MaxFilesizeException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 202;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'File exceeds size maximum';
/**
* Construct a new exception.
*/
function __construct($message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code
);
}
}
?>

View file

@ -0,0 +1,77 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: QuesttypeAgent not found.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuesttypeAgentNotFoundException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 101;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'QuesttypeAgent not found';
/**
* Name of the class that was not found
*
* @var string
*/
private $questtypeName;
/**
* Construct a new exception.
*
* @param string $questtypeName Name of the QuesttypeAgent that was not found
*/
function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$questtypeName
);
// Store values
$this->questtypeName = $questtypeName;
}
/**
* Get the name of the QuesttypeAgent that was not found.
*
* @return string Name of the QuesttypeAgent that was not found
*/
public function getClassName()
{
return $this->questtypeName;
}
}
?>

View file

@ -0,0 +1,77 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: QuesttypeAgent not valid.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuesttypeAgentNotValidException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 102;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'QuesttypeAgent not valid';
/**
* Name of the invalid class
*
* @var string
*/
private $questtypeName;
/**
* Construct a new exception.
*
* @param string $questtypeName Name of the invalid QuesttypeAgent
*/
function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$questtypeName
);
// Store value
$this->questtypeName = $questtypeName;
}
/**
* Get the name of the invalid QuesttypeAgent.
*
* @return string Name of the invalid QuesttypeAgent
*/
public function getClassName()
{
return $this->questtypeName;
}
}
?>

View file

@ -0,0 +1,77 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: QuesttypeController not found.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuesttypeControllerNotFoundException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 103;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'QuesttypeController not found';
/**
* Name of the class that was not found
*
* @var string
*/
private $questtypeName;
/**
* Construct a new exception.
*
* @param string $questtypeName Name of the QuesttypeController that was not found
*/
function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$questtypeName
);
// Store values
$this->questtypeName = $questtypeName;
}
/**
* Get the name of the QuesttypeController that was not found.
*
* @return string Name of the QuesttypeController that was not found
*/
public function getClassName()
{
return $this->questtypeName;
}
}
?>

View file

@ -0,0 +1,77 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: QuesttypeController not valid.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuesttypeControllerNotValidException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 104;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'QuesttypeController not valid';
/**
* Name of the invalid class
*
* @var string
*/
private $questtypeName;
/**
* Construct a new exception.
*
* @param string $questtypeName Name of the invalid QuesttypeController
*/
function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$questtypeName
);
// Store value
$this->questtypeName = $questtypeName;
}
/**
* Get the name of the invalid QuesttypeController.
*
* @return string Name of the invalid QuesttypeController
*/
public function getClassName()
{
return $this->questtypeName;
}
}
?>

View file

@ -0,0 +1,77 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: QuesttypeModel not found.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuesttypeModelNotFoundException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 105;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'QuesttypeModel not found';
/**
* Name of the class that was not found
*
* @var string
*/
private $questtypeName;
/**
* Construct a new exception.
*
* @param string $questtypeName Name of the QuesttypeModel that was not found
*/
function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$questtypeName
);
// Store values
$this->questtypeName = $questtypeName;
}
/**
* Get the name of the QuesttypeModel that was not found.
*
* @return string Name of the QuesttypeModel that was not found
*/
public function getClassName()
{
return $this->questtypeName;
}
}
?>

View file

@ -0,0 +1,77 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: QuesttypeModel not valid.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuesttypeModelNotValidException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 106;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'QuesttypeModel not valid';
/**
* Name of the invalid class
*
* @var string
*/
private $questtypeName;
/**
* Construct a new exception.
*
* @param string $questtypeName Name of the invalid QuesttypeModel
*/
function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$questtypeName
);
// Store value
$this->questtypeName = $questtypeName;
}
/**
* Get the name of the invalid QuesttypeModel.
*
* @return string Name of the invalid QuesttypeModel
*/
public function getClassName()
{
return $this->questtypeName;
}
}
?>

View file

@ -0,0 +1,77 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: Character submission not valid.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class SubmissionNotValidException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 200;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'Character submission not valid';
/**
* Nested exception
*
* @var Exception
*/
private $nestedException;
/**
* Construct a new exception.
*
* @param string $nestedException Nested exception
*/
function __construct($nestedException, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$nestedException
);
// Store value
$this->nestedException = $nestedException;
}
/**
* Get Nested exception.
*
* @return string Nested exception
*/
public function getNestedException()
{
return $this->nestedException;
}
}
?>

View file

@ -0,0 +1,75 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\exceptions;
/**
* Exception: File has wrong filetype.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class WrongFiletypeException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 201;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'File has wrong type “%s”';
/**
* Type of file
*
* @var string
*/
private $type;
/**
* Construct a new exception.
*/
function __construct($type, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$type
);
// Store values
$this->type = $type;
}
/**
* Get type of file.
*
* @return Type of file
*/
public function getType()
{
return $this->type;
}
}
?>

316
app/lib/Password.inc Normal file
View file

@ -0,0 +1,316 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\lib
{
/**
* Class to ensure that Compatibility library below is loaded.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class Password
{
/**
* Call this function to ensure this file is loaded.
*/
public static function load()
{
}
}
}
/**
* A Compatibility library with PHP 5.5's simplified password hashing API.
*
* @author Anthony Ferrara <ircmaxell@php.net>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @copyright 2012 The Authors
*/
namespace {
if (!defined('PASSWORD_DEFAULT')) {
define('PASSWORD_BCRYPT', 1);
define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
/**
* Hash the password using the specified algorithm
*
* @param string $password The password to hash
* @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
* @param array $options The options for the algorithm to use
*
* @return string|false The hashed password, or false on error.
*/
function password_hash($password, $algo, array $options = array()) {
if (!function_exists('crypt')) {
trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
return null;
}
if (!is_string($password)) {
trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
return null;
}
if (!is_int($algo)) {
trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
return null;
}
$resultLength = 0;
switch ($algo) {
case PASSWORD_BCRYPT:
// Note that this is a C constant, but not exposed to PHP, so we don't define it here.
$cost = 10;
if (isset($options['cost'])) {
$cost = $options['cost'];
if ($cost < 4 || $cost > 31) {
trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
return null;
}
}
// The length of salt to generate
$raw_salt_len = 16;
// The length required in the final serialization
$required_salt_len = 22;
$hash_format = sprintf("$2y$%02d$", $cost);
// The expected length of the final crypt() output
$resultLength = 60;
break;
default:
trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
return null;
}
$salt_requires_encoding = false;
if (isset($options['salt'])) {
switch (gettype($options['salt'])) {
case 'NULL':
case 'boolean':
case 'integer':
case 'double':
case 'string':
$salt = (string) $options['salt'];
break;
case 'object':
if (method_exists($options['salt'], '__tostring')) {
$salt = (string) $options['salt'];
break;
}
case 'array':
case 'resource':
default:
trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
return null;
}
if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
return null;
} elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
$salt_requires_encoding = true;
}
} else {
$buffer = '';
$buffer_valid = false;
if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
$buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
if ($buffer) {
$buffer_valid = true;
}
}
if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
$buffer = openssl_random_pseudo_bytes($raw_salt_len);
if ($buffer) {
$buffer_valid = true;
}
}
if (!$buffer_valid && @is_readable('/dev/urandom')) {
$f = fopen('/dev/urandom', 'r');
$read = PasswordCompat\binary\_strlen($buffer);
while ($read < $raw_salt_len) {
$buffer .= fread($f, $raw_salt_len - $read);
$read = PasswordCompat\binary\_strlen($buffer);
}
fclose($f);
if ($read >= $raw_salt_len) {
$buffer_valid = true;
}
}
if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
$bl = PasswordCompat\binary\_strlen($buffer);
for ($i = 0; $i < $raw_salt_len; $i++) {
if ($i < $bl) {
$buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
} else {
$buffer .= chr(mt_rand(0, 255));
}
}
}
$salt = $buffer;
$salt_requires_encoding = true;
}
if ($salt_requires_encoding) {
// encode string with the Base64 variant used by crypt
$base64_digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$bcrypt64_digits =
'./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$base64_string = base64_encode($salt);
$salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
}
$salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
$hash = $hash_format . $salt;
$ret = crypt($password, $hash);
if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
return false;
}
return $ret;
}
/**
* Get information about the password hash. Returns an array of the information
* that was used to generate the password hash.
*
* array(
* 'algo' => 1,
* 'algoName' => 'bcrypt',
* 'options' => array(
* 'cost' => 10,
* ),
* )
*
* @param string $hash The password hash to extract info from
*
* @return array The array of information about the hash.
*/
function password_get_info($hash) {
$return = array(
'algo' => 0,
'algoName' => 'unknown',
'options' => array(),
);
if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
$return['algo'] = PASSWORD_BCRYPT;
$return['algoName'] = 'bcrypt';
list($cost) = sscanf($hash, "$2y$%d$");
$return['options']['cost'] = $cost;
}
return $return;
}
/**
* Determine if the password hash needs to be rehashed according to the options provided
*
* If the answer is true, after validating the password using password_verify, rehash it.
*
* @param string $hash The hash to test
* @param int $algo The algorithm used for new password hashes
* @param array $options The options array passed to password_hash
*
* @return boolean True if the password needs to be rehashed.
*/
function password_needs_rehash($hash, $algo, array $options = array()) {
$info = password_get_info($hash);
if ($info['algo'] != $algo) {
return true;
}
switch ($algo) {
case PASSWORD_BCRYPT:
$cost = isset($options['cost']) ? $options['cost'] : 10;
if ($cost != $info['options']['cost']) {
return true;
}
break;
}
return false;
}
/**
* Verify a password against a hash using a timing attack resistant approach
*
* @param string $password The password to verify
* @param string $hash The hash to verify against
*
* @return boolean If the password matches the hash
*/
function password_verify($password, $hash) {
if (!function_exists('crypt')) {
trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
return false;
}
$ret = crypt($password, $hash);
if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
return false;
}
$status = 0;
for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
$status |= (ord($ret[$i]) ^ ord($hash[$i]));
}
return $status === 0;
}
}
}
namespace PasswordCompat\binary {
/**
* Count the number of bytes in a string
*
* We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
* In this case, strlen() will count the number of *characters* based on the internal encoding. A
* sequence of bytes might be regarded as a single multibyte character.
*
* @param string $binary_string The input string
*
* @internal
* @return int The number of bytes
*/
function _strlen($binary_string) {
if (function_exists('mb_strlen')) {
return mb_strlen($binary_string, '8bit');
}
return strlen($binary_string);
}
/**
* Get a substring based on byte limits
*
* @see _strlen()
*
* @param string $binary_string The input string
* @param int $start
* @param int $length
*
* @internal
* @return string The substring
*/
function _substr($binary_string, $start, $length) {
if (function_exists('mb_substr')) {
return mb_substr($binary_string, $start, $length, '8bit');
}
return substr($binary_string, $start, $length);
}
}

View file

@ -0,0 +1,154 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\models;
/**
* Abstract class for implementing a QuesttypeModel.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
abstract class QuesttypeModel extends \hhu\z\Model
{
/**
* Load a Model.
*
* @static
* @throws QuesttypeModelNotFoundException
* @throws QuesttypeModelNotValidException
* @param string $modelName Name of the QuesttypeModel to load
*/
public static function load($modelName)
{
// Determine full classname
$className = self::getClassName($modelName);
try {
// Load class
static::loadClass($modelName, $className);
// Validate class
static::checkClass($className, get_class());
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \hhu\z\exceptions\QuesttypeModelNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \hhu\z\exceptions\QuesttypeModelNotFoundException($e->getClassName());
}
}
/**
* Instantiate a QuesttypeModel (Factory Pattern).
*
* @static
* @param string $questtypeName Name of the QuesttypeModel to instantiate
*/
public static function factory($questtypeName)
{
// Determine full classname
$className = self::getClassName($questtypeName);
// Construct and return Model
return new $className();
}
/**
* Determine the Model-classname for the given Questtype-name.
*
* @static
* @param string $questtypeName Questtype-name to get Model-classname of
* @return string Classname for the Questtype-name
*/
private static function getClassName($questtypeName)
{
$className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'model');
return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
}
/**
* Load the class of a QuesttypeModel.
*
* @static
* @throws ClassNotFoundException
* @param string $questtypeName Name of the QuesttypeModel to load
* @param string $fullClassName Name of the class to load
*/
private static function loadClass($questtypeName, $fullClassName)
{
// Determine folder to look in
$className = explode('\\', $fullClassName);
$className = array_pop($className);
// Determine filename
$fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
// Check file
if(!file_exists($fileName))
{
throw new \nre\exceptions\ClassNotFoundException(
$fullClassName
);
}
// Include file
include_once($fileName);
}
/**
* Check inheritance of the QuesttypeModel-class.
*
* @static
* @throws ClassNotValidException
* @param string $className Name of the class to check
* @param string $parentClassName Name of the parent class
*/
public static function checkClass($className, $parentClassName)
{
// Check if class is subclass of parent class
if(!is_subclass_of($className, $parentClassName)) {
throw new \nre\exceptions\ClassNotValidException(
$className
);
}
}
/**
* Construct a new QuesttypeModel.
*
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws QuesttypeModelNotValidException
* @throws QuesttypeModelNotFoundException
*/
public function __construct()
{
parent::__construct();
}
}
?>

View file

@ -0,0 +1,76 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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\views;
/**
* Abstract class for implementing a QuesttypeView.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuesttypeView extends \nre\core\View
{
/**
* Load and instantiate the QuesttypeView of a QuesttypeAgent.
*
* @throws ViewNotFoundException
* @param string $layoutName Name of Layout in use
* @param string $agentName Name of the Agent
* @param string $action Current Action
* @param bool $isToplevel Agent is a ToplevelAgent
*/
public static function loadAndFactory($layoutName, $agentName=null, $action=null, $isToplevel=false)
{
return new QuesttypeView($layoutName, $agentName, $action, $isToplevel);
}
/**
* Construct a new QuesttypeView.
*
* @throws ViewNotFoundException
* @param string $layoutName Name of Layout in use
* @param string $agentName Name of the Agent
* @param string $action Current Action
* @param bool $isToplevel Agent is a ToplevelAgent
*/
protected function __construct($layoutName, $agentName=null, $action=null, $isToplevel=false)
{
// Create template filename
// LayoutName
$fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($agentName).DS.strtolower($layoutName).DS;
// Action
$fileName .= strtolower($action);
// File extension
$fileName .= \nre\configs\CoreConfig::getFileExt('views');
// Check template file
if(!file_exists($fileName)) {
throw new \nre\exceptions\ViewNotFoundException($fileName);
}
// Save filename
$this->templateFilename = $fileName;
}
}
?>

33
bootstrap.inc Normal file
View file

@ -0,0 +1,33 @@
<?php
/**
* NRE
*
* @author coderkun <olli@coderkun.de>
* @copyright 2013 coderkun (http://www.coderkun.de)
* @license http://www.gnu.org/licenses/gpl.html
* @link http://www.coderkun.de/projects/nre
*/
// Include required classes
require_once(ROOT.DS.'configs'.DS.'CoreConfig.inc');
require_once(ROOT.DS.\nre\configs\CoreConfig::getClassDir('core').DS.'Autoloader.inc');
// Set PHP-logging
ini_set('error_log', ROOT.DS.\nre\configs\CoreConfig::getClassDir('logs').DS.'php'.\nre\configs\CoreConfig::getFileExt('logs'));
// Register autoloader
\nre\core\Autoloader::register();
// Initialize WebApi
$webApi = new \nre\apis\WebApi();
// Run WebApi
$webApi->run();
// Render output
$webApi->render();
?>

298
configs/AppConfig.inc Normal file
View file

@ -0,0 +1,298 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 nre\configs;
/**
* Application configuration.
*
* This class contains static variables with configuration values for
* the specific application.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
final class AppConfig
{
/**
* Application values
*
* @static
* @var array
*/
public static $app = array(
'name' => 'Questlab',
'genericname' => 'The Legend of Z',
'namespace' => 'hhu\\z\\',
'timeZone' => 'Europe/Berlin',
'mailsender' => 'noreply@zyren.inf-d.de'
);
/**
* Default values
*
* @static
* @var array
*/
public static $defaults = array(
'toplevel' => 'html',
'toplevel-error' => 'fault',
'intermediate' => 'introduction',
'intermediate-error' => 'error',
'language' => 'de_DE.utf8',
'locale' => 'de-DE'
);
/**
* Directories
*
* @static
* @var array
*/
public static $dirs = array(
'locale' => 'locale',
'media' => 'media',
'seminarymedia' => 'seminarymedia',
'questtypes' => 'questtypes',
'temporary' => 'tmp',
'uploads' => 'uploads',
'seminaryuploads' => 'seminaryuploads'
);
/**
* Media sizes
*
* @static
* @var array
*/
public static $media = array(
'questgroup' => array(
'width' => 480,
'height' => 5000
),
'avatar' => array(
'width' => 500,
'height' => 500
),
'charactergroup' => array(
'width' => 80,
'height' => 80
),
'charactergroupsquest' => array(
'width' => 80,
'height' => 80
)
);
/**
* Allowed mimetypes with sizes
*
* @static
* @var array
*/
public static $mimetypes = array(
'icons' => array(
array(
'mimetype' => 'image/jpeg',
'size' => 102400
),
array(
'mimetype' => 'image/png',
'size' => 204800
)
),
'charactergroupsquests' => array(
array(
'mimetype' => 'image/jpeg',
'size' => 1048576
)
)
);
/**
* Miscellaneous settings
*
* @static
* @var array
*/
public static $misc = array(
'ranking_range' => 2,
'achievements_range' => 3,
'title_delimiter' => ' ',
'questlist_limit' => 10
);
/**
* Validation settings for user input
*
* @static
* @var array
*/
public static $validation = array(
'username' => array(
'minlength' => 5,
'maxlength' => 12,
'regex' => '/^\w*$/'
),
'email' => array(
'regex' => '/^\S+@[\w\d.-]{2,}\.[\w]{2,6}$/iU'
),
'prename' => array(
'minlength' => 2,
'maxlength' => 32,
'regex' => '/^(\S| )*$/'
),
'surname' => array(
'minlength' => 2,
'maxlength' => 32,
'regex' => '/^\S*$/'
),
'password' => array(
'minlength' => 5,
'maxlength' => 64
),
'charactername' => array(
'minlength' => 5,
'maxlength' => 12,
'regex' => '/^\w*$/'
),
'charactergroupsgroupname' => array(
'minlength' => 4,
'maxlength' => 32,
'regex' => '/^(\S| )*$/'
),
'preferred' => array(
'regex' => '/^(0|1)$/'
),
'charactergroupname' => array(
'minlength' => 4,
'maxlength' => 32,
'regex' => '/^(\S| )*$/'
),
'motto' => array(
'maxlength' => 128
),
'title' => array(
'minlength' => 4,
'maxlength' => 32,
'regex' => '/^(\S| )*$/'
),
'xps' => array(
'minlength' => 1,
'regex' => '/^(\d*)$/'
)
);
/**
* Routes
*
* @static
* @var array
*/
public static $routes = array(
array('^users/([^/]+)/(edit|delete)/?$', 'users/$2/$1', true),
array('^users/(?!(index|login|register|logout|manage|create|edit|delete))/?', 'users/user/$1', true),
array('^seminaries/([^/]+)/(edit|delete)/?$', 'seminaries/$2/$1', true),
array('^seminaries/(?!(index|create|edit|delete|calculatexps))/?', 'seminaries/seminary/$1', true),
array('^questgroups/([^/]+)/(create)/?$', 'questgroups/$2/$1', true),
array('^questgroups/([^/]+)/([^/]+)/?$', 'questgroups/questgroup/$1/$2', true),
array('^quests/([^/]+)/?$', 'quests/index/$1', true),
array('^quests/([^/]+)/all/?$', 'quests/index/$1/all', true),
array('^quests/([^/]+)/(create|createmedia)/?$', 'quests/$2/$1' , true),
array('^quests/([^/]+)/([^/]+)/([^/]+)/(submissions)/?$', 'quests/$4/$1/$2/$3', true),
array('^quests/([^/]+)/([^/]+)/([^/]+)/(submission)/([^/]+)/?$', 'quests/$4/$1/$2/$3/$5', true),
array('^quests/(?!(index|create|createmedia))/?', 'quests/quest/$1', true),
array('^characters/([^/]+)/(register|manage)/?$', 'characters/$2/$1', true),
array('^characters/([^/]+)/?$', 'characters/index/$1', true),
array('^characters/([^/]+)/([^/]+)/(edit|delete)/?$', 'characters/$3/$1/$2', true),
array('^characters/([^/]+)/(?!(index|register|manage))/?', 'characters/character/$1/$2', true),
array('^charactergroups/([^/]+)/?$', 'charactergroups/index/$1', true),
array('^charactergroups/([^/]+)/(create)/?$', 'charactergroups/creategroupsgroup/$1/$2', true),
array('^charactergroups/([^/]+)/([^/]+)/?$', 'charactergroups/groupsgroup/$1/$2', true),
array('^charactergroups/([^/]+)/([^/]+)/(edit|delete)/?$', 'charactergroups/$3groupsgroup/$1/$2', true),
array('^charactergroups/([^/]+)/([^/]+)/(create)/?$', 'charactergroups/creategroup/$1/$2/$3', true),
array('^charactergroups/([^/]+)/([^/]+)/([^/]+)/?$', 'charactergroups/group/$1/$2/$3', true),
array('^charactergroups/([^/]+)/([^/]+)/([^/]+)/(manage|edit|delete)/?$', 'charactergroups/$4group/$1/$2/$3', true),
array('^charactergroupsquests/([^/]+)/([^/]+)/create/?$', 'charactergroupsquests/create/$1/$2', true),
array('^charactergroupsquests/([^/]+)/([^/]+)/([^/]+)/?$', 'charactergroupsquests/quest/$1/$2/$3', true),
array('^charactergroupsquests/([^/]+)/([^/]+)/([^/]+)/(edit|delete|manage)/?$', 'charactergroupsquests/$4/$1/$2/$3', true),
array('^achievements/([^/]+)/?$', 'achievements/index/$1', true),
array('^library/([^/]+)/?$', 'library/index/$1', true),
array('^library/([^/]+)/create/?$', 'library/create/$1', true),
array('^library/([^/]+)/([^/]+)/?$', 'library/topic/$1/$2', true),
array('^library/([^/]+)/([^/]+)/(edit|delete|manage)/?$', 'library/$3/$1/$2', true),
array('^media/(.*)$', 'media/$1?layout=binary', false),
array('^uploads/(.*)$', 'uploads/$1?layout=binary', false)
);
/**
* Reverse routes
*
* @static
* @var array
*/
public static $reverseRoutes = array(
array('^users/user/(.*)$', 'users/$1', true),
array('^users/([^/]+)/(.*)$', 'users/$2/$1', true),
array('^seminaries/seminary/(.*)$', 'seminaries/$1', false),
array('^questgroups/create/(.*)$', 'questgroups/$2/$1', true),
array('^questgroups/questgroup/(.*)$', 'questgroups/$1', true),
array('^quests/index/(.+)$', 'quests/$1', true),
array('^quests/quest/(.*)$', 'quests/$1', true),
array('^quests/(create|createmedia)/(.*)$', 'quests/$2/$1' , true),
array('^quests/(submissions)/(.*)$', 'quests/$2/$1', true),
array('^quests/(submission)/([^/]+)/([^/]+)/([^/]+)/([^/]+)$', 'quests/$2/$3/$4/$1/$5', true),
array('^characters/(index|character)/(.*)$', 'characters/$2', true),
array('^characters/(register|manage)/([^/]+)$', 'characters/$2/$1', true),
array('^characters/(edit|delete)/([^/]+)/([^/]+)$', 'characters/$2/$3/$1', true),
array('^charactergroups/index/([^/]+)$', 'charactergroups/$1', true),
array('^charactergroups/creategroupsgroup/([^/]+)$', 'charactergroups/$1/create', true),
array('^charactergroups/groupsgroup/([^/]+)/([^/]+)$', 'charactergroups/$1/$2', true),
array('^charactergroups/(edit|delete)groupsgroup/([^/]+)/([^/]+)$', 'charactergroups/$2/$3/$1', true),
array('^charactergroups/creategroup/([^/]+)/([^/]+)$', 'charactergroups/$1/$2/create', true),
array('^charactergroups/group/([^/]+)/([^/]+)/([^/]+)$', 'charactergroups/$1/$2/$3', true),
array('^charactergroups/(manage|edit|delete)group/([^/]+)/([^/]+)/([^/]+)$', 'charactergroups/$2/$3/$4/$1', true),
array('^charactergroupsquests/create/([^/]+)/([^/]+)/?$', 'charactergroupsquests/$1/$2/create', true),
array('^charactergroupsquests/quest/(.*)$', 'charactergroupsquests/$1', true),
array('^charactergroupsquests/(edit|delete|manage)/([^/]+)/([^/]+)/([^/]+)$', 'charactergroupsquests/$2/$3/$4/$1', true),
array('^achievements/index/(.*)$', 'achievements/$1', true),
array('^library/index/([^/]+)/?$', 'library/$1', true),
array('^library/create/([^/]+)/?$', 'library/$1/create', true),
array('^library/topic/([^/]+)/([^/]+)/?$', 'library/$1/$2', true),
array('^library/(edit|delete|manage)/([^/]+)/([^/]+)/?$', 'library/$2/$3/$1', true)
);
/**
* Database connection settings
*
* @static
* @var array
*/
public static $database = array(
'user' => 'z',
'host' => 'localhost',
'password' => 'legendofZ',
'db' => 'z'
);
}
?>

167
configs/CoreConfig.inc Normal file
View file

@ -0,0 +1,167 @@
<?php
/**
* NRE
*
* @author coderkun <olli@coderkun.de>
* @copyright 2013 coderkun (http://www.coderkun.de)
* @license http://www.gnu.org/licenses/gpl.html
* @link http://www.coderkun.de/projects/nre
*/
namespace nre\configs;
/**
* Core configuration.
*
* This class contains static variables with configuration values.
*
* @author coderkun <olli@coderkun.de>
*/
final class CoreConfig
{
/**
* Core values
*
* @static
* @var array
*/
public static $core = array(
'namespace' => 'nre\\',
);
/**
* Directories
*
* @static
* @var array
*/
public static $dirs = array(
'core' => 'core',
'publicDir' => 'www'
);
/**
* File extensions
*
* @static
* @var array
*/
public static $fileExts = array(
'default' => 'inc',
'views' => 'tpl',
'logs' => 'log',
);
/**
* Default values
*
* @static
* @var array
*/
public static $defaults = array(
'action' => 'index',
'errorFile' => 'error',
'inlineErrorFile' => 'inlineerror'
);
/**
* Miscellaneous settings
*
* @static
* @var array
*/
public static $misc = array(
'fileExtDot' => '.'
);
/**
* Logging settings
*
* @static
* @var array
*/
public static $log = array(
'filename' => 'errors',
'format' => 'Fehler %d: %s in %s, Zeile %d'
);
/**
* Class-specific settings
*
* @static
* @var array
*/
public static $classes = array(
'linker' => array(
'url' => array(
'length' => 128,
'delimiter' => '-'
)
)
);
/**
* Determine the directory for a specific classtype.
*
* @param string $classType Classtype to get directory of
* @return string Directory of given classtype
*/
public static function getClassDir($classType)
{
// Default directory (for core classes)
$classDir = self::$dirs['core'];
// Configurable directory
if(array_key_exists($classType, self::$dirs)) {
$classDir = self::$dirs[$classType];
}
else
{
// Default directory for classtype
if(is_dir(ROOT.DS.$classType)) {
$classDir = $classType;
}
}
// Return directory
return $classDir;
}
/**
* Determine the file extension for a specific filetype.
*
* @param string $fileType Filetype to get file extension of
* @return string File extension of given filetype
*/
public static function getFileExt($fileType)
{
// Default file extension
$fileExt = self::$fileExts['default'];
// Configurable file extension
if(array_key_exists($fileType, self::$fileExts)) {
$fileExt = self::$fileExts[$fileType];
}
// Return file extension
return self::$misc['fileExtDot'].$fileExt;
}
}
?>

View file

@ -0,0 +1,189 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 Agent to list Achievements.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class AchievementsController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('achievements', 'seminaries', 'media', 'characters');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'index' => array('admin', 'moderator', 'user')
);
/**
* Action: index.
*
* List Achievements of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of Seminary
*/
public function index($seminaryUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character
$character = SeminaryController::$character;
// Get seldom Achievements
$seldomAchievements = $this->Achievements->getSeldomAchievements($seminary['id'], \nre\configs\AppConfig::$misc['achievements_range'], false);
foreach($seldomAchievements as &$achievement) {
$achievement['achieved'] = $this->Achievements->hasCharacterAchievedAchievement($achievement['id'], $character['id']);
}
// Get Characters with the most Achievements
$successfulCharacters = $this->Characters->getCharactersWithMostAchievements($seminary['id'], \nre\configs\AppConfig::$misc['achievements_range'], false);
// Get total count of Achievements for Seminary
$achievementsCount = $this->Achievements->getAchievementsCountForSeminary($seminary['id'], false);
// Get achieved Achievements
$achievedAchievements = $this->Achievements->getAchievedAchievementsForCharacter($character['id']);
// Get unachieved Achievements
$unachievedAchievements = array_merge(
$this->Achievements->getUnachhievedAchievementsForCharacter($seminary['id'], $character['id'], false, false),
$this->Achievements->getUnachievedOnlyOnceAchievementsForSeminary($seminary['id'])
);
usort($unachievedAchievements, function($a, $b) {
if($a['pos'] == $b['pos']) {
return 0;
}
return ($a['pos'] > $b['pos']) ? 1 : -1;
});
foreach($unachievedAchievements as &$achievement)
{
// Get Character progress
if($achievement['progress'])
{
$conditions = array();
switch($achievement['condition'])
{
// Character conditions
case 'character':
$conditionsCharacter = $this->Achievements->getAchievementConditionsCharacter($achievement['id']);
foreach($conditionsCharacter as &$condition)
{
$conditions[] = array(
'func' => 'getAchievementConditionCharacterProgress',
'params' => array(
$condition['field'],
$condition['value'],
$character['id']
)
);
}
break;
// Quest conditions
case 'quest':
$conditionsQuest = $this->Achievements->getAchievementConditionsQuest($achievement['id']);
foreach($conditionsQuest as &$condition)
{
$conditions[] = array(
'func' => 'getAchievementConditionQuestProgress',
'params' => array(
$condition['field'],
$condition['count'],
$condition['value'],
$condition['status'],
$condition['groupby'],
$condition['quest_id'],
$character['id']
)
);
}
break;
// Achievement conditions
case 'achievement':
$conditionsAchievement = $this->Achievements->getAchievementConditionsAchievement($achievement['id']);
foreach($conditionsAchievement as &$condition)
{
$conditions[] = array(
'func' => 'getAchievementConditionAchievementProgress',
'params' => array(
$condition['field'],
$condition['count'],
$condition['value'],
$condition['groupby'],
$condition['meta_achievement_id'],
$character['id']
)
);
}
break;
}
$characterProgresses = array();
foreach($conditions as &$condition)
{
// Calculate progress of condition
$characterProgresses[] = call_user_func_array(
array(
$this->Achievements,
$condition['func']
),
$condition['params']
);
}
$achievement['characterProgress'] = array_sum($characterProgresses) / count($characterProgresses);
}
}
// Get ranking
$character['rank'] = $this->Achievements->getCountRank($seminary['id'], count($achievedAchievements));
// Set title
$this->addTitleLocalized('Achievements');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('character', $character);
$this->set('seldomAchievements', $seldomAchievements);
$this->set('successfulCharacters', $successfulCharacters);
$this->set('achievementsCount', $achievementsCount);
$this->set('achievedAchievements', $achievedAchievements);
$this->set('unachievedAchievements', $unachievedAchievements);
}
}
?>

View file

@ -0,0 +1,37 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 BinaryAgent to show binary data.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class BinaryController extends \hhu\z\controllers\IntermediateController
{
/**
* Action: index.
*
* Create binary data.
*/
public function index()
{
}
}
?>

View file

@ -0,0 +1,759 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 CharactergroupsAgent to display Character groups.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class CharactergroupsController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'charactergroups', 'charactergroupsquests', 'characters', 'avatars', 'media');
/**
* Required components
*
* @var array
*/
public $components = array('validation');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user'),
'groupsgroup' => array('admin', 'moderator', 'user'),
'creategroupsgroup' => array('admin', 'moderator', 'user'),
'editgroupsgroup' => array('admin', 'moderator', 'user'),
'deletegroupsgroup' => array('admin', 'moderator', 'user'),
'group' => array('admin', 'moderator', 'user'),
'managegroup' => array('admin', 'moderator', 'user'),
'creategroup' => array('admin', 'moderator', 'user'),
'editgroup' => array('admin', 'moderator', 'user'),
'deletegroup' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'index' => array('admin', 'moderator', 'user'),
'groupsgroup' => array('admin', 'moderator', 'user'),
'creategroupsgroup' => array('admin', 'moderator'),
'editgroupsgroup' => array('admin', 'moderator'),
'deletegroupsgroup' => array('admin', 'moderator'),
'group' => array('admin', 'moderator', 'user'),
'managegroup' => array('admin', 'moderator'),
'creategroup' => array('admin', 'moderator'),
'editgroup' => array('admin', 'moderator', 'user'),
'deletegroup' => array('admin', 'moderator')
);
/**
* Action: index.
*
* Show Character groups-groups for a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
*/
public function index($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-groups
$groupsgroups = $this->Charactergroups->getGroupsroupsForSeminary($seminary['id']);
// Set titile
$this->addTitleLocalized('Character Groups');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroups', $groupsgroups);
}
/**
* Action: groupsgroups.
*
* Show Character groups for a Character groups-group of a
* Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
*/
public function groupsgroup($seminaryUrl, $groupsgroupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character groups
$groups = $this->Charactergroups->getGroupsForGroupsgroup($groupsgroup['id'], 'xps');
// Get Character groups-group Quests
$quests = $this->Charactergroupsquests->getQuestsForCharactergroupsgroup($groupsgroup['id']);
// Set titile
$this->addTitle($groupsgroup['name']);
$this->addTitleLocalized('Character Groups');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('groups', $groups);
$this->set('quests', $quests);
}
/**
* Action: creategroupsgroups.
*
* Create a new Character groups-group for a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
*/
public function creategroupsgroup($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Values
$charactergroupsgroupname = '';
$preferred = false;
$fields = array('charactergroupsgroupname');
$validation = array();
// Create a new Character groups-group
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
{
// Get params and validate them
$validation = $this->Validation->validateParams($this->request->getPostParams(), $fields);
$charactergroupsgroupname = $this->request->getPostParam('charactergroupsgroupname');
if($this->Charactergroups->characterGroupsgroupNameExists($charactergroupsgroupname)) {
$validation = $this->Validation->addValidationResult($validation, 'charactergroupsgroupname', 'exist', true);
}
$preferred = !is_null($this->request->getPostParam('preferred'));
// Create groups-group
if($validation === true)
{
$groupsgroupId = $this->Charactergroups->createGroupsgroup(
$this->Auth->getUserId(),
$seminary['id'],
$charactergroupsgroupname,
$preferred
);
// Redirect to groups-group page
$groupsgroup = $this->Charactergroups->getGroupsgroupById($groupsgroupId);
$this->redirect($this->linker->link(array('groupsgroup', $seminary['url'], $groupsgroup['url']), 1));
}
}
// Get validation settings
$validationSettings = array();
foreach($fields as &$field) {
$validationSettings[$field] = \nre\configs\AppConfig::$validation[$field];
}
// Set titile
$this->addTitleLocalized('New Character groups-group');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('charactergroupsgroupname', $charactergroupsgroupname);
$this->set('preferred', $preferred);
$this->set('validation', $validation);
$this->set('validationSettings', $validationSettings);
}
/**
* Action: editgroupsgroups.
*
* Edit a Character groups-group of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
*/
public function editgroupsgroup($seminaryUrl, $groupsgroupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Values
$charactergroupsgroupname = $groupsgroup['name'];
$preferred = $groupsgroup['preferred'];
$fields = array('charactergroupsgroupname');
$validation = array();
// Edit Character groups-group
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('edit')))
{
// Get params and validate them
$validation = $this->Validation->validateParams($this->request->getPostParams(), $fields);
$charactergroupsgroupname = $this->request->getPostParam('charactergroupsgroupname');
if($this->Charactergroups->characterGroupsgroupNameExists($charactergroupsgroupname, $groupsgroup['id'])) {
$validation = $this->Validation->addValidationResult($validation, 'charactergroupsgroupname', 'exist', true);
}
$preferred = !is_null($this->request->getPostParam('preferred'));
// Edit groups-group
if($validation === true)
{
$this->Charactergroups->editGroupsgroup(
$groupsgroup['id'],
$charactergroupsgroupname,
$preferred
);
// Redirect to user page
$groupsgroup = $this->Charactergroups->getGroupsgroupById($groupsgroup['id']);
$this->redirect($this->linker->link(array('groupsgroup', $seminary['url'], $groupsgroup['url']), 1));
}
}
// Get validation settings
$validationSettings = array();
foreach($fields as &$field) {
$validationSettings[$field] = \nre\configs\AppConfig::$validation[$field];
}
// Set titile
$this->addTitleLocalized('Edit Character groups-group');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('charactergroupsgroupname', $charactergroupsgroupname);
$this->set('preferred', $preferred);
$this->set('validation', $validation);
$this->set('validationSettings', $validationSettings);
}
/**
* Action: deletegroupsgroups.
*
* Delete a Character groups-group of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
*/
public function deletegroupsgroup($seminaryUrl, $groupsgroupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Check confirmation
if(!is_null($this->request->getPostParam('delete')))
{
// Delete seminary
$this->Charactergroups->deleteGroupsgroup($groupsgroup['id']);
// Redirect to overview
$this->redirect($this->linker->link(array('index', $seminary['url']), 1));
}
// Redirect to entry
$this->redirect($this->linker->link(array('groupsgroup', $seminary['url'], $groupsgroup['url']), 1));
}
// Set titile
$this->addTitleLocalized('Delete Character groups-group');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
}
/**
* Action: group.
*
* Show a Character group for a Character groups-group of a
* Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $groupUrl URL-Title of a Character group
*/
public function group($seminaryUrl, $groupsgroupUrl, $groupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character group
$group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
$group['characters'] = $this->Characters->getCharactersForGroup($group['id']);
$group['rank'] = $this->Charactergroups->getXPRank($groupsgroup['id'], $group['xps']);
// Get Character avatars
foreach($group['characters'] as &$character)
{
$avatar = $this->Avatars->getAvatarById($character['avatar_id']);
if(!is_null($avatar['small_avatarpicture_id'])) {
$character['small_avatar'] = $this->Media->getSeminaryMediaById($avatar['small_avatarpicture_id']);
}
}
// Get Character groups Quests
$quests = $this->Charactergroupsquests->getQuestsForGroup($group['id']);
// Set titile
$this->addTitle($group['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('group', $group);
$this->set('quests', $quests);
}
/**
* Action: managegroup.
*
* Manage a Character group for a Character groups-group of a
* Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $groupUrl URL-Title of a Character group
*/
public function managegroup($seminaryUrl, $groupsgroupUrl, $groupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character group
$group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
// Manage
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('actions')) && count($this->request->getPostParam('actions')) > 0) // && !is_null($this->request->getPostParam('characters')) && count($this->request->getPostParam('characters')) > 0)
{
$actions = $this->request->getPostParam('actions');
$action = array_keys($actions)[0];
$selectedCharacters = $this->request->getPostParam('characters');
switch($action)
{
// Add Characters to group
case 'addcharacters':
foreach($selectedCharacters as &$characterId) {
$this->Charactergroups->addCharacterToCharactergroup($group['id'], $characterId);
}
break;
// Remove Characters from group
case 'removecharacters':
foreach($selectedCharacters as &$characterId) {
$this->Charactergroups->removeCharacterFromCharactergroup($group['id'], $characterId);
}
break;
}
}
// Get additional data for group
$group['characters'] = $this->Characters->getCharactersForGroup($group['id']);
$group['rank'] = $this->Charactergroups->getXPRank($groupsgroup['id'], $group['xps']);
// Get Character avatars
foreach($group['characters'] as &$character)
{
$avatar = $this->Avatars->getAvatarById($character['avatar_id']);
if(!is_null($avatar['small_avatarpicture_id'])) {
$character['small_avatar'] = $this->Media->getSeminaryMediaById($avatar['small_avatarpicture_id']);
}
}
// Get Character groups Quests
$quests = $this->Charactergroupsquests->getQuestsForGroup($group['id']);
// Get all Characters of Seminary
$groupCharacterIds = array_map(function($c) { return $c['id']; }, $group['characters']);
$seminaryCharacters = $this->Characters->getCharactersForSeminary($seminary['id'], true);
$characters = array();
foreach($seminaryCharacters as &$character) {
if(!in_array($character['id'], $groupCharacterIds)) {
$characters[] = $character;
}
}
// Set titile
$this->addTitle($group['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('group', $group);
$this->set('quests', $quests);
$this->set('characters', $characters);
}
/**
* Action: creategroup.
*
* Create a Character group for a Character groups-group of a
* Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
*/
public function creategroup($seminaryUrl, $groupsgroupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get allowed mimetypes
$mimetypes = \nre\configs\AppConfig::$mimetypes['icons'];
// Values
$charactergroupname = '';
$motto = '';
$fields = array('charactergroupname', 'motto');
$validation = array();
// Create a new Character groups-group
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
{
// Get params and validate them
$validation = $this->Validation->validateParams($this->request->getPostParams(), $fields);
$charactergroupname = $this->request->getPostParam('charactergroupname');
if($this->Charactergroups->characterGroupNameExists($charactergroupname)) {
$validation = $this->Validation->addValidationResult($validation, 'charactergroupname', 'exist', true);
}
$motto = $this->request->getPostParam('motto');
// Validate icon
$icon = null;
if(!empty($_FILES) && array_key_exists('icon', $_FILES) && $_FILES['icon']['error'] != UPLOAD_ERR_NO_FILE)
{
$icon = $_FILES['icon'];
// Check error
if($icon['error'] !== UPLOAD_ERR_OK) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'error', $icon['error']);
}
// Check mimetype
$mediaMimetype = null;
$icon['mimetype'] = \hhu\z\Utils::getMimetype($icon['tmp_name'], $icon['type']);
foreach($mimetypes as &$mimetype) {
if($mimetype['mimetype'] == $icon['mimetype']) {
$mediaMimetype = $mimetype;
break;
}
}
if(is_null($mediaMimetype)) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'mimetype', $icon['mimetype']);
}
elseif($icon['size'] > $mediaMimetype['size']) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'size', $mediaMimetype['size']);
}
}
// Create group
if($validation === true)
{
$groupId = $this->Charactergroups->createGroup(
$this->Auth->getUserId(),
$groupsgroup['id'],
$charactergroupname,
$motto
);
$group = $this->Charactergroups->getGroupById($groupId);
// Upload icon
if(!is_null($icon))
{
$mediaId = $this->Media->createCharactergroupMedia(
$this->Auth->getUserId(),
$seminary['id'],
sprintf('charactergroup-%s', $group['url']),
'',
$icon['mimetype'],
$icon['tmp_name']
);
if($mediaId !== false) {
$this->Charactergroups->setMediaForGroup($group['id'], $mediaId);
}
}
// Redirect to group page
$this->redirect($this->linker->link(array('group', $seminary['url'], $groupsgroup['url'], $group['url']), 1));
}
}
// Get validation settings
$validationSettings = array();
foreach($fields as &$field) {
$validationSettings[$field] = \nre\configs\AppConfig::$validation[$field];
}
// Set title
$this->addTitleLocalized('New %s Character group', $groupsgroup['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('charactergroupname', $charactergroupname);
$this->set('motto', $motto);
$this->set('mimetypes', $mimetypes);
$this->set('validation', $validation);
$this->set('validationSettings', $validationSettings);
}
/**
* Action: editgroup.
*
* Edit a Character group for a Character groups-group of a
* Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $groupUrl URL-Title of a Character group
*/
public function editgroup($seminaryUrl, $groupsgroupUrl, $groupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character group
$group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
$group['characters'] = $this->Characters->getCharactersForGroup($group['id']);
// Check permission
if(count(array_intersect(array('admin', 'moderator'), \hhu\z\controllers\SeminaryController::$character['characterroles'])) == 0 && !in_array(\hhu\z\controllers\SeminaryController::$character['id'], array_map(function($c) { return $c['id']; }, $group['characters']))) {
throw new \nre\exceptions\AccessDeniedException();
}
// Get allowed mimetypes
$mimetypes = \nre\configs\AppConfig::$mimetypes['icons'];
// Values
$charactergroupname = $group['name'];
$motto = $group['motto'];
$fields = array('charactergroupname', 'motto');
$validation = array();
// Edit Character group
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('edit')))
{
// Get params and validate them
$validation = $this->Validation->validateParams($this->request->getPostParams(), $fields);
$charactergroupname = (count(array_intersect(array('admin','moderator'), \hhu\z\controllers\SeminaryController::$character['characterroles'])) > 0) ? $this->request->getPostParam('charactergroupname') : $group['name'];
if($this->Charactergroups->characterGroupNameExists($charactergroupname, $group['id'])) {
$validation = $this->Validation->addValidationResult($validation, 'charactergroupname', 'exist', true);
}
$motto = $this->request->getPostParam('motto');
// Validate icon
$icon = null;
if(!empty($_FILES) && array_key_exists('icon', $_FILES) && $_FILES['icon']['error'] != UPLOAD_ERR_NO_FILE)
{
$icon = $_FILES['icon'];
// Check error
if($icon['error'] !== UPLOAD_ERR_OK) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'error', $icon['error']);
}
// Check mimetype
$mediaMimetype = null;
$icon['mimetype'] = \hhu\z\Utils::getMimetype($icon['tmp_name'], $icon['type']);
foreach($mimetypes as &$mimetype) {
if($mimetype['mimetype'] == $icon['mimetype']) {
$mediaMimetype = $mimetype;
break;
}
}
if(is_null($mediaMimetype)) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'mimetype', $icon['mimetype']);
}
elseif($icon['size'] > $mediaMimetype['size']) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'size', $mediaMimetype['size']);
}
}
// Edit group
if($validation === true)
{
$this->Charactergroups->editGroup(
$group['id'],
$charactergroupname,
$motto
);
$group = $this->Charactergroups->getGroupById($group['id']);
// Upload icon
if(!is_null($icon))
{
$mediaId = $this->Media->createCharactergroupMedia(
$this->Auth->getUserId(),
$seminary['id'],
sprintf('charactergroup-%s', $group['url']),
'',
$icon['mimetype'],
$icon['tmp_name']
);
if($mediaId !== false) {
$this->Charactergroups->setMediaForGroup($group['id'], $mediaId);
}
}
// Redirect to user page
$this->redirect($this->linker->link(array('group', $seminary['url'], $groupsgroup['url'], $group['url']), 1));
}
}
// Get validation settings
$validationSettings = array();
foreach($fields as &$field) {
$validationSettings[$field] = \nre\configs\AppConfig::$validation[$field];
}
// Set title
$this->addTitleLocalized('Edit %s Character group', $groupsgroup['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('group', $group);
$this->set('charactergroupname', $charactergroupname);
$this->set('motto', $motto);
$this->set('mimetypes', $mimetypes);
$this->set('validation', $validation);
$this->set('validationSettings', $validationSettings);
}
/**
* Action: deletegroup.
*
* Delete a Character group for a Character groups-group of a
* Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $groupUrl URL-Title of a Character group
*/
public function deletegroup($seminaryUrl, $groupsgroupUrl, $groupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character group
$group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Check confirmation
if(!is_null($this->request->getPostParam('delete')))
{
// Delete seminary
$this->Charactergroups->deleteGroup($group['id']);
// Redirect to overview
$this->redirect($this->linker->link(array('groupsgroup', $seminary['url'], $groupsgroup['url']), 1));
}
// Redirect to entry
$this->redirect($this->linker->link(array('group', $seminary['url'], $groupsgroup['url'], $group['url']), 1));
}
// Set title
$this->addTitleLocalized('Delete %s Character group', $groupsgroup['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('group', $group);
}
}
?>

View file

@ -0,0 +1,615 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 CharactergroupsquestsAgent to display Character
* groups Quests.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class CharactergroupsquestsController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'charactergroups', 'charactergroupsquests', 'media', 'questgroups', 'uploads');
/**
* Required components
*
* @var array
*/
public $components = array('validation');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'quest' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'quest' => array('admin', 'moderator', 'user')
);
/**
* Action: quest.
*
* Show a Character groups Quest for a Character groups-group
* of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $questUrl URL-Title of a Character groups Quest
*/
public function quest($seminaryUrl, $groupsgroupUrl, $questUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character groups-group Quests
$quest = $this->Charactergroupsquests->getQuestByUrl($groupsgroup['id'], $questUrl);
// Get Questgroup
$questgroup = $this->Questgroups->getQuestgroupById($quest['questgroups_id']);
$questgroup['entered'] = $this->Questgroups->hasCharacterEnteredQuestgroup($questgroup['id'], self::$character['id']);
// Get Character groups-groups
$groups = $this->Charactergroups->getGroupsForQuest($quest['id']);
// Get uploads
$uploads = $this->Charactergroupsquests->getMediaForQuest($quest['id']);
foreach($uploads as &$upload) {
$upload['upload'] = $this->Uploads->getSeminaryuploadById($upload['seminaryupload_id']);
}
// Set title
$this->addTitle($quest['title']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('quest', $quest);
$this->set('questgroup', $questgroup);
$this->set('groups', $groups);
$this->set('uploads', $uploads);
}
/**
* Action: manage.
*
* Manage a Character groups Quest for a Character groups-group
* of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $questUrl URL-Title of a Character groups Quest
*/
public function manage($seminaryUrl, $groupsgroupUrl, $questUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character groups-group Quests
$quest = $this->Charactergroupsquests->getQuestByUrl($groupsgroup['id'], $questUrl);
// Get Questgroup
$questgroup = $this->Questgroups->getQuestgroupById($quest['questgroups_id']);
$questgroup['entered'] = $this->Questgroups->hasCharacterEnteredQuestgroup($questgroup['id'], self::$character['id']);
// Get Character groups
$groups = $this->Charactergroups->getGroupsForGroupsgroup($groupsgroup['id']);
// Get allowed mimetypes
$mimetypes = \nre\configs\AppConfig::$mimetypes['charactergroupsquests'];
// Manage
$validation = array();
if($this->request->getRequestMethod() == 'POST')
{
// Upload media
if(!is_null($this->request->getPostParam('setmedia')))
{
$file = $_FILES['media'];
// Check error
if($file['error'] !== 0 || empty($file['tmp_name'])) {
$validation = $this->Validation->addValidationResult($validation, 'media', 'error', $file['error']);
}
// Check mimetype
$mediaMimetype = null;
$file['mimetype'] = \hhu\z\Utils::getMimetype($file['tmp_name'], $file['type']);
foreach($mimetypes as &$mimetype) {
if($mimetype['mimetype'] == $file['mimetype']) {
$mediaMimetype = $mimetype;
break;
}
}
if(is_null($mediaMimetype)) {
$validation = $this->Validation->addValidationResult($validation, 'media', 'mimetype', $file['mimetype']);
}
elseif($file['size'] > $mediaMimetype['size']) {
$validation = $this->Validation->addValidationResult($validation, 'media', 'size', $mediaMimetype['size']);
}
// Upload media
if($validation === true || empty($valiadion))
{
// Create filename
$filename = sprintf(
'%s-%d-%s.%s',
'charactergroupsquest',
$quest['id'],
date('Ymd-His'),
mb_substr($file['name'], strrpos($file['name'], '.')+1)
);
// Upload file
$this->Charactergroupsquests->uploadMediaForQuest($this->Auth->getUserId(), $seminary['id'], $quest['id'], $file, $filename);
}
}
// Set XPs of Character groups for this Character groups Quest
if(!is_null($this->request->getPostParam('setxps')))
{
$xps = $this->request->getPostParam('xps');
foreach($groups as &$group)
{
if(array_key_exists($group['url'], $xps) && $xps[$group['url']] != 'null')
{
$xpsFactor = intval($xps[$group['url']]) / $quest['xps'];
$this->Charactergroupsquests->setXPsOfGroupForQuest($quest['id'], $group['id'], $xpsFactor);
}
else {
$this->Charactergroupsquests->deleteGroupForQuest($quest['id'], $group['id']);
}
}
}
// Redirect to Quest page
if($validation === true || empty($validation)) {
$this->redirect($this->linker->link(array('quest', $seminary['url'], $groupsgroup['url'], $quest['url']), 1));
}
}
// Get icon
$questmedia = null;
if(!is_null($quest['questsmedia_id'])) {
$questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']);
}
// Get uploads
$uploads = $this->Charactergroupsquests->getMediaForQuest($quest['id']);
foreach($uploads as &$upload) {
$upload['upload'] = $this->Uploads->getSeminaryuploadById($upload['seminaryupload_id']);
}
// Set XPs for Groups
foreach($groups as &$group) {
$group['quest_group'] = $this->Charactergroupsquests->getXPsOfGroupForQuest($quest['id'], $group['id']);
}
// Set title
$this->addTitle($quest['title']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('quest', $quest);
$this->set('uploads', $uploads);
$this->set('mimetypes', $mimetypes);
$this->set('questgroup', $questgroup);
$this->set('groups', $groups);
$this->set('media', $questmedia);
$this->set('validation', $validation);
}
/**
* Action: create.
*
* Create a new Character groups Quest for a Character
* groups-group of a Seminary.
*
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
*/
public function create($seminaryUrl, $groupsgroupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Questgroups
$questgroups = $this->Questgroups->getQuestgroupsForSeminary($seminary['id']);
// Get allowed mimetypes
$mimetypes = \nre\configs\AppConfig::$mimetypes['icons'];
// Values
$title = '';
$xps = 0;
$description = '';
$rules = '';
$wonText = '';
$lostText = '';
$fields = array('title', 'xps');
$validation = array();
// Create a new Character groups Quest
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->Charactergroupsquests->characterGroupsQuestTitleExists($title)) {
$validation = $this->Validation->addValidationResult($validation, 'title', 'exist', true);
}
$xps = $this->request->getPostParam('xps');
$description = $this->request->getPostParam('description');
$rules = $this->request->getPostParam('rules');
$wonText = $this->request->getPostParam('wonText');
$lostText = $this->request->getPostParam('lostText');
// Validate icon
$icon = null;
if(!empty($_FILES) && array_key_exists('icon', $_FILES) && $_FILES['icon']['error'] != UPLOAD_ERR_NO_FILE)
{
$icon = $_FILES['icon'];
// Check error
if($icon['error'] !== UPLOAD_ERR_OK) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'error', $icon['error']);
}
// Check mimetype
$mediaMimetype = null;
$icon['mimetype'] = \hhu\z\Utils::getMimetype($icon['tmp_name'], $icon['type']);
foreach($mimetypes as &$mimetype) {
if($mimetype['mimetype'] == $icon['mimetype']) {
$mediaMimetype = $mimetype;
break;
}
}
if(is_null($mediaMimetype)) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'mimetype', $icon['mimetype']);
}
elseif($icon['size'] > $mediaMimetype['size']) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'size', $mediaMimetype['size']);
}
}
// Validate Questgroup
$questgroupIndex = null;
foreach($questgroups as $index => &$questgroup)
{
$questgroup['selected'] = ($questgroup['url'] == $this->request->getPostParam('questgroup'));
if($questgroup['selected']) {
$questgroupIndex = $index;
}
}
if(is_null($questgroupIndex)) {
throw new \nre\exceptions\ParamsNotValidException($questgroup);
}
// Create groups Quest
if($validation === true)
{
$questId = $this->Charactergroupsquests->createQuest(
$this->Auth->getUserId(),
$groupsgroup['id'],
$questgroups[$questgroupIndex]['id'],
$title,
$description,
$xps,
$rules,
$wonText,
$lostText
);
$quest = $this->Charactergroupsquests->getQuestById($questId);
// Upload icon
if(!is_null($icon))
{
$mediaId = $this->Media->createQuestMedia(
$this->Auth->getUserId(),
$seminary['id'],
sprintf('charactergroupsquest-%s', $quest['url']),
'',
$icon['mimetype'],
$icon['tmp_name']
);
if($mediaId !== false) {
$this->Charactergroupsquests->setMediaForQuest($quest['id'], $mediaId);
}
}
// Redirect to Quest page
$this->redirect($this->linker->link(array('quest', $seminary['url'], $groupsgroup['url'], $quest['url']), 1));
}
}
// Get validation settings
$validationSettings = array();
foreach($fields as &$field) {
$validationSettings[$field] = \nre\configs\AppConfig::$validation[$field];
}
// Set title
$this->addTitleLocalized('New %s-Quest', $groupsgroup['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('questgroups', $questgroups);
$this->set('title', $title);
$this->set('xps', $xps);
$this->set('description', $description);
$this->set('rules', $rules);
$this->set('wonText', $wonText);
$this->set('lostText', $lostText);
$this->set('mimetypes', $mimetypes);
$this->set('validation', $validation);
$this->set('validationSettings', $validationSettings);
}
/**
* Action: edit.
*
* Edit a Character groups Quest of a Character groups-group
* of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $questUrl URL-Title of a Character groups Quest
*/
public function edit($seminaryUrl, $groupsgroupUrl, $questUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character groups-group Quests
$quest = $this->Charactergroupsquests->getQuestByUrl($groupsgroup['id'], $questUrl);
// Get Questgroups
$questgroups = $this->Questgroups->getQuestgroupsForSeminary($seminary['id']);
foreach($questgroups as $index => &$questgroup) {
$questgroup['selected'] = ($questgroup['id'] == $quest['questgroups_id']);
}
// Get allowed mimetypes
$mimetypes = \nre\configs\AppConfig::$mimetypes['icons'];
// Values
$title = $quest['title'];
$xps = $quest['xps'];
$description = $quest['description'];
$rules = $quest['rules'];
$wonText = $quest['won_text'];
$lostText = $quest['lost_text'];
$fields = array('title', 'xps');
$validation = array();
// Edit Character group
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('edit')))
{
// Get params and validate them
$validation = $this->Validation->validateParams($this->request->getPostParams(), $fields);
$title = $this->request->getPostParam('title');
if($this->Charactergroupsquests->characterGroupsQuestTitleExists($title, $quest['id'])) {
$validation = $this->Validation->addValidationResult($validation, 'title', 'exist', true);
}
$xps = $this->request->getPostParam('xps');
$description = $this->request->getPostParam('description');
$rules = $this->request->getPostParam('rules');
$wonText = $this->request->getPostParam('wonText');
$lostText = $this->request->getPostParam('lostText');
// Validate icon
$icon = null;
if(!empty($_FILES) && array_key_exists('icon', $_FILES) && $_FILES['icon']['error'] != UPLOAD_ERR_NO_FILE)
{
$icon = $_FILES['icon'];
// Check error
if($icon['error'] !== UPLOAD_ERR_OK) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'error', $icon['error']);
}
// Check mimetype
$mediaMimetype = null;
$icon['mimetype'] = \hhu\z\Utils::getMimetype($icon['tmp_name'], $icon['type']);
foreach($mimetypes as &$mimetype) {
if($mimetype['mimetype'] == $icon['mimetype']) {
$mediaMimetype = $mimetype;
break;
}
}
if(is_null($mediaMimetype)) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'mimetype', $icon['mimetype']);
}
elseif($icon['size'] > $mediaMimetype['size']) {
$validation = $this->Validation->addValidationResult($validation, 'icon', 'size', $mediaMimetype['size']);
}
}
// Validate Questgroup
$questgroupIndex = null;
foreach($questgroups as $index => &$questgroup)
{
$questgroup['selected'] = ($questgroup['url'] == $this->request->getPostParam('questgroup'));
if($questgroup['selected']) {
$questgroupIndex = $index;
}
}
if(is_null($questgroupIndex)) {
throw new \nre\exceptions\ParamsNotValidException($questgroup);
}
// Edit groups Quest
if($validation === true)
{
$this->Charactergroupsquests->editQuest(
$quest['id'],
$groupsgroup['id'],
$questgroups[$questgroupIndex]['id'],
$title,
$description,
$xps,
$rules,
$wonText,
$lostText
);
$quest = $this->Charactergroupsquests->getQuestById($quest['id']);
// Upload icon
if(!is_null($icon))
{
$mediaId = $this->Media->createQuestMedia(
$this->Auth->getUserId(),
$seminary['id'],
sprintf('charactergroupsquest-%s', $quest['url']),
'',
$icon['mimetype'],
$icon['tmp_name']
);
if($mediaId !== false) {
$this->Charactergroupsquests->setMediaForQuest($quest['id'], $mediaId);
}
}
// Redirect to Quest page
$this->redirect($this->linker->link(array('quest', $seminary['url'], $groupsgroup['url'], $quest['url']), 1));
}
}
// Get validation settings
$validationSettings = array();
foreach($fields as &$field) {
$validationSettings[$field] = \nre\configs\AppConfig::$validation[$field];
}
// Set title
$this->addTitleLocalized('Edit %s-Quest', $groupsgroup['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('quest', $quest);
$this->set('questgroups', $questgroups);
$this->set('title', $title);
$this->set('xps', $xps);
$this->set('description', $description);
$this->set('rules', $rules);
$this->set('wonText', $wonText);
$this->set('lostText', $lostText);
$this->set('mimetypes', $mimetypes);
$this->set('validation', $validation);
$this->set('validationSettings', $validationSettings);
}
/**
* Action: delete.
*
* Delete a Character groups Quest of a Character groups-group
* of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $questUrl URL-Title of a Character groups Quest
*/
public function delete($seminaryUrl, $groupsgroupUrl, $questUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character groups-group Quests
$quest = $this->Charactergroupsquests->getQuestByUrl($groupsgroup['id'], $questUrl);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Check confirmation
if(!is_null($this->request->getPostParam('delete')))
{
// Delete seminary
$this->Charactergroupsquests->deleteQuest($quest['id']);
// Redirect to overview
$this->redirect($this->linker->link(array('charactergroups', 'groupsgroup', $seminary['url'], $groupsgroup['url'])));
}
// Redirect to entry
$this->redirect($this->linker->link(array('quest', $seminary['url'], $groupsgroup['url'], $quest['url']), 1));
}
// Set title
$this->addTitleLocalized('Delete %s-Quest', $groupsgroup['name']);
$this->addTitle($groupsgroup['name']);
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('quest', $quest);
}
}
?>

View file

@ -0,0 +1,783 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 Agent to list registered users and their data.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class CharactersController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'characters', 'users', 'charactergroups', 'charactertypes', 'seminarycharacterfields', 'avatars', 'media', 'quests', 'questgroups', 'questtopics');
/**
* Required components
*
* @var array
*/
public $components = array('validation');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user'),
'character' => array('admin', 'moderator', 'user'),
'register' => array('admin', 'moderator', 'user'),
'manage' => array('admin', 'moderator', 'user'),
'edit' => array('admin', 'moderator', 'user'),
'delete' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'index' => array('admin', 'moderator'),
'character' => array('admin', 'moderator', 'user'),
'manage' => array('admin', 'moderator'),
'edit' => array('admin', 'moderator', 'user'),
'delete' => array('admin', 'moderator')
);
/**
* Action: index.
*
* List registered Characters for a Seminary
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
*/
public function index($seminaryUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Seminarycharacterfields
$characterfields = $this->Seminarycharacterfields->getFieldsForSeminary($seminary['id']);
// Get registered Characters
$characters = $this->Characters->getCharactersForSeminary($seminary['id']);
foreach($characters as &$character)
{
$character['xplevel'] = $this->Characters->getXPLevelOfCharacters($character['id']);
$character['user'] = $this->Users->getUserById($character['user_id']);
$character['characterroles'] = array_map(function($r) { return $r['name']; }, $this->Characterroles->getCharacterrolesForCharacterById($character['id']));
$character['characterfields'] = array();
foreach($this->Seminarycharacterfields->getFieldsForCharacter($character['id']) as $value) {
$character['characterfields'][$value['url']] = $value;
}
}
// Sort Characters
global $sortorder;
$sortorder = ($this->request->getRequestMethod() == 'GET') ? $this->request->getGetParam('sortorder') : null;
$sortorder = (!is_null($sortorder)) ? $sortorder : 'xps';
$sortMethod = 'sortCharactersBy'.ucfirst(strtolower($sortorder));
if(method_exists($this, $sortMethod)) {
usort($characters, array($this, $sortMethod));
}
elseif(in_array($sortorder, array_map(function($f) { return $f['title']; }, $characterfields))) {
usort($characters, function($a, $b) {
global $sortorder;
return $this->sortCharactersByField($a, $b, $sortorder);
});
}
else {
throw new \nre\exceptions\ParamsNotValidException($sortorder);
}
// Set titile
$this->addTitleLocalized('Characters');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('characters', $characters);
$this->set('characterfields', $characterfields);
$this->set('sortorder', $sortorder);
}
/**
* Action: character.
*
* Show a Charater and its details.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $characterUrl URL-name of a Charater
*/
public function character($seminaryUrl, $characterUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
$seminary['achievable_xps'] = $this->Seminaries->getTotalXPs($seminary['id']);
// Get Character
$character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl);
$character['quest_xps'] = $this->Characters->getQuestXPsOfCharacter($character['id']);
$character['xplevel'] = $this->Characters->getXPLevelOfCharacters($character['id']);
$character['rank'] = $this->Characters->getXPRank($seminary['id'], $character['xps']);
// Get User
$user = $this->Users->getUserById($character['user_id']);
// Get Character groups
$groups = $this->Charactergroups->getGroupsForCharacter($character['id']);
foreach($groups as &$group) {
$group['groupsgroup'] = $this->Charactergroups->getGroupsgroupById($group['charactergroupsgroup_id']);
}
// Get Achievements
$achievements = $this->Achievements->getAchievedAchievementsForCharacter($character['id']);
// Get Achievements with deadline (milestones)
$milestones = $this->Achievements->getDeadlineAchievements($seminary['id']);
foreach($milestones as &$milestone) {
$milestone['achieved'] = $this->Achievements->hasCharacterAchievedAchievement($milestone['id'], $character['id']);
}
// Get ranking
$ranking = array(
'superior' => $this->Characters->getSuperiorCharacters($seminary['id'], $character['xps'], \nre\configs\AppConfig::$misc['ranking_range']),
'inferior' => $this->Characters->getInferiorCharacters($seminary['id'], $character['id'], $character['xps'], \nre\configs\AppConfig::$misc['ranking_range'])
);
// Get Quest topics
$questtopics = $this->Questtopics->getQuesttopicsForSeminary($seminary['id']);
foreach($questtopics as &$questtopic)
{
$questtopic['questcount'] = $this->Questtopics->getQuestCountForQuesttopic($questtopic['id']);
$questtopic['characterQuestcount'] = $this->Questtopics->getCharacterQuestCountForQuesttopic($questtopic['id'], $character['id']);
}
// Get “last” Quest
$lastQuest = null;
if(count(array_intersect(array('admin', 'moderator'), \hhu\z\controllers\SeminaryController::$character['characterroles'])) > 0)
{
$lastQuest = $this->Quests->getLastQuestForCharacter($character['id']);
if(!is_null($lastQuest)) {
$lastQuest['questgroup'] = $this->Questgroups->getQuestgroupById($lastQuest['questgroup_id']);
}
}
// Set titile
$this->addTitle($character['name']);
$this->addTitleLocalized('Characters');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('character', $character);
$this->set('user', $user);
$this->set('groups', $groups);
$this->set('achievements', $achievements);
$this->set('milestones', $milestones);
$this->set('ranking', $ranking);
$this->set('questtopics', $questtopics);
$this->set('lastQuest', $lastQuest);
}
/**
* Acton: register.
*
* Register a new character for a Seminary.
*
* @throws IdNotFoundException
* @throws ParamsNotValidException
* @param string $seminaryUrl URL-Title of a Seminary
*/
public function register($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Check for already existing Character
try {
$this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
throw new \nre\exceptions\AccessDeniedException();
}
catch(\nre\exceptions\IdNotFoundException $e) {
// The should be the case
}
// Character types
$types = $this->Charactertypes->getCharacterTypesForSeminary($seminary['id']);
// Character fields
$fields = $this->Seminarycharacterfields->getFieldsForSeminary($seminary['id']);
// Register Character
$charactername = '';
$validation = true;
$fieldsValidation = true;
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
{
// Validate Character properties
$validation = $this->Validation->validateParams($this->request->getPostParams(), array('charactername'));
$charactername = $this->request->getPostParam('charactername');
if($this->Characters->characterNameExists($charactername)) {
$validation = $this->Validation->addValidationResult($validation, 'charactername', 'exist', true);
}
// Validate type
$typeIndex = null;
foreach($types as $index => &$type)
{
$type['selected'] = ($type['url'] == $this->request->getPostParam('type'));
if($type['selected']) {
$typeIndex = $index;
}
}
if(is_null($typeIndex)) {
$validation = $this->Validation->addValidationResult($validation, 'type', 'exist', false);
}
// Validate fields
$fieldsValues = $this->request->getPostParam('fields');
foreach($fields as &$field)
{
if(!array_key_exists($field['url'], $fieldsValues)) {
throw new \nre\exceptions\ParamsNotValidException($index);
}
$field['uservalue'] = $fieldsValues[$field['url']];
if($field['required'])
{
$fieldValidation = $this->Validation->validate($fieldsValues[$field['url']], array('regex'=>$field['regex']));
if($fieldValidation !== true)
{
if(!is_array($fieldsValidation)) {
$fieldsValidation = array();
}
$fieldsValidation[$field['url']] = $fieldValidation;
}
}
}
// Register
if($validation === true && $fieldsValidation === true)
{
$characterId = $this->Characters->createCharacter($this->Auth->getUserId(), $types[$typeIndex]['id'], $charactername);
// Add Seminary fields
foreach($fields as &$field) {
if(!empty($fieldsValues[$field['url']])) {
$this->Seminarycharacterfield->setSeminaryFieldOfCharacter($field['id'], $characterId, $fieldsValues[$field['url']]);
}
}
// Send mail
$this->sendRegistrationMail($charactername);
// Redirect
$this->redirect($this->linker->link(array('seminaries')));
}
}
// Get XP-levels
$xplevels = $this->Characters->getXPLevelsForSeminary($seminary['id']);
// Set titile
$this->addTitleLocalized('Create Character');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('types', $types);
$this->set('fields', $fields);
$this->set('charactername', $charactername);
$this->set('validation', $validation);
$this->set('fieldsValidation', $fieldsValidation);
$this->set('xplevels', $xplevels);
}
/**
* Action: manage.
*
* Manage Characters.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
*/
public function manage($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Set default properties to show
$properties = array(
'username',
'xps',
'roles'
);
$selectedCharacters = array();
global $sortorder;
if($this->request->getRequestMethod() == 'POST')
{
// Set sortorder
$sortorder = $this->request->getPostParam('sortorder');
// Do action
$selectedCharacters = $this->request->getPostParam('characters');
if(!is_array($selectedCharacters)) {
$selectedCharacters = array();
}
if(!is_null($this->request->getPostParam('actions')) && count($this->request->getPostParam('actions')) > 0 && !is_null($this->request->getPostParam('characters')) && count($this->request->getPostParam('characters')) > 0)
{
$actions = $this->request->getPostParam('actions');
$action = array_keys($actions)[0];
switch($action)
{
// Add/remove role to/from Characters
case 'addrole':
case 'removerole':
// Determine role and check permissions
$role = null;
switch($actions[$action])
{
case _('Admin'):
if(count(array_intersect(array('admin', 'moderator'), \hhu\z\controllers\IntermediateController::$user['roles'])) <= 0 && !in_array('admin', \hhu\z\controllers\SeminaryController::$character['characterroles'])) {
throw new \nre\exceptions\AccessDeniedException();
}
$role = 'admin';
break;
case _('Moderator'):
if(count(array_intersect(array('admin', 'moderator'), \hhu\z\controllers\IntermediateController::$user['roles'])) <= 0 && !in_array('admin', \hhu\z\controllers\SeminaryController::$character['characterroles'])) {
throw new \nre\exceptions\AccessDeniedException();
}
$role = 'moderator';
break;
case _('User'):
if(count(array_intersect(array('admin', 'moderator'), \hhu\z\controllers\IntermediateController::$user['roles'])) <= 0 && count(array_intersect(array('admin', 'moderator'), \hhu\z\controllers\SeminaryController::$character['characterroles'])) <= 0) {
throw new \nre\exceptions\AccessDeniedException();
}
$role = 'user';
break;
}
// Add role
if($action == 'addrole') {
foreach($selectedCharacters as &$characterId) {
$this->Characterroles->addCharacterroleToCharacter($characterId, $role);
}
}
// Remove role
else {
foreach($selectedCharacters as &$characterId) {
$this->Characterroles->removeCharacterroleFromCharacter($characterId, $role);
}
}
break;
}
}
}
// Get Seminarycharacterfields
$characterfields = $this->Seminarycharacterfields->getFieldsForSeminary($seminary['id']);
// Get registered Characters
$characters = $this->Characters->getCharactersForSeminary($seminary['id']);
foreach($characters as &$character)
{
$character['xplevel'] = $this->Characters->getXPLevelOfCharacters($character['id']);
$character['user'] = $this->Users->getUserById($character['user_id']);
$character['characterroles'] = array_map(function($r) { return $r['name']; }, $this->Characterroles->getCharacterrolesForCharacterById($character['id']));
$character['characterfields'] = array();
foreach($this->Seminarycharacterfields->getFieldsForCharacter($character['id']) as $value) {
$character['characterfields'][$value['url']] = $value;
}
}
// Sort Characters
$sortorder = (!is_null($sortorder)) ? $sortorder : 'xps';
$sortMethod = 'sortCharactersBy'.ucfirst(strtolower($sortorder));
if(method_exists($this, $sortMethod)) {
usort($characters, array($this, $sortMethod));
}
elseif(in_array($sortorder, array_map(function($f) { return $f['title']; }, $characterfields))) {
usort($characters, function($a, $b) {
global $sortorder;
return $this->sortCharactersByField($a, $b, $sortorder);
});
}
else {
throw new \nre\exceptions\ParamsNotValidException($sortorder);
}
// Set titile
$this->addTitleLocalized('Manage Characters');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('characters', $characters);
$this->set('characterfields', $characterfields);
$this->set('selectedCharacters', $selectedCharacters);
$this->set('sortorder', $sortorder);
}
/**
* Acton: edit.
*
* Edit a new character for a Seminary.
*
* @throws IdNotFoundException
* @throws ParamsNotValidException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $characterUrl URL-name of a Charater
*/
public function edit($seminaryUrl, $characterUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character
$character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl);
// Check permissions
if(count(array_intersect(array('admin','moderator'), \hhu\z\controllers\SeminaryController::$character['characterroles'])) == 0 && $character['id'] != \hhu\z\controllers\SeminaryController::$character['id']) {
throw new \nre\exceptions\AccessDeniedException();
}
// Get User
$user = $this->Users->getUserById($character['user_id']);
// Character types
$types = $this->Charactertypes->getCharacterTypesForSeminary($seminary['id']);
foreach($types as &$type) {
$type['selected'] = ($type['url'] == $character['charactertype_url']);
}
// Character fields
$fields = $this->Seminarycharacterfields->getFieldsForSeminary($seminary['id']);
foreach($fields as &$field)
{
$userValue = $this->Seminarycharacterfields->getSeminaryFieldOfCharacter($field['id'], $character['id']);
if(!empty($userValue)) {
$field['uservalue'] = $userValue['value'];
}
}
// Values
$charactername = $character['name'];
$validation = array();
$fieldsValidation = true;
// Edit Character
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('edit')))
{
// Validate Character properties
$validation = $this->Validation->validateParams($this->request->getPostParams(), array('charactername'));
$charactername = (count(array_intersect(array('admin','moderator'), \hhu\z\controllers\SeminaryController::$character['characterroles'])) > 0) ? $this->request->getPostParam('charactername') : $character['name'];
if($this->Characters->characterNameExists($charactername, $character['id'])) {
$validation = $this->Validation->addValidationResult($validation, 'charactername', 'exist', true);
}
// Validate type
$typeIndex = null;
foreach($types as $index => &$type)
{
$type['selected'] = (count(array_intersect(array('admin','moderator'), \hhu\z\controllers\SeminaryController::$character['characterroles'])) > 0) ? ($type['url'] == $this->request->getPostParam('type')) : ($type['url'] == $character['charactertype_url']);
if($type['selected']) {
$typeIndex = $index;
}
}
if(is_null($typeIndex)) {
$validation = $this->Validation->addValidationResult($validation, 'type', 'exist', false);
}
// Validate fields
$fieldsValues = $this->request->getPostParam('fields');
foreach($fields as &$field)
{
if(!array_key_exists($field['url'], $fieldsValues)) {
throw new \nre\exceptions\ParamsNotValidException($index);
}
$field['uservalue'] = $fieldsValues[$field['url']];
if($field['required'])
{
$fieldValidation = $this->Validation->validate($fieldsValues[$field['url']], array('regex'=>$field['regex']));
if($fieldValidation !== true)
{
if(!is_array($fieldsValidation)) {
$fieldsValidation = array();
}
$fieldsValidation[$field['url']] = $fieldValidation;
}
}
}
// Edit
if($validation === true && $fieldsValidation === true)
{
$this->Characters->editCharacter(
$character['id'],
$types[$typeIndex]['id'],
$charactername
);
// Set Seminary fields
foreach($fields as &$field) {
if(!empty($fieldsValues[$field['url']])) {
$this->Seminarycharacterfields->setSeminaryFieldOfCharacter($field['id'], $character['id'], $fieldsValues[$field['url']]);
}
}
// Redirect
$character = $this->Characters->getCharacterById($character['id']);
$this->redirect($this->linker->link(array('character', $seminary['url'], $character['url']), 1));
}
}
// Get XP-levels
$xplevels = $this->Characters->getXPLevelsForSeminary($seminary['id']);
// Set titile
$this->addTitleLocalized('Edit Character');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('types', $types);
$this->set('fields', $fields);
$this->set('charactername', $charactername);
$this->set('validation', $validation);
$this->set('fieldsValidation', $fieldsValidation);
$this->set('xplevels', $xplevels);
}
/**
* Action: delete.
*
* Delete a Character.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $characterUrl URL-name of a Charater
*/
public function delete($seminaryUrl, $characterUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character
$character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl);
// Get User
$user = $this->Users->getUserById($character['user_id']);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Check confirmation
if(!is_null($this->request->getPostParam('delete')))
{
// Delete Character
$this->Characters->deleteCharacter($character['id']);
// Redirect to overview
$this->redirect($this->linker->link(array('index', $seminary['url']), 1));
}
// Redirect to entry
$this->redirect($this->linker->link(array('index', $seminary['url'], $character['url']), 1));
}
// Set titile
$this->addTitleLocalized('Delete Character');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('character', $character);
$this->set('user', $user);
}
/**
* Send mail for new Character registration.
*
* @param string $charactername Name of newly registered Character
*/
private function sendRegistrationMail($charactername)
{
$sender = \nre\configs\AppConfig::$app['mailsender'];
if(empty($sender)) {
return;
}
// Send notification mail to system moderators
$subject = sprintf('new Character registration: %s', $charactername);
$message = sprintf('User “%s” <%s> has registered a new Character “%s” for the Seminary “%s”', self::$user['username'], self::$user['email'], $charactername, self::$seminary['title']);
$characters = $this->Characters->getCharactersWithCharacterRole(self::$seminary['id'], 'moderator');
foreach($characters as &$character)
{
$moderator = $this->Users->getUserById($character['user_id']);
\hhu\z\Utils::sendMail($sender, $moderator['email'], $subject, $message);
}
}
/**
* Compare two Characters by their name.
*
* @param array $a Character a
* @param array $b Character b
* @return int Result of comparison
*/
private function sortCharactersByCharactername($a, $b)
{
if($a['name'] == $b['name']) {
return 0;
}
return ($a['name'] < $b['name']) ? -1 : 1;
}
/**
* Compare two Characters by their XPs.
*
* @param array $a Character a
* @param array $b Character b
* @return int Result of comparison
*/
private function sortCharactersByXps($a, $b)
{
if($a['xps'] == $b['xps']) {
return 0;
}
return ($a['xps'] > $b['xps']) ? -1 : 1;
}
/**
* Compare two Characters by their Character roles.
*
* @param array $a Character a
* @param array $b Character b
* @return int Result of comparison
*/
private function sortCharactersByRole($a, $b)
{
if(in_array('admin', $a['characterroles']))
{
if(in_array('admin', $b['characterroles'])) {
return 0;
}
return -1;
}
if(in_array('moderator', $a['characterroles']))
{
if(in_array('admin', $b['characterroles'])) {
return 1;
}
if(in_array('moderator', $b['characterroles'])) {
return 0;
}
return -1;
}
if(in_array('user', $a['characterroles']))
{
if(in_array('admin', $b['characterroles']) || in_array('moderator', $b['characterroles'])) {
return 1;
}
if(in_array('user', $b['characterroles'])) {
return 0;
}
return -1;
}
if(in_array('guest', $a['characterroles']))
{
if(in_array('admin', $b['characterroles']) || in_array('moderator', $b['characterroles']) || in_array('user', $b['characterroles'])) {
return 1;
}
if(in_array('guest', $b['characterroles'])) {
return 0;
}
return -1;
}
return 1;
}
/**
* Compare two Characters by their registration date.
*
* @param array $a Character a
* @param array $b Character b
* @return int Result of comparison
*/
private function sortCharactersByDate($a, $b)
{
if($a['created'] == $b['created']) {
return 0;
}
return ($a['created'] > $b['created']) ? -1 : 1;
}
/**
* Compare two Characters by one of their Seminary fields.
*
* @param array $a Character a
* @param array $b Character b
* @param string $field Field to compare
* @return int Result of comparison
*/
private function sortCharactersByField($a, $b, $field)
{
if($a['characterfields'][$field] == $b['characterfields'][$field]) {
return 0;
}
return ($a['characterfields'][$field] < $b['characterfields'][$field]) ? -1 : 1;
}
}
?>

View file

@ -0,0 +1,51 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 Agent to show an error page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class ErrorController extends \hhu\z\Controller
{
/**
* Action: index.
*
* Set HTTP-header and print an error message.
*
* @param int $httpStatusCode HTTP-statuscode of the error that occurred
*/
public function index($httpStatusCode)
{
// Set HTTP-header
if(!array_key_exists($httpStatusCode, \nre\core\WebUtils::$httpStrings)) {
$httpStatusCode = 200;
}
$this->response->addHeader(\nre\core\WebUtils::getHttpHeader($httpStatusCode));
// Display statuscode and message
$this->set('code', $httpStatusCode);
$this->set('string', \nre\core\WebUtils::$httpStrings[$httpStatusCode]);
$this->set('userId', $this->Auth->getUserId());
}
}
?>

View file

@ -0,0 +1,37 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 Agent to display a toplevel error page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class FaultController extends \nre\core\Controller
{
/**
* Action: index.
*
* Show the error message.
*/
public function index()
{
}
}
?>

View file

@ -0,0 +1,111 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 HtmlAgent to display a HTML-page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class HtmlController extends \hhu\z\Controller
{
/**
* Required components
*
* @var array
*/
public $components = array('notification');
/**
* Prefilter.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::preFilter($request, $response);
// Set content-type
$this->response->addHeader("Content-type: text/html; charset=utf-8");
}
/**
* Postfilter that is executed after running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
{
// Get title
$this->set('title', $this->getTitle());
}
/**
* Action: index.
*
* Create the HTML-structure.
*/
public function index()
{
// Set the name of the current IntermediateAgent as page title
$this->set('title', $this->request->getParam(1, 'intermediate'));
// Set userdata
$this->set('loggedUser', IntermediateController::$user);
$this->set('loggedSeminary', SeminaryController::$seminary);
$this->set('loggedCharacter', SeminaryController::$character);
// Set notifications
$this->set('notifications', $this->Notification->getNotifications());
}
/**
* Get title information from IntermediateController if possible
* and create a title.
*
* @return string Title for the current page
*/
private function getTitle()
{
$title = array();
// Get title of IntermediateController
$intermediateController = $this->agent->getIntermediateAgent()->controller;
if($intermediateController instanceof \hhu\z\controllers\IntermediateController) {
$title = $intermediateController->getTitle();
}
if(!is_array($title)) {
$title = array($title);
}
// Add application name
$title[] = \nre\configs\AppConfig::$app['name'];
// Return title with delimiter
return implode(\nre\configs\AppConfig::$misc['title_delimiter'], $title);
}
}
?>

View file

@ -0,0 +1,37 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 Agent to show an introduction page.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class IntroductionController extends \hhu\z\controllers\IntermediateController
{
/**
* Action: index.
*/
public function index()
{
// Pass data to view
$this->set('userId', $this->Auth->getUserId());
}
}
?>

View file

@ -0,0 +1,513 @@
<?php
/**
* The Legend of Z
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @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 LibraryAgent to list Quest topics.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class LibraryController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('questtopics', 'seminaries', 'quests', 'questgroups');
/**
* Required components
*
* @var array
*/
public $components = array('validation');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user'),
'topic' => array('admin', 'moderator', 'user'),
'manage' => array('admin', 'moderator', 'user'),
'create' => array('admin', 'moderator', 'user'),
'edit' => array('admin', 'moderator', 'user'),
'delete' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'index' => array('admin', 'moderator', 'user', 'guest'),
'topic' => array('admin', 'moderator', 'user', 'guest'),
'manage' => array('admin', 'moderator'),
'create' => array('admin', 'moderator'),
'edit' => array('admin', 'moderator'),
'delete' => array('admin', 'moderator')
);
/**
* Action: index.
*
* List Questtopics of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of Seminary
*/
public function index($seminaryUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character
$character = SeminaryController::$character;
// Get Quest topics
$totalQuestcount = 0;
$totalCharacterQuestcount = 0;
$questtopics = $this->Questtopics->getQuesttopicsForSeminary($seminary['id']);
foreach($questtopics as &$questtopic)
{
// Get Quest count
$questtopic['questcount'] = $this->Questtopics->getQuestCountForQuesttopic($questtopic['id']);
$totalQuestcount += $questtopic['questcount'];
// Get Character progress
$questtopic['characterQuestcount'] = $this->Questtopics->getCharacterQuestCountForQuesttopic($questtopic['id'], $character['id']);
$totalCharacterQuestcount += $questtopic['characterQuestcount'];
}
// Set title
$this->addTitleLocalized('Library');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('totalQuestcount', $totalQuestcount);
$this->set('totalCharacterQuestcount', $totalCharacterQuestcount);
$this->set('questtopics', $questtopics);
}
/**
* Action: topic.
*
* Show a Questtopic and its Quests with Questsubtopics.
*
* @throws IdNotFoundException
* @param string $eminaryUrl URL-Title of Seminary
* @param string $questtopicUrl URL-Title of Questtopic
*/
public function topic($seminaryUrl, $questtopicUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character
$character = SeminaryController::$character;
// Get Questtopic
$questtopic = $this->Questtopics->getQuesttopicByUrl($seminary['id'], $questtopicUrl);
$questtopic['questcount'] = $this->Questtopics->getQuestCountForQuesttopic($questtopic['id']);
$questtopic['characterQuestcount'] = $this->Questtopics->getCharacterQuestCountForQuesttopic($questtopic['id'], $character['id']);
// Get Quests
$quests = array();
foreach($this->Quests->getQuestsForQuesttopic($questtopic['id']) as $quest)
{
if($this->Quests->hasCharacterEnteredQuest($quest['id'], $character['id']) || count(array_intersect(array('admin', 'moderator'), self::$character['characterroles'])) > 0)
{
// Get Subtopics
$quest['subtopics'] = $this->Questtopics->getQuestsubtopicsForQuest($quest['id']);
$quests[] = $quest;
}
}
// Set title
$this->addTitle($questtopic['title']);
$this->addTitleLocalized('Library');
$this->addTitle($seminary['title']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questtopic', $questtopic);
$this->set('quests', $quests);
}
/**
* Action: manage.
*
* Manage a Questtopic and its Quests with Questsubtopics.
*
* @throws IdNotFoundException
* @param string $eminaryUrl URL-Title of Seminary
* @param string $questtopicUrl URL-Title of Questtopic
*/
public function manage($seminaryUrl, $questtopicUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Questtopic
$questtopic = $this->Questtopics->getQuesttopicByUrl($seminary['id'], $questtopicUrl);
// Get Questsubtopics
$questsubtopics = $this->Questtopics->getSubtopicsForQuesttopic($questtopic['id']);
// Set Questsubtopics for Quests
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('questsubtopics')))
{
$selectedSubtopics = $this->request->getPostParam('questsubtopics');
// Set subtopics of Quests
$quests = $this->Quests->getQuestsForQuesttopic($questtopic['id']);
foreach($quests as &$quest)
{
$subtopics = (array_key_exists($quest['id'], $selectedSubtopics)) ? $selectedSubtopics[$quest['id']] : array();
$this->Questtopics->setQuestsubtopicsForQuest($quest['id'], array_keys($subtopics));
}
// Add Quest
$addQuestId = $this->request->getPostParam('addquest');
if(!empty($addQuestId))
{
$subtopics = (array_key_exists('addquest', $selectedSubtopics)) ? $selectedSubtopics['addquest'] : array();
if(!empty($subtopics)) {
$this->Questtopics->setQuestsubtopicsForQuest($addQuestId, array_keys($subtopics));
}
}
// Redirect
$this->redirect($this->linker->link(array('topic', $seminary['url'], $questtopic['url']), 1));
}
// Get Quests
$quests = $this->Quests->getQuestsForQuesttopic($questtopic['id']);
foreach($quests as &$quest)
{
// Get Subtopics
$quest['subtopics'] = $this->Questtopics->getQuestsubtopicsForQuest($quest['id']);
$quest['subtopics'] = array_map(function($t) { return $t['id']; }, $quest['subtopics']);
}
// Get all Quests
$allQuests = $this->Quests->getQuestsForSeminary($seminary['id']);
// Set title
$this->addTitle($questtopic['title']);
$this->addTitleLocalized('Library');
$this->addTitle($seminary['title']);
// Pass data to view