fixed order of achievement title and count

This commit is contained in:
Daniel 2014-04-28 14:32:05 +02:00
commit df3dd6466c
3459 changed files with 594367 additions and 0 deletions

8
.hgignore Normal file
View file

@ -0,0 +1,8 @@
syntax: regexp
^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\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\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);
}
}
?>

267
app/QuesttypeAgent.inc Normal file
View file

@ -0,0 +1,267 @@
<?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 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";
}
/**
* 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\QuesttypeController::load($controllerName);
// Construct Controller
$this->controller = QuesttypeController::factory($controllerName, $toplevelAgentName, $action, $this);
}
}
?>

308
app/QuesttypeController.inc Normal file
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;
/**
* 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
QuesttypeModel::load($model);
// Construct Model
$modelName = ucfirst(strtolower($model));
$this->$modelName = 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 = QuesttypeView::loadAndFactory($layoutName, $controllerName, $action);
}
}
?>

154
app/QuesttypeModel.inc Normal file
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;
/**
* 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();
}
}
?>

76
app/QuesttypeView.inc Normal file
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;
/**
* 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;
}
}
?>

141
app/TextFormatter.inc Normal file
View file

@ -0,0 +1,141 @@
<?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);
// 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>$4', $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);
}
}
?>

36
app/ToplevelAgent.inc Normal file
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;
/**
* 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']);
}
}
?>

112
app/Utils.inc Normal file
View file

@ -0,0 +1,112 @@
<?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);
}
}
?>

View file

@ -0,0 +1,139 @@
<?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;
/**
* 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);
}
/**
* 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,300 @@
<?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);
// 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.
*/
private function checkAchievements(\nre\core\Request $request, \nre\core\Response $response)
{
// Check if Character is present
if(is_null(self::$character)) {
return;
}
// 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 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);
}
}

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();
?>

239
configs/AppConfig.inc Normal file
View file

@ -0,0 +1,239 @@
<?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
)
);
/**
* Miscellaneous settings
*
* @static
* @var array
*/
public static $misc = array(
'ranking_range' => 2,
'achievements_range' => 3
);
/**
* 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
)
);
/**
* Routes
*
* @static
* @var array
*/
public static $routes = array(
array('^users/([^/]+)/(edit|delete)/?$', 'users/$2/$1', true),
array('^users/(?!(index|login|register|logout|create|edit|delete))/?', 'users/user/$1', true),
array('^seminaries/([^/]+)/(edit|delete)/?$', 'seminaries/$2/$1', true),
array('^seminaries/(?!(index|create|edit|delete))/?', 'seminaries/seminary/$1', true),
array('^questgroups/([^/]+)/(create)/?$', 'questgroups/$2/$1', true),
array('^questgroups/([^/]+)/([^/]+)/?$', 'questgroups/questgroup/$1/$2', 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/([^/]+)/(?!(index|create|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/([^/]+)/([^/]+)/([^/]+)/?$', 'charactergroupsquests/quest/$1/$2/$3', true),
array('^achievements/([^/]+)/?$', 'achievements/index/$1', true),
array('^library/([^/]+)/?$', 'library/index/$1', true),
array('^library/([^/]+)/([^/]+)/?$', 'library/topic/$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/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('^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/quest/(.*)$', 'charactergroupsquests/$1', true),
array('^achievements/index/(.*)$', 'achievements/$1', true),
array('^library/(index|topic)/(.*)$', 'library/$2', 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,172 @@
<?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 achieved Achievements
$achievedAchievements = $this->Achievements->getAchievedAchievementsForCharacter($character['id'], false);
// Get unachieved Achievements
$unachievedAchievements = $this->Achievements->getUnachhievedAchievementsForCharacter($seminary['id'], $character['id'], true, false);
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));
// Pass data to view
$this->set('seminary', $seminary);
$this->set('character', $character);
$this->set('seldomAchievements', $seldomAchievements);
$this->set('successfulCharacters', $successfulCharacters);
$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,610 @@
<?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'),
'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']);
// 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']);
// Get Character groups-group Quests
$quests = $this->Charactergroupsquests->getQuestsForCharactergroupsgroup($groupsgroup['id']);
// 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];
}
// 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];
}
// 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));
}
// 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']);
// 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']);
$characters = array();
foreach($seminaryCharacters as &$character) {
if(!in_array($character['id'], $groupCharacterIds)) {
$characters[] = $character;
}
}
// 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);
// 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');
// Create group
if($validation === true)
{
$groupId = $this->Charactergroups->createGroup(
$this->Auth->getUserId(),
$groupsgroup['id'],
$charactergroupname,
$motto
);
// Redirect to group page
$group = $this->Charactergroups->getGroupById($groupId);
$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];
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('charactergroupname', $charactergroupname);
$this->set('motto', $motto);
$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);
// 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 = $this->request->getPostParam('charactergroupname');
if($this->Charactergroups->characterGroupNameExists($charactergroupname, $group['id'])) {
$validation = $this->Validation->addValidationResult($validation, 'charactergroupname', 'exist', true);
}
$motto = $this->request->getPostParam('motto');
// Edit group
if($validation === true)
{
$this->Charactergroups->editGroup(
$group['id'],
$charactergroupname,
$motto
);
// Redirect to user page
$group = $this->Charactergroups->getGroupById($group['id']);
$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];
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('charactergroupname', $charactergroupname);
$this->set('motto', $motto);
$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));
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('group', $group);
}
}
?>

View file

@ -0,0 +1,91 @@
<?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');
/**
* 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 Character groups-groups
$groups = $this->Charactergroupsquests->getGroupsForQuest($quest['id']);
// Media
$questmedia = null;
if(!is_null($quest['questsmedia_id'])) {
$questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']);
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('quest', $quest);
$this->set('groups', $groups);
$this->set('media', $questmedia);
}
}
?>

View file

@ -0,0 +1,427 @@
<?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')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'index' => array('admin', 'moderator'),
'character' => array('admin', 'moderator', 'user'),
'manage' => 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);
// Set default properties to show
$properties = array(
'username',
'xps'
);
// Select proprties to show
if($this->request->getRequestMethod() == 'POST')
{
$properties = $this->request->getPostParam('properties');
if(!is_array($properties)) {
$properties = array();
}
}
// Get registered Characters
$characters = $this->Characters->getCharactersForSeminary($seminary['id']);
foreach($characters as &$character)
{
$character['xplevel'] = $this->Characters->getXPLevelOfCharacters($character['id']);
$character['characterroles'] = array_map(function($r) { return $r['name']; }, $this->Characterroles->getCharacterrolesForCharacterById($character['id']));
$character['user'] = $this->Users->getUserById($character['user_id']);
$character['characterfields'] = $this->Seminarycharacterfields->getFieldsForCharacter($character['id']);
}
// Get Seminarycharacterfields
$characterfields = $this->Seminarycharacterfields->getFieldsForSeminary($seminary['id']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('characters', $characters);
$this->set('characterfields', $characterfields);
$this->set('properties', $properties);
}
/**
* 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']);
// 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['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']);
}
}
// 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)) {
throw new \nre\exceptions\ParamsNotValidException($typeIndex);
}
// 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->Characters->setSeminaryFieldOfCharacter($characterId, $field['id'], $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']);
// 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();
if($this->request->getRequestMethod() == 'POST')
{
// Do action
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];
$selectedCharacters = $this->request->getPostParam('characters');
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;
}
}
// Properties to show
$properties = $this->request->getPostParam('properties');
if(!is_array($properties)) {
$properties = array();
}
}
// Get registered Characters
$characters = $this->Characters->getCharactersForSeminary($seminary['id']);
foreach($characters as &$character)
{
$character['xplevel'] = $this->Characters->getXPLevelOfCharacters($character['id']);
$character['characterroles'] = array_map(function($r) { return $r['name']; }, $this->Characterroles->getCharacterrolesForCharacterById($character['id']));
$character['user'] = $this->Users->getUserById($character['user_id']);
$character['characterfields'] = $this->Seminarycharacterfields->getFieldsForCharacter($character['id']);
}
// Get Seminarycharacterfields
$characterfields = $this->Seminarycharacterfields->getFieldsForSeminary($seminary['id']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('characters', $characters);
$this->set('characterfields', $characterfields);
$this->set('properties', $properties);
$this->set('selectedCharacters', $selectedCharacters);
}
/**
* 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);
}
}
}
?>

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,68 @@
<?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");
}
/**
* 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());
}
}
?>

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,135 @@
<?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');
/**
* 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 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'];
}
// 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 Questgroup
$quest['questgroup'] = $this->Questgroups->getQuestgroupById($quest['questgroup_id']);
// Get Subtopics
$quest['subtopics'] = $this->Questtopics->getQuestsubtopicsForQuest($quest['id']);
$quests[] = $quest;
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questtopic', $questtopic);
$this->set('quests', $quests);
}
}
?>

View file

@ -0,0 +1,458 @@
<?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 MediaAgent to process and show Media.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class MediaController extends \hhu\z\controllers\SeminaryController
{
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user', 'guest'),
'seminarymoodpic' => array('admin', 'moderator', 'user'),
'seminary' => array('admin', 'moderator', 'user'),
'avatar' => array('admin', 'moderator', 'user'),
'achievement' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'seminary' => array('admin', 'moderator', 'user', 'guest'),
'achievement' => array('admin', 'moderator', 'user', 'guest')
);
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'achievements', 'media', 'avatars');
/**
* 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 headers for caching control
$response->addHeader("Pragma: public");
$response->addHeader("Cache-control: public, max-age=".(60*60*24));
$response->addHeader("Expires: ".gmdate('r', time()+(60*60*24)));
$response->addHeader("Date: ".gmdate(\DateTime::RFC822));
}
/**
* Action: index
*
* Display a medium.
*
* @param string $mediaUrl URL-name of the medium
* @param string $action Action for processing the media
*/
public function index($mediaUrl, $action=null)
{
// Get Media
$media = $this->Media->getMediaByUrl($mediaUrl);
// Get file
$file = $this->getMediaFile($media, $action);
if(is_null($media)) {
return;
}
// Pass data to view
$this->set('media', $media);
$this->set('file', $file);
}
/**
* Action: seminarymoodpic
*
* Display the moodpic for a category of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-title of the Seminary
* @param string $category Category to show moodpic of
* @param string $action Action for processing the media
*/
public function seminarymoodpic($seminaryUrl, $category=null, $action=null)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Set index
switch($category)
{
case null:
$index = 'seminarymedia_id';
break;
case 'charactergroups':
$index = 'charactergroups_seminarymedia_id';
break;
case 'achievements':
$index = 'achievements_seminarymedia_id';
break;
case 'library':
$index = 'library_seminarymedia_id';
break;
}
// Get media
$media = $this->Media->getSeminaryMediaById($seminary[$index]);
// Get file
$file = $this->getMediaFile($media, $action);
if(is_null($file)) {
return;
}
// Pass data to view
$this->set('media', $media);
$this->set('file', $file);
}
/**
* Action: seminary.
*
* Display a Seminary medium.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-title of the Seminary
* @param string $mediaUrl URL-name of the medium
* @param string $action Action for processing the media
*/
public function seminary($seminaryUrl, $mediaUrl, $action=null)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Media
$media = $this->Media->getSeminaryMediaByUrl($seminary['id'], $mediaUrl);
// Get file
$file = $this->getMediaFile($media, $action);
if(is_null($file)) {
return;
}
// Pass data to view
$this->set('media', $media);
$this->set('file', $file);
}
/**
* Action: avatar.
*
* Display an Avatar as full size or portrait.
*
* @throws ParamsNotValidException
* @throws IdNotFoundException
* @param string $seminaryUrl URL-title of the Seminary
* @param string $charactertypeUrl URL-title of Character type
* @param int $xplevel XP-level
* @param string $action Size to show (avatar or portrait)
*/
public function avatar($seminaryUrl, $charactertypeUrl, $xplevel, $action='avatar')
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Avatar
$avatar = $this->Avatars->getAvatarByTypeAndLevel($seminary['id'], $charactertypeUrl, $xplevel);
// Get media
switch($action)
{
case null:
case 'avatar':
$media = $this->Media->getSeminaryMediaById($avatar['avatarpicture_id']);
$file = $this->getMediaFile($media, 'avatar');
break;
case 'portrait':
$media = $this->Media->getSeminaryMediaById($avatar['small_avatarpicture_id']);
$file = $this->getMediaFile($media);
break;
default:
throw new \nre\exceptions\ParamsNotValidException($action);
break;
}
// Get file
if(is_null($file)) {
return;
}
// Pass data to view
$this->set('media', $media);
$this->set('file', $file);
}
/**
* Action: achievement
*
* Display the achievement of a Seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-title of the Seminary
* @param string $achievementUrl URL-title of the Achievement
* @param string $action Action for processing the media
*/
public function achievement($seminaryUrl, $achievementUrl, $locked=null)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character
$character = SeminaryController::$character;
// Get Achievement
$achievement = $this->Achievements->getAchievementByUrl($seminary['id'], $achievementUrl);
// Get media
switch($locked)
{
case null:
if(is_null($character) || !$this->Achievements->hasCharacterAchievedAchievement($achievement['id'], $character['id'])) {
throw new \nre\exceptions\AccessDeniedException();
}
$index = 'achieved_achievementsmedia_id';
break;
case 'locked':
$index = 'unachieved_achievementsmedia_id';
break;
default:
throw new \nre\exceptions\ParamsNotValidException($locked);
break;
}
if(is_null($achievement[$index])) {
throw new \nre\exceptions\IdNotFoundException($achievementUrl);
}
$media = $this->Media->getSeminaryMediaById($achievement[$index]);
// Get file
$file = $this->getMediaFile($media, null);
if(is_null($file)) {
return;
}
// Pass data to view
$this->set('media', $media);
$this->set('file', $file);
}
/**
* Determine file information and set the HTTP-header for
* caching accordingly.
*
* @param string $fileName Filename
* @return boolean HTTP-status 304 was set (in cache)
*/
private function setCacheHeaders($fileName)
{
// Determine last change of file
$fileLastModified = gmdate('r', filemtime($fileName));
// Generate E-Tag
$fileEtag = hash('sha256', $fileLastModified.$fileName);
// Set header
$this->response->addHeader("Last-Modified: ".$fileLastModified);
$this->response->addHeader("Etag: ".$fileEtag);
// HTTP-status
$headerModifiedSince = $this->request->getServerParam('HTTP_IF_MODIFIED_SINCE');
$headerNoneMatch = $this->request->getServerParam('HTTP_IF_NONE_MATCH');
if(
!is_null($headerModifiedSince) && $fileLastModified < strtotime($headerModifiedSince) &&
!is_null($headerNoneMatch) && $headerNoneMatch == $fileEtag
) {
$this->response->setExit(true);
$this->response->addHeader(\nre\core\WebUtils::getHttpHeader(304));
return true;
}
return false;
}
/**
* Determine the file for a medium and process it if necessary.
*
* @throws IdNotFoundException
* @throws ParamsNotValidException
* @param array $media Medium to get file for
* @param string $action Action for processing the media
* @return object File for the medium (or null if medium is cached)
*/
private function getMediaFile($media, $action=null)
{
// Get format
$format = explode('/', $media['mimetype']);
$format = $format[1];
// Set content-type
$this->response->addHeader("Content-type: ".$media['mimetype']."");
// Set filename
$media['filename'] = ROOT.DS.\nre\configs\AppConfig::$dirs['seminarymedia'].DS.$media['id'];
if(!file_exists($media['filename'])) {
throw new \nre\exceptions\IdNotFoundException($mediaUrl);
}
// Cache
if($this->setCacheHeaders($media['filename'])) {
return null;
}
// Load and process file
$file = null;
switch($action)
{
// No action
case null:
// Do not process the file
$file = file_get_contents($media['filename']);
break;
case 'questgroup':
if(!in_array(strtoupper($format), self::getImageTypes())) {
$file = file_get_contents($media['filename']);
}
else
{
$file = self::resizeImage(
$media['filename'],
$format,
\nre\configs\AppConfig::$media['questgroup']['width'],
\nre\configs\AppConfig::$media['questgroup']['height']
);
}
break;
case 'avatar':
$file = self::resizeImage(
$media['filename'],
$format,
\nre\configs\AppConfig::$media['avatar']['width'],
\nre\configs\AppConfig::$media['avatar']['height']
);
break;
default:
throw new ParamsNotValidException($action);
break;
}
// Return file
return $file;
}
/**
* Get supported image types.
*
* @return array List of supported image types
*/
private static function getImageTypes()
{
$im = new \Imagick();
return $im->queryFormats();
}
/**
* Resize an image.
*
* @param string $fileName Absolute pathname of image to resize
* @param string $mimeType Mimetype of target image
* @param int $width Max. width to resize to
* @param int $height Max. height to resize to
* @return mixed Resized image
*/
private static function resizeImage($fileName, $mimeType, $width, $height)
{
// Read image from cache
$tempFileName = ROOT.DS.\nre\configs\AppConfig::$dirs['temporary'].DS.'media-'.basename($fileName).'-'.$width.'x'.$height;
if(file_exists($tempFileName))
{
// Check age of file
if(date('r', filemtime($tempFileName)+(60*60*24)) > date('r', time())) {
// Too old, delete
unlink($tempFileName);
}
else {
// Valid, read and return
return file_get_contents($tempFileName);
}
}
// ImageMagick
$im = new \Imagick($fileName);
// Calculate new size
$geometry = $im->getImageGeometry();
if($geometry['width'] < $width) {
$width = $geometry['width'];
}
if($geometry['height'] < $height) {
$height = $geometry['width'];
}
// Process
$im->thumbnailImage($width, $height, true);
$im->contrastImage(1);
$im->setImageFormat($mimeType);
// Save temporary file
$im->writeImage($tempFileName);
// Return resized image
return $im;
}
}
?>

View file

@ -0,0 +1,52 @@
<?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 menu.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class MenuController extends \hhu\z\Controller
{
/**
* 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 userdata
$this->set('loggedUser', IntermediateController::$user);
$this->set('loggedCharacter', SeminaryController::$character);
$this->set('loggedSeminary', SeminaryController::$seminary);
}
/**
* Action: index.
*/
public function index()
{
}
}
?>

View file

@ -0,0 +1,238 @@
<?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 QuestgroupsAgent to display Questgroups.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuestgroupsController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'questgroupshierarchy', 'questgroups', 'quests', 'questtexts', 'media');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'questgroup' => array('admin', 'moderator', 'user'),
'create' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'questgroup' => array('admin', 'moderator', 'user'),
'create' => array('admin', 'moderator')
);
/**
* Action: questgroup.
*
* Display a Questgroup and its data.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $questgroupUrl URL-Title of a Questgroup
*/
public function questgroup($seminaryUrl, $questgroupUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Questgroup
$questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
// Get Questgrouphierarchy
$questgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroup['id']);
// Get Character
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Check permission
if(count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) == 0)
{
$previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
if(!is_null($previousQuestgroup)) {
if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
throw new \nre\exceptions\AccessDeniedException();
}
}
}
// Set status “entered”
$this->Questgroups->setQuestgroupEntered($questgroup['id'], $character['id']);
// Get child Questgroupshierarchy
$childQuestgroupshierarchy = null;
if(!empty($questgroup['hierarchy']))
{
$childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($questgroup['hierarchy']['id']);
foreach($childQuestgroupshierarchy as &$hierarchy)
{
// Get Questgroups
$hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id'], $questgroup['id']);
// Get additional data
foreach($hierarchy['questgroups'] as $i => &$group)
{
$group['solved'] = $this->Questgroups->hasCharacterSolvedQuestgroup($group['id'], $character['id']);
// Check permission of Questgroups
if($i >= 1 && count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) == 0)
{
if(!$hierarchy['questgroups'][$i-1]['solved'])
{
$hierarchy['questgroups'] = array_slice($hierarchy['questgroups'], 0, $i);
break;
}
}
// Get cumulated data
$data = $this->Questgroups->getCumulatedDataForQuestgroup($group['id'], $character['id']);
$group['xps'] = $data['xps'];
$group['character_xps'] = $data['character_xps'];
// Attach related Questgroups
$group['relatedQuestgroups'] = array();
$relatedQuestgroups = $this->Questgroups->getRelatedQuestsgroupsOfQuestgroup($group['id']);
foreach($relatedQuestgroups as &$relatedQuestgroup) {
if($this->Questgroups->hasCharacterEnteredQuestgroup($relatedQuestgroup['id'], $character['id'])) {
$group['relatedQuestgroups'][] = $this->Questgroups->getQuestgroupById($relatedQuestgroup['id']);
}
}
}
}
}
// Get texts
$questgroupTexts = $this->Questgroups->getQuestgroupTexts($questgroup['id']);
// Get Character XPs
$questgroup['character_xps'] = $this->Questgroups->getAchievedXPsForQuestgroup($questgroup['id'], $character['id']);
// Media
$picture = null;
if(!is_null($questgroup['questgroupspicture_id']))
{
$picture = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']);
}
// Get Quests
$quests = array();
if(count($childQuestgroupshierarchy) == 0)
{
$currentQuest = null;
do {
// Get next Quest
if(is_null($currentQuest)) {
$currentQuest = $this->Quests->getFirstQuestOfQuestgroup($questgroup['id']);
}
else {
$nextQuests = $this->Quests->getNextQuests($currentQuest['id']);
$currentQuest = null;
foreach($nextQuests as &$nextQuest) {
if($this->Quests->hasCharacterEnteredQuest($nextQuest['id'], $character['id'])) {
$currentQuest = $nextQuest;
break;
}
}
}
// Add additional data
if(!is_null($currentQuest))
{
// Set status
$currentQuest['solved'] = $this->Quests->hasCharacterSolvedQuest($currentQuest['id'], $character['id']);
// Attach related Questgroups
$currentQuest['relatedQuestgroups'] = array();
$relatedQuestgroups = $this->Questgroups->getRelatedQuestsgroupsOfQuest($currentQuest['id']);
foreach($relatedQuestgroups as &$relatedQuestgroup)
{
if($this->Questgroups->hasCharacterEnteredQuestgroup($relatedQuestgroup['id'], $character['id'])) {
$currentQuest['relatedQuestgroups'][] = $this->Questgroups->getQuestgroupById($relatedQuestgroup['id']);
}
}
// Add Quest to Quests
$quests[] = $currentQuest;
}
}
while(!is_null($currentQuest) && ($currentQuest['solved'] || count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) > 0));
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
$this->set('childquestgroupshierarchy', $childQuestgroupshierarchy);
$this->set('texts', $questgroupTexts);
$this->set('picture', $picture);
$this->set('quests', $quests);
}
/**
* Action: create.
*
* Create a new Questgroup.
*
* @param string $seminaryUrl URL-Title of a Seminary
*/
public function create($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Create Questgroup
$validation = true;
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
{
// TODO Validation
$title = $this->request->getPostParam('title');
// Create new Questgroup
if($validation === true)
{
$questgroupId = $this->Questgroups->createQuestgroup(
$this->Auth->getUserId(),
$seminary['id'],
$title
);
// Redirect
$this->redirect($this->linker->link(array('seminaries', 'seminary', $seminary['url'])));
}
}
// Pass data to view
$this->set('seminary', $seminary);
}
}
?>

View file

@ -0,0 +1,90 @@
<?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 QuestgroupshierarchypathAgent to display the
* Questgroups hierarchy path.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuestgroupshierarchypathController extends \hhu\z\Controller
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'questgroups', 'questgroupshierarchy', 'quests', 'questtexts');
/**
* Action: index.
*
* Calculate and show the hierarchy path of a Questgroup.
*
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $questgroupUrl URL-Title of a Questgroup
* @param boolean $showGroup Show the current group itself
*/
public function index($seminaryUrl, $questgroupUrl, $showGroup=false)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Questgroup
$questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
$questgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroup['id']);
// Get parent Questgrouphierarchy
$currentQuestgroup = $questgroup;
$parentQuestgroupshierarchy = array();
if($showGroup) {
array_unshift($parentQuestgroupshierarchy, $currentQuestgroup);
}
if(is_null($questgroup['hierarchy']))
{
// Get related Questgroup
$questtext = $this->Questtexts->getRelatedQuesttextForQuestgroup($currentQuestgroup['id']);
$quest = $this->Quests->getQuestById($questtext['quest_id']);
$currentQuestgroup = $this->Questgroups->getQuestgroupById($quest['questgroup_id']);
$currentQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($currentQuestgroup['id']);
$quest['questgroup'] = $currentQuestgroup;
// Use Hierarchy name for optional Questgroup
if(!empty($parentQuestgroupshierarchy)) {
$parentQuestgroupshierarchy[0]['hierarchy'] = $currentQuestgroup['hierarchy'];
unset($parentQuestgroupshierarchy[0]['hierarchy']['questgroup_pos']);
}
array_unshift($parentQuestgroupshierarchy, $quest);
array_unshift($parentQuestgroupshierarchy, $currentQuestgroup);
}
while(!empty($currentQuestgroup['hierarchy']) && !is_null($currentQuestgroup['hierarchy']['parent_questgroup_id']))
{
$currentQuestgroup = $this->Questgroups->GetQuestgroupById($currentQuestgroup['hierarchy']['parent_questgroup_id']);
$currentQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($currentQuestgroup['id']);
array_unshift($parentQuestgroupshierarchy, $currentQuestgroup);
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('parentquestgroupshierarchy', $parentQuestgroupshierarchy);
}
}
?>

View file

@ -0,0 +1,819 @@
<?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 QuestsAgent to display Quests.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class QuestsController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'questgroups', 'quests', 'questtexts', 'media', 'questtypes', 'questgroupshierarchy');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user'),
'quest' => array('admin', 'moderator', 'user'),
'submissions' => array('admin', 'moderator', 'user'),
'submission' => array('admin', 'moderator', 'user'),
'create' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'index' => array('admin', 'moderator', 'user'),
'quest' => array('admin', 'moderator', 'user'),
'submissions' => array('admin', 'moderator'),
'submission' => array('admin', 'moderator'),
'create' => array('admin', 'moderator')
);
/**
* Action: index.
*
* List all Quests for a Seminary.
*
* @param string $seminaryUrl URL-Title of Seminary
*/
public function index($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Prepare filters
$filters = array(
'questgroups' => array(),
'questtypes' => array()
);
// Get selected filters
$selectedFilters = array(
'questgroup' => "0",
'questtype' => ""
);
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('filters'))) {
$selectedFilters = $this->request->getPostParam('filters');
}
// Get Quests
$quests = array();
foreach($this->Quests->getQuestsForSeminary($seminary['id']) as $quest)
{
// Get Questgroup
$quest['questgroup'] = $this->Questgroups->getQuestgroupById($quest['questgroup_id']);
if($selectedFilters['questgroup'] != "0" && $selectedFilters['questgroup'] != $quest['questgroup']['id']) {
continue;
}
// Get Questtype
$quest['questtype'] = $this->Questtypes->getQuesttypeById($quest['questtype_id']);
if($selectedFilters['questtype'] != "" && $selectedFilters['questtype'] != $quest['questtype']['classname']) {
continue;
}
// Add filter values
$filters['questgroups'][$quest['questgroup']['id']] = $quest['questgroup'];
$filters['questtypes'][$quest['questtype']['classname']] = $quest['questtype'];
// Add open submissions count
$quest['opensubmissionscount'] = count($this->Characters->getCharactersSubmittedQuest($quest['id']));
$quests[] = $quest;
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('quests', $quests);
$this->set('filters', $filters);
$this->set('selectedFilters', $selectedFilters);
}
/**
* Action: quest.
*
* Show a quest and its task.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of Seminary
* @param string $questgroupUrl URL-Title of Questgroup
* @param string $questUrl URL-Title of Quest
* @param string $questtexttypeUrl URL-Title of Questtexttype
* @param int $questtextPos Position of Questtext
*/
public function quest($seminaryUrl, $questgroupUrl, $questUrl, $questtexttypeUrl=null, $questtextPos=1)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Questgroup
$questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
$questgroup['picture'] = null;
if(!is_null($questgroup['questgroupspicture_id'])) {
$questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']);
}
// Get Quest
$quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl);
// Get Character
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Check permissions
if(count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) == 0)
{
$previousQuests = $this->Quests->getPreviousQuests($quest['id']);
if(count($previousQuests) == 0)
{
// Previous Questgroup
$previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
if(!is_null($previousQuestgroup) && !$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
throw new \nre\exceptions\AccessDeniedException();
}
}
else
{
// Previous Quests
// One previous Quest has to be solved and no other
// following Quests of ones has to be tried
$solved = false;
$tried = false;
foreach($previousQuests as &$previousQuest)
{
// // Check previous Quest
if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id']))
{
$solved = true;
// Check following Quests
$followingQuests = $this->Quests->getNextQuests($previousQuest['id']);
foreach($followingQuests as $followingQuest)
{
// Check following Quest
if($followingQuest['id'] != $quest['id'] && $this->Quests->hasCharacterTriedQuest($followingQuest['id'], $character['id']))
{
$tried = true;
break;
}
}
break;
}
}
if(!$solved || $tried) {
throw new \nre\exceptions\AccessDeniedException();
}
}
}
// Set status “entered”
$this->Quests->setQuestEntered($quest['id'], $character['id']);
// Has Character solved quest?
$solved = $this->Quests->hasCharacterSolvedQuest($quest['id'], $character['id']);
// Get Questtexts
$questtexts = array();
$questtexts['Prolog'] = $this->Questtexts->getQuesttextsOfQuest($quest['id'], 'Prolog');
if($solved) {
$questtexts['Epilog'] = $this->Questtexts->getQuesttextsOfQuest($quest['id'], 'Epilog');
}
foreach($questtexts as &$questtextList)
{
foreach($questtextList as &$questtext)
{
// Questtext media
if(!is_null($questtext['questsmedia_id'])) {
$questtext['media'] = $this->Media->getSeminaryMediaById($questtext['questsmedia_id']);
}
// Related Questgroups
$questtext['relatedQuestsgroups'] = $this->Questgroups->getRelatedQuestsgroupsOfQuesttext($questtext['id']);
}
}
// Quest status
$questStatus = $this->request->getGetParam('status');
// Quest media
$questmedia = null;
if(!is_null($quest['questsmedia_id'])) {
$questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']);
}
// Task
$task = null;
$questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']);
if(!is_null($questtype['classname'])) {
$task = $this->renderTask($questtype['classname'], $seminary, $questgroup, $quest, $character);
}
else
{
// Mark Quest as solved
$this->Quests->setQuestSolved($quest['id'], $character['id']);
$solved = true;
}
// Get (related) Questtext
$relatedQuesttext = $this->Questtexts->getRelatedQuesttextForQuestgroup($questgroup['id']);
if(!empty($relatedQuesttext)) {
$relatedQuesttext['quest'] = $this->Quests->getQuestById($relatedQuesttext['quest_id']);
if(!empty($relatedQuesttext['quest'])) {
$relatedQuesttext['quest']['questgroup_url'] = $this->Questgroups->getQuestgroupById($relatedQuesttext['quest']['questgroup_id'])['url'];
}
}
// Next Quest/Questgroup
$nextQuests = null;
$charactedHasChoosenNextQuest = false;
$nextQuestgroup = null;
if($solved)
{
// Next Quest
$nextQuests = $this->Quests->getNextQuests($quest['id']);
foreach($nextQuests as &$nextQuest)
{
// Set entered status of Quest
$nextQuest['entered'] = $this->Quests->hasCharacterEnteredQuest($nextQuest['id'], $character['id']);
if($nextQuest['entered']) {
$charactedHasChoosenNextQuest = true;
}
}
// Next Questgroup
if(empty($nextQuests))
{
if(is_null($relatedQuesttext))
{
$nextQuestgroup = $this->Questgroups->getNextQuestgroup($questgroup['id']);
$nextQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyForQuestgroup($nextQuestgroup['id']);
}
else
{
// Related (Main-) Quest
$nextQuest = $relatedQuesttext['quest'];
$nextQuest['entered'] = true;
$nextQuests = array($nextQuest);
}
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
//$this->set('questtexttype', $questtexttype);
$this->set('questtexts', $questtexts);
//$this->set('hasEpilog', $hasEpilog);
$this->set('quest', $quest);
$this->set('queststatus', $questStatus);
$this->set('relatedquesttext', $relatedQuesttext);
$this->set('nextquests', $nextQuests);
$this->set('charactedHasChoosenNextQuest', $charactedHasChoosenNextQuest);
$this->set('nextquestgroup', $nextQuestgroup);
$this->set('task', $task);
$this->set('media', $questmedia);
$this->set('solved', $solved);
}
/**
* List Character submissions for a Quest.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of Seminary
* @param string $questgroupUrl URL-Title of Questgroup
* @param string $questUrl URL-Title of Quest
*/
public function submissions($seminaryUrl, $questgroupUrl, $questUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Questgroup
$questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
$questgroup['picture'] = null;
if(!is_null($questgroup['questgroupspicture_id'])) {
$questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']);
}
// Get Quest
$quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl);
// Media
$questmedia = null;
if(!is_null($quest['questsmedia_id'])) {
$questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']);
}
// Get submitted Character submissions waiting for approval
$submittedSubmissionCharacters = $this->Characters->getCharactersSubmittedQuest($quest['id']);
// Get unsolved Character submissions
$unsolvedSubmissionCharacters = $this->Characters->getCharactersUnsolvedQuest($quest['id']);
// Get solved Character submissions
$solvedSubmissionCharacters = $this->Characters->getCharactersSolvedQuest($quest['id']);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
$this->set('quest', $quest);
$this->set('media', $questmedia);
$this->set('submittedSubmissionCharacters', $submittedSubmissionCharacters);
$this->set('unsolvedSubmissionCharacters', $unsolvedSubmissionCharacters);
$this->set('solvedSubmissionCharacters', $solvedSubmissionCharacters);
}
/**
* Show and handle the submission of a Character for a Quest.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of Seminary
* @param string $questgroupUrl URL-Title of Questgroup
* @param string $questUrl URL-Title of Quest
* @param string $characterUrl URL-Title of Character
*/
public function submission($seminaryUrl, $questgroupUrl, $questUrl, $characterUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Questgroup
$questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
$questgroup['picture'] = null;
if(!is_null($questgroup['questgroupspicture_id'])) {
$questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']);
}
// Get Quest
$quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl);
// Character
$character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl);
// Media
$questmedia = null;
if(!is_null($quest['questsmedia_id'])) {
$questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']);
}
// Questtype
$questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']);
// Render Questtype output
$output = $this->renderTaskSubmission($questtype['classname'], $seminary, $questgroup, $quest, $character);
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
$this->set('quest', $quest);
$this->set('character', $character);
$this->set('media', $questmedia);
$this->set('output', $output);
}
/**
* Action: create.
*
* Create a new Quest.
*
* @param string $seminaryUrl URL-Title of a Seminary
*/
public function create($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Quest groups
$questgroups = $this->Questgroups->getQuestgroupsForSeminary($seminary['id']);
// Quest types
$questtypes = $this->Questtypes->getQuesttypes();
// Create Quest
$validation = true;
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
{
// TODO Validation
$name = $this->request->getPostParam('name');
$xps = $this->request->getPostParam('xps');
$prolog = $this->request->getPostParam('prolog');
$entrytext = $this->request->getPostParam('entrytext');
$wrongtext = $this->request->getPostParam('wrongtext');
$task = $this->request->getPostParam('task');
// 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);
}
// Validate Questtype
$questtypeIndex = null;
foreach($questtypes as $index => &$questtype)
{
$questtype['selected'] = ($questtype['url'] == $this->request->getPostParam('questtype'));
if($questtype['selected']) {
$questtypeIndex = $index;
}
}
if(is_null($questtypeIndex)) {
throw new \nre\exceptions\ParamsNotValidException($questtype);
}
// Questmedia
$questmedia = null;
if(array_key_exists('questmedia', $_FILES) && !empty($_FILES['questmedia']) && $_FILES['questmedia']['error'] == 0) {
$questmedia = $_FILES['questmedia'];
}
// Process Prolog
if(!empty($prolog)) {
$prolog = preg_split('/\s*(_|=){5,}\s*/', $prolog, -1, PREG_SPLIT_NO_EMPTY);
}
// Create new Quest
if($validation === true)
{
$questId = $this->Quests->createQuest(
$this->Auth->getUserId(),
$name,
$questgroups[$questgroupIndex]['id'],
$questtypes[$questtypeIndex]['id'],
$xps,
$entrytext,
$wrongtext,
$task
);
// Create Questmedia
if(!is_null($questmedia))
{
$questsmediaId = $this->Media->createQuestMedia(
$this->Auth->getUserId(),
$seminary['id'],
$questmedia['name'],
$name,
$questmedia['type'],
$questmedia['tmp_name']
);
if($questsmediaId > 0) {
$this->Quests->setQuestmedia($questId, $questsmediaId);
}
}
// Add Prolog-texts
if(!empty($prolog)) {
$this->Questtexts->addQuesttextsToQuest($this->Auth->getUserId(), $questId, 'Prolog', $prolog);
}
// Redirect
$this->redirect($this->linker->link(array('quests', 'index', $seminary['url'])));
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroups', $questgroups);
$this->set('questtypes', $questtypes);
}
/**
* Action: createmedia.
* TODO only temporary for easier data import.
*
* Display a form for creating new Seminary media.
*
* @param string $seminaryUrl URL-title of Seminary
*/
public function createmedia($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Create media
$mediaId = null;
$error = null;
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
{
$file = $_FILES['file'];
$error = $file['error'];
if(empty($error))
{
$mediaId = $this->Media->createQuestMedia(
$this->Auth->getUserId(),
$seminary['id'],
$file['name'],
$this->request->getPostParam('description'),
$file['type'],
$file['tmp_name']
);
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('mediaid', $mediaId);
}
/**
* Render and handle the task of a Quest.
*
* @param string $questtypeClassname Name of the class for the Questtype of a Quest
* @param array $seminary Seminary data
* @param array $questgroup Questgroup data
* @param array $quest Quest data
* @param array $character Character data
* @return string Rendered output
*/
private function renderTask($questtypeClassname, $seminary, $questgroup, $quest, $character)
{
$task = null;
try {
// Generate request and response
$request = clone $this->request;
$response = $this->createQuesttypeResponse('quest', $seminary, $questgroup, $quest, $character);
// Load Questtype Agent
$questtypeAgent = $this->loadQuesttypeAgent($questtypeClassname, $request, $response);
// Solve Quest
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
{
// Get user answers
$answers = $this->request->getPostParam('answers');
// Save answers in database
try {
if(!$this->Quests->hasCharacterSolvedQuest($quest['id'], $character['id'])) {
$questtypeAgent->saveAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers);
}
// Match answers with correct ones
$status = $questtypeAgent->matchAnswersofCharacter($seminary, $questgroup, $quest, $character, $answers);
if($status === true)
{
// Mark Quest as solved
$this->Quests->setQuestSolved($quest['id'], $character['id']);
// Notify of XP-level change
$newXPLevel = $this->Characters->getXPLevelOfCharacters($character['id']);
if($newXPLevel['level'] > $character['xplevel']) {
$this->Notification->addNotification(
\hhu\z\controllers\components\NotificationComponent::TYPE_LEVELUP,
$newXPLevel['level'],
$this->linker->link(array('characters', 'character', $seminary['url'], $character['url']))
);
}
// Redirect
$this->redirect($this->linker->link(array(), 5, true, array('status'=>'solved'), false, 'task'));
}
elseif($status === false)
{
// Mark Quest as unsolved
$this->Quests->setQuestUnsolved($quest['id'], $character['id']);
// Redirect
$this->redirect($this->linker->link(array(), 5, true, array('status'=>'unsolved'), false, 'task'));
}
else {
// Mark Quest as submitted
$this->Quests->setQuestSubmitted($quest['id'], $character['id']);
// Redirect
$this->redirect($this->linker->link(array(), 5, true, false, 'task'));
}
}
catch(\hhu\z\exceptions\SubmissionNotValidException $e) {
$response->addParam($e);
}
}
// Render Task
$task = $this->runQuesttypeAgent($questtypeAgent, $request, $response);
}
catch(\nre\exceptions\ViewNotFoundException $e) {
$task = $e->getMessage();
}
catch(\nre\exceptions\ActionNotFoundException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeControllerNotValidException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeControllerNotFoundException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeAgentNotValidException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeAgentNotFoundException $e) {
$task = $e->getMessage();
}
// Return rendered output
return $task;
}
/**
* Render and handle a Character submission for a Quest.
*
* @param string $questtypeClassname Name of the class for the Questtype of a Quest
* @param array $seminary Seminary data
* @param array $questgroup Questgroup data
* @param array $quest Quest data
* @param array $character Character data
* @return string Rendered output
*/
private function renderTaskSubmission($questtypeClassname, $seminary, $questgroup, $quest, $character)
{
$task = null;
try {
// Generate request and response
$request = clone $this->request;
$response = $this->createQuesttypeResponse('submission', $seminary, $questgroup, $quest, $character);
// Load Questtype Agent
$questtypeAgent = $this->loadQuesttypeAgent($questtypeClassname, $request, $response);
// Solve Quest
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
{
// Set status
if($this->request->getPostParam('submit') == _('solved'))
{
// Mark Quest as solved
$this->Quests->setQuestSolved($quest['id'], $character['id']);
}
else
{
// Mark Quest as unsolved
$this->Quests->setQuestUnsolved($quest['id'], $character['id']);
}
// Save additional data for Character answers
$questtypeAgent->controller->saveDataForCharacterAnswers($seminary, $questgroup, $quest, $character, $this->request->getPostParam('characterdata'));
// Redirect
$this->redirect($this->linker->link(array('submissions', $seminary['url'], $questgroup['url'], $quest['url']), 1));
}
// Render task submissions
$task = $this->runQuesttypeAgent($questtypeAgent, $request, $response);
}
catch(\nre\exceptions\ViewNotFoundException $e) {
$task = $e->getMessage();
}
catch(\nre\exceptions\ActionNotFoundException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeControllerNotValidException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeControllerNotFoundException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeAgentNotValidException $e) {
$task = $e->getMessage();
}
catch(\hhu\z\exceptions\QuesttypeAgentNotFoundException $e) {
$task = $e->getMessage();
}
// Return rendered output
return $task;
}
/**
* Create a response for the Questtype rendering.
*
* @param string $action Action to run
* @param mixed $param Additional parameters to add to the response
* @return Response Generated response
*/
private function createQuesttypeResponse($action, $param1)
{
// Clone current response
$response = clone $this->response;
// Clear parameters
$response->clearParams(1);
// Add Action
$response->addParams(
null,
$action
);
// Add additional parameters
foreach(array_slice(func_get_args(), 1) as $param) {
$response->addParam($param);
}
// Return response
return $response;
}
/**
* Load and construct the QuesttypeAgent for a Questtype.
*
* @param string $questtypeClassname Name of the class for the Questtype of a Quest
* @param Request $request Request
* @param Response $response Response
* @return QuesttypeAgent
*/
private function loadQuesttypeAgent($questtypeClassname, $request, $response)
{
// Load Agent
\hhu\z\QuesttypeAgent::load($questtypeClassname);
// Construct and return Agent
return \hhu\z\QuesttypeAgent::factory($questtypeClassname, $request, $response);
}
/**
* Run and render the Agent for a QuesttypeAgent and return ist output.
*
* @param Agent $questtypeAgent QuesttypeAgent to run and render
* @param Request $request Request
* @param Response $response Response
* @return string Rendered output
*/
private function runQuesttypeAgent($questtypeAgent, $request, $response)
{
// Run Agent
$questtypeAgent->run($request, $response);
// Render and return output
return $questtypeAgent->render();
}
}
?>

View file

@ -0,0 +1,253 @@
<?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 seminaries.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class SeminariesController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('seminaries', 'users', 'characterroles', 'questgroupshierarchy', 'questgroups', 'media');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user'),
'seminary' => array('admin', 'moderator', 'user'),
'create' => array('admin', 'moderator'),
'edit' => array('admin', 'moderator', 'user'),
'delete' => array('admin', 'moderator', 'user')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'seminary' => array('admin', 'moderator', 'user', 'guest'),
'edit' => array('admin'),
'delete' => array('admin')
);
/**
* Action: index.
*
* List registered seminaries.
*/
public function index()
{
// Get seminaries
$seminaries = $this->Seminaries->getSeminaries();
// Get additional data
foreach($seminaries as &$seminary)
{
$seminary['description'] = \hhu\z\Utils::shortenString($seminary['description'], 100, 120).' …';
// Created user
$seminary['creator'] = $this->Users->getUserById($seminary['created_user_id']);
// Character of currently logged-in user
try {
$seminary['usercharacter'] = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
$seminary['usercharacter']['characterroles'] = $this->Characterroles->getCharacterrolesForCharacterById($seminary['usercharacter']['id']);
}
catch(\nre\exceptions\IdNotFoundException $e) {
}
}
// Pass data to view
$this->set('seminaries', $seminaries);
}
/**
* Action: seminary.
*
* Show a seminary and its details.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a seminary
*/
public function seminary($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Created user
$seminary['creator'] = $this->Users->getUserById($seminary['created_user_id']);
// Get Character
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Questgrouphierarchy and Questgroups
$questgroupshierarchy = $this->Questgroupshierarchy->getHierarchyOfSeminary($seminary['id']);
foreach($questgroupshierarchy as &$hierarchy)
{
// Get Questgroups
$hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id']);
// Get additional data
foreach($hierarchy['questgroups'] as $i => &$questgroup)
{
// Check permission of Questgroups
if($i >= 1 && count(array_intersect(array('admin','moderator'), SeminaryController::$character['characterroles'])) == 0)
{
if(!$this->Questgroups->hasCharacterSolvedQuestgroup($hierarchy['questgroups'][$i-1]['id'], $character['id']))
{
$hierarchy['questgroups'] = array_slice($hierarchy['questgroups'], 0, $i);
break;
}
}
// Get first Questgroup text
$text = $this->Questgroups->getFirstQuestgroupText($questgroup['id']);
if(!is_null($text))
{
$questgroup['text'] = \hhu\z\Utils::shortenString($text, 100, 120).' …';
}
// Get cumulated data
$data = $this->Questgroups->getCumulatedDataForQuestgroup($questgroup['id'], $character['id']);
$questgroup['xps'] = $data['xps'];
$questgroup['character_xps'] = $data['character_xps'];
// Get Media
$questgroup['picture'] = null;
try {
$questgroup['picture'] = $this->Media->getSeminaryMediaById($questgroup['questgroupspicture_id']);
}
catch(\nre\exceptions\IdNotFoundException $e) {
}
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroupshierarchy', $questgroupshierarchy);
}
/**
* Action: create.
*
* Create a new seminary.
*/
public function create()
{
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
{
// Create new seminary
$seminaryId = $this->Seminaries->createSeminary(
$this->request->getPostParam('title'),
$this->Auth->getUserId()
);
// Redirect to seminary
$user = $this->Seminaries->getSeminaryById($seminaryId);
$this->redirect($this->linker->link(array($seminary['url']), 1));
}
}
/**
* Action: edit.
*
* Edit a seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a seminary
*/
public function edit($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Save changes
if(!is_null($this->request->getPostParam('save')))
{
// Edit seminary
$this->Seminaries->editSeminary(
$seminary['id'],
$this->request->getPostParam('title')
);
$seminary = $this->Seminaries->getSeminaryById($seminary['id']);
}
// Redirect to entry
$this->redirect($this->linker->link(array($seminary['url']), 1));
}
// Pass data to view
$this->set('seminary', $seminary);
}
/**
* Action: delete.
*
* Delete a seminary.
*
* @throws IdNotFoundException
* @param string $seminaryUrl URL-Title of a seminary
*/
public function delete($seminaryUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Check confirmation
if(!is_null($this->request->getPostParam('delete')))
{
// Delete seminary
$this->Seminaries->deleteSeminary($seminary['id']);
// Redirect to overview
$this->redirect($this->linker->link(null, 1));
}
// Redirect to entry
$this->redirect($this->linker->link(array('seminary', $seminary['url']), 1));
}
// Show confirmation
$this->set('seminary', $seminary);
}
}
?>

View file

@ -0,0 +1,86 @@
<?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 sidebar with Seminary related
* information.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class SeminarybarController extends \hhu\z\Controller
{
/**
* Required models
*
* @var array
*/
public $models = array('characters', 'quests', 'questgroups', 'achievements', 'charactergroups', 'avatars', 'media');
/**
* Action: index.
*/
public function index()
{
if(is_null(SeminaryController::$seminary)) {
return;
}
// Get Seminary
$seminary = SeminaryController::$seminary;
// Get Character
$character = SeminaryController::$character;
if(is_null($character)) {
return;
}
$character['xplevel'] = $this->Characters->getXPLevelOfCharacters($character['id']);
$character['rank'] = $this->Characters->getXPRank($seminary['id'], $character['xps']);
// Get “last” Quest
$lastQuest = $this->Quests->getLastQuestForCharacter($character['id']);
if(!is_null($lastQuest)) {
$lastQuest['questgroup'] = $this->Questgroups->getQuestgroupById($lastQuest['questgroup_id']);
}
// Get last achieved Achievement
$achievements = $this->Achievements->getAchievedAchievementsForCharacter($character['id']);
$lastAchievement = array_shift($achievements);
// Get Character group members
$characterGroups = array();
foreach($this->Charactergroups->getGroupsForCharacter($character['id']) as $group)
{
$groupsgroup = $this->Charactergroups->getGroupsgroupById($group['charactergroupsgroup_id']);
if($groupsgroup['preferred'])
{
$group['members'] = $this->Characters->getCharactersForGroup($group['id']);
$characterGroups[] = $group;
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('character', $character);
$this->set('lastQuest', $lastQuest);
$this->set('lastAchievement', $lastAchievement);
$this->set('characterGroups', $characterGroups);
}
}
?>

View file

@ -0,0 +1,53 @@
<?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 menu with Seminary related
* links.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class SeminarymenuController extends \hhu\z\Controller
{
/**
* 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 userdata
$this->set('loggedUser', \hhu\z\controllers\IntermediateController::$user);
$this->set('loggedSeminary', \hhu\z\controllers\SeminaryController::$seminary);
$this->set('loggedCharacter', \hhu\z\controllers\SeminaryController::$character);
}
/**
* Action: index.
*/
public function index()
{
}
}
?>

View file

@ -0,0 +1,171 @@
<?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 UploadsAgent to process and show user uploads.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class UploadsController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('uploads', 'users', 'userroles', 'characterroles', 'seminaries');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator', 'user', 'guest')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'seminary' => array('admin', 'moderator', 'user', 'guest')
);
/**
* 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 headers for caching control
$response->addHeader("Pragma: public");
$response->addHeader("Cache-control: public, max-age=".(60*60*24));
$response->addHeader("Expires: ".gmdate('r', time()+(60*60*24)));
$response->addHeader("Date: ".gmdate(\DateTime::RFC822));
}
/**
* Action: seminary.
*
* Display a Seminary upload.
*
* @throws AccessDeniedException
* @throws IdNotFoundException
* @param string $seminaryUrl URL-title of Seminary
* @param string $uploadUrl URL-name of the upload
*/
public function seminary($seminaryUrl, $uploadUrl)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Upload
$upload = $this->Uploads->getSeminaryuploadByUrl($seminary['id'], $uploadUrl);
// Check permissions
if(!$upload['public'])
{
$user = $this->Users->getUserById($this->Auth->getUserId());
$user['roles'] = array_map(function($r) { return $r['name']; }, $this->Userroles->getUserrolesForUserById($user['id']));
// System roles
if(count(array_intersect(array('admin', 'moderator'), $user['roles'])) == 0)
{
// Owner of file
if($upload['created_user_id'] != $user['id'])
{
// Seminary permissions
$characterRoles = array_map(function($r) { return $r['name']; }, $this->Characterroles->getCharacterrolesForCharacterById($character['id']));
if(count(array_intersect(array('admin', 'moderator'), $characterRoles)) == 0) {
throw new \nre\exceptions\AccessDeniedException();
}
}
}
}
// Set content-type
$this->response->addHeader("Content-type: ".$upload['mimetype']."");
// Set filename
$upload['filename'] = ROOT.DS.\nre\configs\AppConfig::$dirs['seminaryuploads'].DS.$upload['url'];
if(!file_exists($upload['filename'])) {
throw new \nre\exceptions\IdNotFoundException($uploadUrl);
}
// Cache
if($this->setCacheHeaders($upload['filename'])) {
return;
}
// Load file
$file = file_get_contents($upload['filename']);
// Pass data to view
$this->set('upload', $upload);
$this->set('file', $file);
}
/**
* Determine file information and set the HTTP-header for
* caching accordingly.
*
* @param string $fileName Filename
* @return boolean HTTP-status 304 was set (in cache)
*/
private function setCacheHeaders($fileName)
{
// Determine last change of file
$fileLastModified = gmdate('r', filemtime($fileName));
// Generate E-Tag
$fileEtag = hash('sha256', $fileLastModified.$fileName);
// Set header
$this->response->addHeader("Last-Modified: ".$fileLastModified);
$this->response->addHeader("Etag: ".$fileEtag);
// HTTP-status
$headerModifiedSince = $this->request->getServerParam('HTTP_IF_MODIFIED_SINCE');
$headerNoneMatch = $this->request->getServerParam('HTTP_IF_NONE_MATCH');
if(
!is_null($headerModifiedSince) && $fileLastModified < strtotime($headerModifiedSince) &&
!is_null($headerNoneMatch) && $headerNoneMatch == $fileEtag
) {
$this->response->setExit(true);
$this->response->addHeader(\nre\core\WebUtils::getHttpHeader(304));
return true;
}
return false;
}
}
?>

View file

@ -0,0 +1,47 @@
<?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 and manage userroles.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class UserrolesController extends \hhu\z\Controller
{
/**
* Action: user.
*
* Show a user and its details.
*
* @throws IdNotFoundException
* @param string $userUrl URL-Username of an user
*/
public function user($userUrl)
{
// Get userroles
$roles = $this->Userroles->getUserrolesForUserByUrl($userUrl);
// Pass data to view
$this->set('roles', $roles);
}
}
?>

View file

@ -0,0 +1,371 @@
<?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 UsersController extends \hhu\z\controllers\IntermediateController
{
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'index' => array('admin', 'moderator'),
'user' => array('admin', 'moderator', 'user'),
'create' => array('admin', 'moderator'),
'edit' => array('admin', 'moderator'),
'delete' => array('admin')
);
/**
* Required models
*
* @var array
*/
public $models = array('users', 'characters', 'avatars', 'media', 'characterroles');
/**
* Required components
*
* @var array
*/
public $components = array('validation');
/**
* Action: index.
*/
public function index()
{
// Get registered users
$users = $this->Users->getUsers();
// Pass data to view
$this->set('users', $users);
}
/**
* Action: user.
*
* Show a user and its details.
*
* @throws IdNotFoundException
* @throws AccessDeniedException
* @param string $userUrl URL-Username of an user
*/
public function user($userUrl)
{
// Get user
$user = $this->Users->getUserByUrl($userUrl);
// Check permissions
if(count(array_intersect(array('admin','moderator'), \hhu\z\controllers\IntermediateController::$user['roles'])) == 0 && $user['id'] != IntermediateController::$user['id']) {
throw new \nre\exceptions\AccessDeniedException();
}
// Get Characters
$characters = $this->Characters->getCharactersForUser($user['id']);
// Additional Character information
foreach($characters as &$character)
{
// Seminary roles
$character['characterroles'] = $this->Characterroles->getCharacterrolesForCharacterById($character['id']);
$character['characterroles'] = array_map(function($a) { return $a['name']; }, $character['characterroles']);
// Level
$character['xplevel'] = $this->Characters->getXPLevelOfCharacters($character['id']);
// Avatar
$avatar = $this->Avatars->getAvatarById($character['avatar_id']);
if(!is_null($avatar['small_avatarpicture_id']))
{
//$character['seminary'] =
$character['small_avatar'] = $this->Media->getSeminaryMediaById($avatar['small_avatarpicture_id']);
}
}
// Pass data to view
$this->set('user', $user);
$this->set('characters', $characters);
}
/**
* Action: login.
*
* Log in a user.
*/
public function login()
{
$username = '';
$referrer = null;
// Log the user in
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('login')))
{
$username = $this->request->getPostParam('username');
$referrer = $this->request->getPostParam('referrer');
$userId = $this->Users->login(
$username,
$this->request->getPostParam('password')
);
if(!is_null($userId))
{
$this->Auth->setUserId($userId);
$user = $this->Users->getUserById($userId);
if(!empty($referrer)) {
$this->redirect($referrer);
}
else {
$this->redirect($this->linker->link(array($user['url']), 1));
}
}
}
// Pass data to view
$this->set('username', $username);
$this->set('referrer', $referrer);
$this->set('failed', ($this->request->getRequestMethod() == 'POST'));
}
/**
* Action: register.
*
* Register a new user.
*/
public function register()
{
$username = '';
$prename = '';
$surname = '';
$email = '';
$fields = array('username', 'prename', 'surname', 'email', 'password');
$validation = array();
// Register a new user
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('register')))
{
// Get params and validate them
$validation = $this->Validation->validateParams($this->request->getPostParams(), $fields);
$username = $this->request->getPostParam('username');
if($this->Users->usernameExists($username)) {
$validation = $this->Validation->addValidationResult($validation, 'username', 'exist', true);
}
$prename = $this->request->getPostParam('prename');
$surname = $this->request->getPostParam('surname');
$email = $this->request->getPostParam('email');
if($this->Users->emailExists($email)) {
$validation = $this->Validation->addValidationResult($validation, 'email', 'exist', true);
}
// Register
if($validation === true)
{
$userId = $this->Users->createUser(
$username,
$prename,
$surname,
$email,
$this->request->getPostParam('password')
);
// Send mail
$this->sendRegistrationMail($username, $email);
// Login
$this->Auth->setUserId($userId);
$user = $this->Users->getUserById($userId);
// Redirect to user page
$this->redirect($this->linker->link(array($user['url']), 1));
}
}
// Get validation settings
$validationSettings = array();
foreach($fields as &$field) {
$validationSettings[$field] = \nre\configs\AppConfig::$validation[$field];
}
// Pass data to view
$this->set('username', $username);
$this->set('prename', $prename);
$this->set('surname', $surname);
$this->set('email', $email);
$this->set('validation', $validation);
$this->set('validationSettings', $validationSettings);
}
/**
* Action: logout.
*
* Log out a user.
*/
public function logout()
{
// Unset the currently logged in user
$this->Auth->setUserId(null);
// Redirect
$this->redirect($this->linker->link(array()));
}
/**
* Action: create.
*
* Create a new user.
*/
public function create()
{
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
{
// Create new user
$userId = $this->Users->createUser(
$this->request->getPostParam('username'),
$this->request->getPostParam('prename'),
$this->request->getPostParam('surname'),
$this->request->getPostParam('email'),
$this->request->getPostParam('password')
);
// Redirect to user
$user = $this->Users->getUserById($userId);
$this->redirect($this->linker->link(array($user['url']), 1));
}
}
/**
* Action: edit.
*
* Edit a user.
*
* @throws IdNotFoundException
* @param string $userUrl URL-Username of an user
*/
public function edit($userUrl)
{
// User
$user = $this->Users->getUserByUrl($userUrl);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Save changes
if(!is_null($this->request->getPostParam('save')))
{
// Edit user
$this->Users->editUser(
$user['id'],
$this->request->getPostParam('username'),
$this->request->getPostParam('prename'),
$this->request->getPostParam('surname'),
$this->request->getPostParam('email'),
$this->request->getPostParam('password')
);
$user = $this->Users->getUserById($user['id']);
}
// Redirect to entry
$this->redirect($this->linker->link(array($user['url']), 1));
}
// Pass data to view
$this->set('user', $user);
}
/**
* Action: delete.
*
* Delete a user.
*
* @throws IdNotFoundException
* @param string $userUrl URL-Username of an user
*/
public function delete($userUrl)
{
// User
$user = $this->Users->getUserByUrl($userUrl);
// Check request method
if($this->request->getRequestMethod() == 'POST')
{
// Check confirmation
if(!is_null($this->request->getPostParam('delete')))
{
// Delete user
$this->Users->deleteUser($user['id']);
// Redirect to overview
$this->redirect($this->linker->link(null, 1));
}
// Redirect to entry
$this->redirect($this->linker->link(array('user', $user['url']), 1));
}
// Show confirmation
$this->set('user', $user);
}
/**
* Send mail for new user registration.
*
* @param string $username Name of newly registered user
* @param string $email Email address of newly registered user
*/
private function sendRegistrationMail($username, $email)
{
$sender = \nre\configs\AppConfig::$app['mailsender'];
if(empty($sender)) {
return;
}
// Send notification mail to system moderators
$subject = sprintf('new user registration: %s', $username);
$message = sprintf('User “%s” <%s> has registered themself to %s', $username, $email, \nre\configs\AppConfig::$app['name']);
$moderators = $this->Users->getUsersWithRole('moderator');
foreach($moderators as &$moderator)
{
\hhu\z\Utils::sendMail($sender, $moderator['email'], $subject, $message);
}
}
}
?>

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\controllers\components;
/**
* Component to handle achievements.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class AchievementComponent extends \nre\core\Component
{
/**
* Required models
*
* @var array
*/
public $models = array('achievements');
/**
* Construct a new Achievements-component.
*/
public function __construct()
{
}
}
?>

View file

@ -0,0 +1,79 @@
<?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\components;
/**
* Component to handle authentication and authorization.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class AuthComponent extends \nre\core\Component
{
/**
* Key to save a user-ID as
*
* @var string
*/
const KEY_USER_ID = 'user_id';
/**
* Construct a new Auth-component.
*/
public function __construct()
{
// Start session
if(session_id() === '') {
session_start();
}
}
/**
* Set the ID of the user that is currently logged in.
*
* @param int $userId ID of the currently logged in user
*/
public function setUserId($userId)
{
if(is_null($userId)) {
unset($_SESSION[self::KEY_USER_ID]);
}
else {
$_SESSION[self::KEY_USER_ID] = $userId;
}
}
/**
* Get the ID of the user that is currently logged in.
*
* @return int ID of the currently logged in user
*/
public function getUserId()
{
if(array_key_exists(self::KEY_USER_ID, $_SESSION)) {
return $_SESSION[self::KEY_USER_ID];
}
return null;
}
}
?>

View file

@ -0,0 +1,108 @@
<?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\components;
/**
* Component to handle user notifications
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class NotificationComponent extends \nre\core\Component
{
/**
* Type: Achievement
*
* @var string
*/
const TYPE_ACHIEVEMENT = 'achievement';
/**
* Type: Level-up
*
* @var string
*/
const TYPE_LEVELUP = 'levelup';
/**
* Key for Session-Array to store notifications in
*
* @var string
*/
const SESSION_KEY = 'notifications';
/**
* Construct a new Notification-component.
*/
public function __construct()
{
// Start session
if(session_id() === '') {
session_start();
}
// Prepare array
if(!array_key_exists(self::SESSION_KEY, $_SESSION)) {
$_SESSION[self::SESSION_KEY] = array();
}
}
/**
* Add a notification.
*
* @param string $type Type of notification
* @param string $message Message to display
* @param string $link Optional URL to link to
* @param string $image Optional URL of image to display
*/
public function addNotification($type, $message, $link=null, $image=null)
{
$_SESSION[self::SESSION_KEY][] = array(
'type' => $type,
'message' => $message,
'link' => $link,
'image' => $image
);
}
/**
* Get all registered notifiactions and clear them.
*
* @return array List of existing notifications
*/
public function getNotifications()
{
$notifications = $_SESSION[self::SESSION_KEY];
$this->clearNotifications();
return $notifications;
}
/**
* Clear all notifications currently registered
*/
public function clearNotifications()
{
unset($_SESSION[self::SESSION_KEY]);
$_SESSION[self::SESSION_KEY] = array();
}
}
?>

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\controllers\components;
/**
* Component to validate user input.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class ValidationComponent extends \nre\core\Component
{
/**
* Validation settings
*
* @var array
*/
private $config;
/**
* Construct a new Validation-component.
*/
public function __construct()
{
// Get validation settings from configuration
$this->config = \nre\configs\AppConfig::$validation;
}
/**
* Validate an user input.
*
* @param mixed $input User input to validate
* @param array $settings Validation setting
* @return mixed True or the settings the validation fails on
*/
public function validate($input, $settings)
{
$validation = array();
// Min string length
if(array_key_exists('minlength', $settings) && strlen($input) < $settings['minlength']) {
$validation['minlength'] = $settings['minlength'];
}
// Max string length
if(array_key_exists('maxlength', $settings) && strlen($input) > $settings['maxlength']) {
$validation['maxlength'] = $settings['maxlength'];
}
// Regex
if(array_key_exists('regex', $settings) && !preg_match($settings['regex'], $input)) {
$validation['regex'] = $settings['regex'];
}
// Return true or the failed fields
if(empty($validation)) {
return true;
}
return $validation;
}
/**
* Validate user input parameters.
*
* @param array $params User input parameters
* @param array $indices Names of parameters to validate and to validate against
* @return mixed True or the parameters with settings the validation failed on
*/
public function validateParams($params, $indices)
{
$validation = array();
foreach($indices as $index)
{
if(!array_key_exists($index, $params)) {
throw new \nre\exceptions\ParamsNotValidException($index);
}
// Check parameter
if(array_key_exists($index, $this->config))
{
$param = $params[$index];
$check = $this->validate($param, $this->config[$index]);
if($check !== true) {
$validation[$index] = $check;
}
}
}
// Return true or the failed parameters with failed settings
if(empty($validation)) {
return true;
}
return $validation;
}
/**
* Add a custom determined validation result to a validation
* store.
*
* @param mixed $validation Validation store to add result to
* @param string $param Name of parameter of the custom validation result
* @param string $setting Name of setting of the custom validation result
* @param mixed $result Validation result
* @return mixed The altered validation store
*/
public function addValidationResult($validation, $param, $setting, $result)
{
if(!is_array($validation)) {
$validation = array();
}
if(!array_key_exists($param, $validation)) {
$validation[$param] = array();
}
$validation[$param][$setting] = $result;
return $validation;
}
}
?>

607
core/Agent.inc Normal file
View file

@ -0,0 +1,607 @@
<?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\core;
/**
* Abstract class for the implementation af an Agent.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class Agent
{
/**
* Name of BottomlevelAgent for showing inline errors
*
* @var string
*/
const INLINEERROR_AGENT = 'inlineerror';
/**
* Current request
*
* @var Request
*/
private $request;
/**
* Current response
*
* @var Response
*/
private $response;
/**
* Log-system
*
* @var Logger
*/
protected $log;
/**
* SubAgents
*
* @var array
*/
protected $subAgents = array();
/**
* Controller of this Agent
*
* @var Controller
*/
public $controller = null;
/**
* Load the class of an Agent.
*
* @static
* @throws AgentNotFoundException
* @throws AgentNotValidException
* @param string $agentName Name of the Agent to load
*/
public static function load($agentName)
{
// Determine full classname
$agentType = self::getAgentType();
$className = self::getClassName($agentName, $agentType);
try {
// Load class
ClassLoader::load($className);
// Validate class
$parentAgentClassName = ClassLoader::concatClassNames($agentType, 'agent');
$parentAgentClassName = "\\nre\\agents\\$parentAgentClassName";
ClassLoader::check($className, $parentAgentClassName);
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \nre\exceptions\AgentNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \nre\exceptions\AgentNotFoundException($e->getClassName());
}
}
/**
* Instantiate an Agent (Factory Pattern).
*
* @static
* @throws DatamodelException
* @throws DriverNotValidException
* @throws DriverNotFoundException
* @throws ViewNotFoundException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ControllerNotValidException
* @throws ControllerNotFoundException
* @param string $agentName Name of the Agent to instantiate
* @param Request $request Current request
* @param Response $respone Current respone
* @param Logger $log Log-system
*/
public static function factory($agentName, Request $request, Response $response, Logger $log=null)
{
// Determine full classname
$agentType = self::getAgentType();
$className = self::getClassName($agentName, $agentType);
// Construct and return Agent
return new $className($request, $response, $log);
}
/**
* Determine the type of an Agent.
*
* @static
* @return string Agent type
*/
private static function getAgentType()
{
return strtolower(ClassLoader::getClassName(get_called_class()));
}
/**
* 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";
}
/**
* Construct a new Agent.
*
* @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(Request $request, Response $response, Logger $log=null)
{
// Store values
$this->request = $request;
$this->response = $response;
$this->log = $log;
// Construct SubAgent
$this->actionConstruct();
// Load corresponding Controller
$this->loadController();
}
/**
* Run the Controller of this Agent and its SubAgents.
*
* @throws ParamsNotValidException
* @throws IdNotFoundException
* @throws DatamodelException
* @throws ActionNotFoundException
* @param Request $request Current request
* @param Response $response Current response
* @return Exception Last occurred exception of SubAgents
*/
public function run(Request $request, Response $response)
{
// Check Controller
if(!is_null($this->controller))
{
// Call prefilter
$this->controller->preFilter($request, $response);
// Run controller
$this->controller->run($request, $response);
// Call postfilter
$this->controller->postFilter($request, $response);
}
// Run SubAgents
$exception = null;
foreach($this->subAgents as &$subAgent)
{
try {
$subAgent['object']->run(
$request,
$subAgent['response']
);
}
catch(ParamsNotValidException $e) {
$subAgent = $this->errorInline($subAgent, $request, $e);
}
catch(IdNotFoundException $e) {
$subAgent = $this->errorInline($subAgent, $request, $e);
}
catch(DatamodelException $e) {
$exception = $e;
$subAgent = $this->errorInline($subAgent, $request, $e);
}
catch(ActionNotFoundException $e) {
$subAgent = $this->errorInline($subAgent, $request, $e);
}
}
// Return last occurred exception
return $exception;
}
/**
* 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())
{
// Check Controller
if(!is_null($this->controller))
{
// Render SubAgents
foreach($this->subAgents as $subAgent)
{
$label = array_key_exists('label', $subAgent) ? $subAgent['label'] : $subAgent['name'];
$data[$label] = $this->renderSubAgent($subAgent);
}
// Render the Controller of this agent
return $this->controller->render($data);
}
}
/**
* Construct SubAgents (per Action).
*/
protected function actionConstruct()
{
// Action ermitteln
$action = $this->response->getParam(2);
if(is_null($action)) {
$action = $this->request->getParam(2, 'action');
$this->response->addParam($action);
}
// Initialisierungsmethode für diese Action ausführen
if(method_exists($this, $action))
{
call_user_func_array(
array(
$this,
$action
),
array(
$this->request,
$this->response
)
);
}
}
/**
* Load the Controller of this Agent.
*
* @throws DatamodelException
* @throws DriverNotValidException
* @throws DriverNotFoundException
* @throws ViewNotFoundException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ControllerNotValidException
* @throws ControllerNotFoundException
*/
protected function loadController()
{
// Determine Controller name
$controllerName = 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
Controller::load($controllerName);
// Construct Controller
$this->controller = Controller::factory($controllerName, $toplevelAgentName, $action, $this);
}
/**
* Log an error.
*
* @param Exception $exception Occurred exception
* @param int $logMode Log mode
*/
protected function log($exception, $logMode)
{
if(is_null($this->log)) {
return;
}
$this->log->log(
$exception->getMessage(),
$logMode
);
}
/**
* Load a SubAgent and add it.
*
* @throws ServiceUnavailableException
* @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(DatamodelException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
}
/**
* Load a SubAgent and add it.
*
* @throws ServiceUnavailableException
* @throws DatamodelException
* @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 {
// Load Agent
\nre\agents\BottomlevelAgent::load($agentName);
// Construct Agent
$this->subAgents[] = call_user_func_array(
array(
$this,
'newSubAgent'
),
func_get_args()
);
}
catch(ViewNotFoundException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(DriverNotValidException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(DriverNotFoundException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(ModelNotValidException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(ModelNotFoundException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(ControllerNotValidException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(ControllerNotFoundException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(AgentNotValidException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
catch(AgentNotFoundException $e) {
$this->subAgents[] = $this->newInlineError($agentName, $e);
}
}
/**
* Create a new SubAgent.
*
* @throws DatamodelException
* @param string $agentName Agent name
* @return array SubAgent
*/
private function newSubAgent($agentName)
{
// Response
$response = clone $this->response;
$response->clearParams(1);
$params = func_get_args();
if(count($params) < 2 || empty($params[1])) {
$params[1] = \nre\configs\CoreConfig::$defaults['action'];
}
call_user_func_array(
array(
$response,
'addParams'
),
$params
);
return array(
'name' => strtolower($agentName),
'response' => $response,
'object' => \nre\agents\BottomlevelAgent::factory(
$agentName,
$this->request,
$response,
$this->log
)
);
}
/**
* Render a SubAgent.
*
* @param array $subAgent SubAgent to render
* @return string Generated output
*/
private function renderSubAgent(&$subAgent)
{
// Check for InlineError
if(array_key_exists('inlineerror', $subAgent) && !empty($subAgent['inlineerror'])) {
return file_get_contents($subAgent['inlineerror']);
}
// Rendern SubAgent and return its output
return $subAgent['object']->render();
}
/**
* Handle the exception of a SubAgent.
*
* @param string $label Name of the original Agent
* @param Excepiton $exception Occurred exception
* @return array InlineError-SubAgent
*/
private function errorInline($subAgent, $request, $exception)
{
// Create the SubAgent for the exception
$subAgent = $this->newInlineError($subAgent['name'], $exception);
// Run the InlineError-SubAgent
try {
$subAgent['object']->run(
$request,
$subAgent['response']
);
}
catch(ActionNotFoundException $e) {
$this->log($e, Logger::LOGMODE_AUTO);
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
// Return the InlineError-SubAgent
return $subAgent;
}
/**
* Create a new InlineError.
*
* @param string $label Name of the original Agent
* @param Exception $exception Occurred exception
*/
private function newInlineError($label, $exception)
{
// Log error
$this->log($exception, Logger::LOGMODE_AUTO);
// Determine Agent name
$agentName = self::INLINEERROR_AGENT;
// Create SugAgent
$subAgent = array();
try {
// Load Agenten
\nre\agents\BottomlevelAgent::load($agentName);
// Construct Agent
$subAgent = $this->newSubAgent($agentName);
$subAgent['label'] = $label;
$subAgent['response']->addParam($exception);
}
catch(ViewNotFoundException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(DatamodelException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(DriverNotValidException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(DriverNotFoundException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(ModelNotValidException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(ModelNotFoundException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(ControllerNotValidException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(ControllerNotFoundException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(AgentNotValidException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
catch(AgentNotFoundException $e) {
$subAgent['inlineerror'] = $this->newInlineErrorService();
}
// Return SubAgent
return $subAgent;
}
/**
* Handle a hardcore error that could not be handled by the
* system.
*/
private function newInlineErrorService()
{
// Read and return static error file
return ROOT.DS.\nre\configs\CoreConfig::getClassDir('views').DS.\nre\configs\CoreConfig::$defaults['inlineErrorFile'].\nre\configs\Config::getFileExt('views');
}
}
?>

163
core/Api.inc Normal file
View file

@ -0,0 +1,163 @@
<?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\core;
/**
* Abstract class to implement an API.
*
* The API is the center of each application and specifies how and what
* to run and render.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class Api
{
/**
* Die aktuelle Anfrage
*
* @var Request
*/
protected $request;
/**
* Der Toplevelagent
*
* @var ToplevelAgent
*/
private $toplevelAgent = null;
/**
* Die aktuelle Antwort
*
* @var Response
*/
protected $response;
/**
* Log-System
*
* @var Logger
*/
protected $log;
/**
* Construct a new API.
*
* @param Request $request Current request
* @param Response $respone Current response
*/
public function __construct(Request $request, Response $response)
{
// Store request
$this->request = $request;
// Store response
$this->response = $response;
// Init logging
$this->log = new \nre\core\Logger();
}
/**
* Run the application.
*
* @throws DatamodelException
* @throws DriverNotValidException
* @throws DriverNotFoundException
* @throws ViewNotFoundException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ControllerNotValidException
* @throws ControllerNotFoundException
* @throws AgentNotValidException
* @throws AgentNotFoundException
* @return Exception Last occurred exception of an subagent
*/
public function run()
{
// Load ToplevelAgent
$this->loadToplevelAgent();
// Run ToplevelAgent
return $this->toplevelAgent->run($this->request, $this->response);
}
/**
* Render the output.
*/
public function render()
{
// Check exit-status
if($this->response->getExit()) {
return;
}
// Render ToplevelAgent
$this->response->setOutput($this->toplevelAgent->render());
}
/**
* Log an exception
*
* @param Exception $exception Occurred exception
* @param int $logMode Log-mode
*/
protected function log($exception, $logMode)
{
$this->log->log(
$exception->getMessage(),
$logMode
);
}
/**
* Load the ToplevelAgent specified by the request.
*
* @throws ServiceUnavailableException
* @throws AgentNotValidException
* @throws AgentNotFoundException
*/
private function loadToplevelAgent()
{
// Determine agent
$agentName = $this->response->getParam(0);
if(is_null($agentName)) {
$agentName = $this->request->getParam(0, 'toplevel');
$this->response->addParam($agentName);
}
// Load agent
\nre\agents\ToplevelAgent::load($agentName);
// Construct agent
$this->toplevelAgent = \nre\agents\ToplevelAgent::factory(
$agentName,
$this->request,
$this->response,
$this->log
);
}
}
?>

98
core/Autoloader.inc Normal file
View file

@ -0,0 +1,98 @@
<?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\core;
/**
* Autoloader.
*
* This class tries to load not yet used classes.
*
* @author coderkun <olli@coderkun.de>
*/
class Autoloader
{
/**
* Private construct().
*/
private function __construct() {}
/**
* Private clone().
*/
private function __clone() {}
/**
* Register load-method.
*/
public static function register()
{
spl_autoload_register(
array(
get_class(),
'load'
)
);
}
/**
* Look for the given class and try to load it.
*
* @param string $fullClassName Die zu ladende Klasse
*/
public static function load($fullClassName)
{
$fullClassNameA = explode('\\', $fullClassName);
if(strpos($fullClassName, \nre\configs\CoreConfig::$core['namespace']) !== 0)
{
// App
$className = array_slice($fullClassNameA, substr_count(\nre\configs\AppConfig::$app['namespace'], '\\'));
array_unshift($className, \nre\configs\CoreConfig::getClassDir('app'));
$filename = ROOT.DS.implode(DS, $className).\nre\configs\CoreConfig::getFileExt('includes');
if(file_exists($filename)) {
require_once($filename);
}
}
else
{
// Core
$className = array_slice($fullClassNameA, substr_count(\nre\configs\CoreConfig::$core['namespace'], '\\'));
$filename = ROOT.DS.implode(DS, $className).\nre\configs\CoreConfig::getFileExt('includes');
if(file_exists($filename)) {
require_once($filename);
}
}
}
/**
* Determine classtype of a class.
*
* @param string $className Name of the class to determine the classtype of
* @return string Classtype of the given class
*/
public static function getClassType($className)
{
// CamelCase
return strtolower(preg_replace('/^.*([A-Z][^A-Z]+)$/', '$1', $className));
}
}
?>

129
core/ClassLoader.inc Normal file
View file

@ -0,0 +1,129 @@
<?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\core;
/**
* Class for safely loading classes.
*
* @author coderkun <olli@coderkun.de>
*/
class ClassLoader
{
/**
* Load a class.
*
* @throws ClassNotFoundException
* @param string $className Name of the class to load
*/
public static function load($fullClassName)
{
// Determine folder to look in
$className = explode('\\', $fullClassName);
$className = array_slice($className, substr_count(\nre\configs\AppConfig::$app['namespace'], '\\'));
// Determine filename
$fileName = ROOT.DS.implode(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 a class.
*
* @throws ClassNotValidException
* @param string $className Name of the class to check
* @param string $parentClassName Name of the parent class
*/
public static function check($className, $parentClassName)
{
// Check if class is subclass of parent class
if(!is_subclass_of($className, $parentClassName)) {
throw new \nre\exceptions\ClassNotValidException(
$className
);
}
}
/**
* Strip the namespace from a class name.
*
* @param string $class Name of a class including its namespace
* @return Name of the given class without its namespace
*/
public static function stripNamespace($class)
{
return array_slice(explode('\\', $class), -1)[0];
}
/**
* Strip the class type from a class name.
*
* @param string $className Name of a class
* @return Name of the given class without its class type
*/
public static function stripClassType($className)
{
return preg_replace('/^(.*)[A-Z][^A-Z]+$/', '$1', $className);
}
/**
* Strip the namespace and the class type of a full class name
* to get only its name.
*
* @param string $class Full name of a class
* @return Only the name of the given class
*/
public static function getClassName($class)
{
return self::stripClassType(self::stripNamespace($class));
}
/**
* Concatenate strings to a class name following the CamelCase
* pattern.
*
* @param string $className1 Arbitrary number of strings to concat
* @return string Class name as CamelCase
*/
public static function concatClassNames($className1)
{
return implode('', array_map(
function($arg) {
return ucfirst(strtolower($arg));
},
func_get_args()
));
}
}
?>

85
core/Component.inc Normal file
View file

@ -0,0 +1,85 @@
<?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\core;
/**
* Abstract class to implement a (Controller) Component.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class Component
{
/**
* Load the class of a Component.
*
* @throws ComponentNotFoundException
* @throws ComponentNotValidException
* @param string $componentName Name of the Component to load
*/
public static function load($componentName)
{
// Determine full classname
$className = self::getClassName($componentName);
try {
// Load class
ClassLoader::load($className);
// Validate class
ClassLoader::check($className, get_class());
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \nre\exceptions\ComponentNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \nre\exceptions\ComponentNotFoundException($e->getClassName());
}
}
/**
* Instantiate a Component (Factory Pattern).
*
* @param string $componentName Name of the Component to instantiate
*/
public static function factory($componentName)
{
// Determine full classname
$className = self::getClassName($componentName);
// Construct and return Controller
return new $className();
}
/**
* Determine the classname for the given Component name.
*
* @param string $componentName Component name to get classname of
* @return string Classname for the Component name
*/
private static function getClassName($componentName)
{
$className = \nre\core\ClassLoader::concatClassNames($componentName, \nre\core\ClassLoader::stripNamespace(get_class()));
return \nre\configs\AppConfig::$app['namespace']."controllers\\components\\$className";
}
}
?>

49
core/Config.inc Normal file
View file

@ -0,0 +1,49 @@
<?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\core;
/**
* Configuration.
*
* This class does not hold any configuration value but helps to
* determine values that can be hold by AppConfig or CoreConfig.
*
* @author coderkun <olli@coderkun.de>
*/
final class Config
{
/**
* Get a default value.
*
* @param string $index Index of value to get
*/
public static function getDefault($index)
{
if(array_key_exists($index, \nre\configs\AppConfig::$defaults)) {
return \nre\configs\AppConfig::$defaults[$index];
}
if(array_key_exists($index, \nre\configs\CoreConfig::$defaults)) {
return \nre\configs\CoreConfig::$defaults[$index];
}
return null;
}
}
?>

433
core/Controller.inc Normal file
View file

@ -0,0 +1,433 @@
<?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\core;
/**
* Abstract class for implementing a Controller.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class Controller
{
/**
* Corresponding Agent
*
* @var Agent
*/
protected $agent;
/**
* View of the Controller
*
* @var View
*/
protected $view = null;
/**
* Data to pass to the View
*
* @var array
*/
protected $viewData = array();
/**
* Current request
*
* @var Request
*/
protected $request = null;
/**
* Current response
*
* @var Response
*/
protected $response = null;
/**
* Load the class of a Controller.
*
* @throws ControllerNotFoundException
* @throws ControllerNotValidException
* @param string $controllerName Name of the Controller to load
*/
public static function load($controllerName)
{
// Determine full classname
$className = self::getClassName($controllerName);
try {
// Load class
ClassLoader::load($className);
// Validate class
ClassLoader::check($className, get_class());
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \nre\exceptions\ControllerNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \nre\exceptions\ControllerNotFoundException($e->getClassName());
}
}
/**
* Instantiate a Controller (Factory Pattern).
*
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
* @throws ViewNotFoundException
* @param string $controllerName Name of the Controller 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 classname for the given Controller name.
*
* @param string $controllerName Controller name to get classname of
* @return string Classname for the Controller name
*/
private static function getClassName($controllerName)
{
$className = \nre\core\ClassLoader::concatClassNames($controllerName, \nre\core\ClassLoader::stripNamespace(get_class()));
return \nre\configs\AppConfig::$app['namespace']."controllers\\$className";
}
/**
* Construct a new 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
*/
protected function __construct($layoutName, $action, $agent)
{
// Store values
$this->agent = $agent;
// Load Components
$this->loadComponents();
// Load Models
$this->loadModels();
// Load View
$this->loadView($layoutName, $action);
}
/**
* Prefilter that is executed before running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function preFilter(Request $request, Response $response)
{
// Request speichern
$this->request = $request;
// Response speichern
$this->response = $response;
// Linker erstellen
$this->set('linker', new \nre\core\Linker($request));
}
/**
* Prefilter that is executed after running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
*/
public function postFilter(Request $request, Response $response)
{
}
/**
* Run the Controller.
*
* This method executes the Action of the Controller defined by
* the current Request.
*
* @throws ParamsNotValidException
* @throws IdNotFoundException
* @throws DatamodelException
* @throws ActionNotFoundException
* @param Request $request Current request
* @param Response $response Current response
*/
public function run(Request $request, Response $response)
{
// Determine Action
$action = $response->getParam(2, 'action');
if(!method_exists($this, $action)) {
throw new \nre\exceptions\ActionNotFoundException($action);
}
// Determine parameters
$params = $response->getParams(3);
if(empty($params)) {
$params = $request->getParams(3);
}
// Fill missing parameters
$rc = new \ReflectionClass($this);
$nullParamsCount = $rc->getMethod($action)->getNumberOfParameters() - count($params);
$nullParams = ($nullParamsCount > 0 ? array_fill(0, $nullParamsCount, NULL) : array());
// Call Action
call_user_func_array(
array(
$this,
$action
),
array_merge(
$params,
$nullParams
)
);
}
/**
* Generate the output.
*
* @param array $viewData Data to pass to the View
* @return string Generated output
*/
public function render($viewData=null)
{
// Combine given data and data of this Controller
$data = $this->viewData;
if(!is_null($viewData)) {
$data = array_merge($viewData, $data);
}
// Rendern and return output
return $this->view->render($data);
}
/**
* Set data for the View.
*
* @param string $name Key
* @param mixed $data Value
*/
protected function set($name, $data)
{
$this->viewData[$name] = $data;
}
/**
* Redirect to the given URL.
*
* @param string $url Relative URL
*/
protected function redirect($url)
{
$url = 'http://'.$_SERVER['HTTP_HOST'].$url;
header('Location: '.$url);
exit;
}
/**
* Check if Models of this Controller are loaded and available.
*
* @param string $modelName Arbitrary number of Models to check
* @return bool All given Models are loaded and available
*/
protected function checkModels($modelName)
{
foreach(func_get_args() as $modelName)
{
if(!isset($this->$modelName) || !is_subclass_of($this->$modelName, 'Model')) {
return false;
}
}
return true;
}
/**
* Get the View of the Controller
*
* @return View View of the Controller
*/
protected function getView()
{
return $this->view;
}
/**
* Load the Components of this Controller.
*
* @throws ComponentNotValidException
* @throws ComponentNotFoundException
*/
private function loadComponents()
{
// Determine components
$components = array();
if(property_exists($this, 'components')) {
$components = $this->components;
}
if(!is_array($components)) {
$components = array($components);
}
// Components of parent classes
$parent = $this;
while($parent = get_parent_class($parent))
{
$properties = get_class_vars($parent);
if(array_key_exists('components', $properties)) {
$components = array_merge($components, $properties['components']);
}
}
// Load components
foreach($components as &$component)
{
// Load class
Component::load($component);
// Construct component
$componentName = ucfirst(strtolower($component));
$this->$componentName = Component::factory($component);
}
}
/**
* Load the Models of this Controller.
*
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
*/
protected function loadModels()
{
// Determine Models
$explicit = false;
$models = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class($this)));
if(property_exists($this, 'models'))
{
$models = $this->models;
$explicit = true;
}
if(!is_array($models)) {
$models = array($models);
}
// Models of parent classes
$parent = $this;
while($parent = get_parent_class($parent))
{
$properties = get_class_vars($parent);
if(array_key_exists('models', $properties)) {
$models = array_merge($models, $properties['models']);
}
}
// Load Models
foreach($models as &$model)
{
try {
// Load class
Model::load($model);
// Construct Model
$modelName = ucfirst(strtolower($model));
$this->$modelName = Model::factory($model);
}
catch(\nre\exceptions\ModelNotValidException $e) {
if($explicit) {
throw $e;
}
}
catch(\nre\exceptions\ModelNotFoundException $e) {
if($explicit) {
throw $e;
}
}
}
}
/**
* Load the View of this Controller.
*
* @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::getClassName(get_class($this));
// Load view
$isToplevel = is_subclass_of($this->agent, '\nre\agents\ToplevelAgent');
$this->view = View::loadAndFactory($layoutName, $controllerName, $action, $isToplevel);
}
}
?>

96
core/Driver.inc Normal file
View file

@ -0,0 +1,96 @@
<?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\core;
/**
* Abstract class for implementing a Driver.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class Driver
{
/**
* Load the class of a Driver.
*
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @param string $driverName Name of the Driver to load
*/
public static function load($driverName)
{
// Determine full classname
$className = self::getClassName($driverName);
try {
// Load class
ClassLoader::load($className);
// Validate class
ClassLoader::check($className, get_class());
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \nre\exceptions\DriverNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \nre\exceptions\DriverNotFoundException($e->getClassName());
}
}
/**
* Instantiate a Driver (Factory Pattern).
*
* @param string $driverName Name of the Driver to instantiate
*/
public static function factory($driverName, $config)
{
// Determine full classname
$className = self::getClassName($driverName);
// Construct and return Driver
return $className::singleton($config);
}
/**
* Determine the classname for the given Driver name.
*
* @param string $driverName Driver name to get classname of
* @return string Classname fore the Driver name
*/
private static function getClassName($driverName)
{
$className = ClassLoader::concatClassNames($driverName, ClassLoader::stripNamespace(get_class()));
return "\\nre\\drivers\\$className";
}
/**
* Construct a new Driver.
*/
protected function __construct()
{
}
}
?>

65
core/Exception.inc Normal file
View file

@ -0,0 +1,65 @@
<?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\core;
/**
* Exception class.
*
* @author coderkun <olli@coderkun.de>
*/
class Exception extends \Exception
{
/**
* Construct a new exception.
*
* @param string $message Error message
* @param int $code Error code
* @param string $name Name to insert
*/
function __construct($message, $code, $name=null)
{
parent::__construct(
$this->concat(
$message,
$name
),
$code
);
}
/**
* Insert the name in a message
*
* @param string $message Error message
* @param string $name Name to insert
*/
private function concat($message, $name)
{
if(is_null($name)) {
return $message;
}
return "$message: $name";
}
}
?>

311
core/Linker.inc Normal file
View file

@ -0,0 +1,311 @@
<?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\core;
/**
* Class to create web links based on the current request.
*
* @author coderkun <olli@coderkun.de>
*/
class Linker
{
/**
* Current request
*
* @var Request
*/
private $request;
/**
* Construct a new linker.
*
* @param Request $request Current request
*/
function __construct(\nre\requests\WebRequest $request)
{
$this->request = $request;
}
/**
* Mask parameters to be used in an URL.
*
* @param string $param1 First parameter
* @return string Masked parameters as string
*/
public static function createLinkParam($param1)
{
return implode(
\nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
call_user_func_array(
'\nre\core\Linker::createLinkParams',
func_get_args()
)
);
}
/**
* Mask parameters to be used in an URL.
*
* @param string $param1 First parameter
* @return string Masked parameters as array
*/
public static function createLinkParams($param1)
{
// Parameters
$linkParams = array();
$params = func_get_args();
foreach($params as $param)
{
// Delete critical signs
$specials = array('/', '?', '&');
foreach($specials as &$special) {
$param = str_replace($special, '', $param);
}
// Process parameter
$param = str_replace(
' ',
\nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
substr(
$param,
0,
\nre\configs\CoreConfig::$classes['linker']['url']['length']
)
);
// Encode parameter
$linkParams[] = $param;
}
// Return link parameters
return $linkParams;
}
/**
* Create a web link.
*
* @param array $params Parameters to use
* @param int $offset Ignore first parameters
* @param bool $exclusiveParams Use only the given parameters
* @param array $getParams GET-parameter to use
* @param bool $exclusiveGetParams Use only the given GET-parameters
* @param string $anchor Target anchor
* @param bool $absolute Include hostname etc. for an absolute URL
* @return string Created link
*/
public function link($params=null, $offset=0, $exclusiveParams=true, $getParams=null, $exclusiveGetParams=true, $anchor=null, $absolute=false)
{
// Make current request to response
$response = new \nre\responses\WebResponse();
// Check parameters
if(is_null($params)) {
$params = array();
}
elseif(!is_array($params)) {
$params = array($params);
}
// Set parameters from request
$reqParams = array_slice($this->request->getParams(), 1, $offset);
if(count($reqParams) < $offset && $offset > 0) {
$reqParams[] = $this->request->getParam(1, 'intermediate');
}
if(count($reqParams) < $offset && $offset > 1) {
$reqParams[] = $this->request->getParam(2, 'action');
}
$params = array_map('rawurlencode', $params);
$params = array_merge($reqParams, $params);
// Use Layout
$layout = \nre\configs\AppConfig::$defaults['toplevel'];
if(!empty($getParams) && array_key_exists('layout', $getParams)) {
$layout = $getParams['layout'];
}
array_unshift($params, $layout);
// Use parameters from request only
if(!$exclusiveParams)
{
$params = array_merge(
$params,
array_slice(
$this->request->getParams(),
count($params)
)
);
}
// Set parameters
call_user_func_array(
array(
$response,
'addParams'
),
$params
);
// Check GET-parameters
if(is_null($getParams)) {
$getParams = array();
}
elseif(!is_array($params)) {
$params = array($params);
}
if(!$exclusiveGetParams)
{
$getParams = array_merge(
$this->request->getGetParams(),
$getParams
);
}
// Set GET-parameters
$response->addGetParams($getParams);
// Create and return link
return self::createLink($this->request, $response, $anchor, $absolute);
}
/**
* Create a link from an URL.
*
* @param string $url URL to create link from
* @param bool $absolute Create absolute URL
* @return string Created link
*/
public function hardlink($url, $absolute=false)
{
return $this->createUrl($url, $this->request, $absolute);
}
/**
* Create a link.
*
* @param Request $request Current request
* @param Response $response Current response
* @param bool $absolute Create absolute link
* @param string $anchor Anchor on target
* @return string Created link
*/
private static function createLink(Request $request, Response $response, $anchor=null, $absolute=false)
{
// Check response
if(is_null($response)) {
return null;
}
// Get parameters
$params = $response->getParams(1);
// Check Action
if(count($params) == 2 && $params[1] == \nre\configs\CoreConfig::$defaults['action']) {
array_pop($params);
}
// Set parameters
$link = implode('/', $params);
// Apply reverse-routes
$link = $request->applyReverseRoutes($link);
// Get GET-parameters
$getParams = $response->getGetParams();
// Layout überprüfen
if(array_key_exists('layout', $getParams) && $getParams['layout'] == \nre\configs\AppConfig::$defaults['toplevel']) {
unset($getParams['layout']);
}
// Set GET-parameters
if(array_key_exists('url', $getParams)) {
unset($getParams['url']);
}
if(count($getParams) > 0) {
$link .= '?'.http_build_query($getParams);
}
// Add anchor
if(!is_null($anchor)) {
$link .= "#$anchor";
}
// Create URL
$url = self::createUrl($link, $request, $absolute);
return $url;
}
/**
* Adapt a link to the environment.
*
* @param string $url URL
* @param Request $request Current request
* @param bool $absolute Create absolute URL
* @return string Adapted URL
*/
private static function createUrl($url, Request $request, $absolute=false)
{
// Variables
$server = $_SERVER['SERVER_NAME'];
$uri = $_SERVER['REQUEST_URI'];
$prefix = '';
// Determine prefix
$ppos = array(strlen($uri));
if(($p = strpos($uri, '/'.$request->getParam(1, 'intermediate'))) !== false) {
$ppos[] = $p;
}
$prefix = substr($uri, 0, min($ppos));
// Create absolute URL
if($absolute) {
$prefix = "http://$server/".trim($prefix, '/');
}
// Put URL together
$url = rtrim($prefix, '/').'/'.ltrim($url, '/');
// Return URL
return $url;
}
}
?>

132
core/Logger.inc Normal file
View file

@ -0,0 +1,132 @@
<?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\core;
/**
* Class to log messages to different targets.
*
* @author coderkun <olli@coderkun.de>
*/
class Logger
{
/**
* Log mode: Detect automatic
*
* @var int
*/
const LOGMODE_AUTO = 0;
/**
* Log mode: Print to screen
*
* @var int
*/
const LOGMODE_SCREEN = 1;
/**
* Log mode: Use PHP-logging mechanism
*
* @var int
*/
const LOGMODE_PHP = 2;
/**
* Do not auto-log to screen
*
* @var boolean
*/
private $autoLogToScreenDisabled = false;
/**
* Construct a new logger.
*/
public function __construct()
{
}
/**
* Log a message.
*
* @param string $message Message to log
* @param int $logMode Log mode to use
*/
public function log($message, $logMode=self::LOGMODE_SCREEN)
{
// Choose log mode automatically
if($logMode == self::LOGMODE_AUTO) {
$logMode = $this->getAutoLogMode();
}
// Print message to screen
if($logMode & self::LOGMODE_SCREEN) {
$this->logToScreen($message);
}
// Use PHP-logging mechanism
if($logMode & self::LOGMODE_PHP) {
$this->logToPhp($message);
}
}
/**
* Disable logging to screen when the log mode is automatically
* detected.
*/
public function disableAutoLogToScreen()
{
$this->autoLogToScreenDisabled = true;
}
/**
* Print a message to screen.
*
* @param string $message Message to print
*/
private function logToScreen($message)
{
echo "$message<br>\n";
}
/**
* Log a message by using PHP-logging mechanism.
*
* @param string $message Message to log
*/
private function logToPhp($message)
{
error_log($message, 0);
}
/**
* Detect log mode automatically by distinguishing between
* production and test environment.
*
* @return int Automatically detected log mode
*/
private function getAutoLogMode()
{
return ($_SERVER['SERVER_ADDR'] == '127.0.0.1' && !$this->autoLogToScreenDisabled) ? self::LOGMODE_SCREEN : self::LOGMODE_PHP;
}
}
?>

141
core/Model.inc Normal file
View file

@ -0,0 +1,141 @@
<?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\core;
/**
* Abstract class for implementing a Model.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class Model
{
/**
* Load the class of a Model.
*
* @throws ModelNotFoundException
* @throws ModelNotValidException
* @param string $modelName Name of the Model to load
*/
public static function load($modelName)
{
// Determine full classname
$className = self::getClassName($modelName);
try {
// Load class
ClassLoader::load($className);
// Validate class
ClassLoader::check($className, get_class());
}
catch(\nre\exceptions\ClassNotValidException $e) {
throw new \nre\exceptions\ModelNotValidException($e->getClassName());
}
catch(\nre\exceptions\ClassNotFoundException $e) {
throw new \nre\exceptions\ModelNotFoundException($e->getClassName());
}
}
/**
* Instantiate a Model (Factory Pattern).
*
* @param string $modelName Name of the Model to instantiate
*/
public static function factory($modelName)
{
// Determine full classname
$className = self::getClassName($modelName);
// Construct and return Model
return new $className();
}
/**
* Determine the classname for the given Model name.
*
* @param string $modelName Model name to get classname of
* @return string Classname fore the Model name
*/
private static function getClassName($modelName)
{
$className = ClassLoader::concatClassNames($modelName, ClassLoader::stripNamespace(get_class()));
return \nre\configs\AppConfig::$app['namespace']."models\\$className";
}
/**
* Construct a new Model.
*
* TODO Catch exception
*
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
*/
protected function __construct()
{
// Load Models
$this->loadModels();
}
/**
* Load the Models of this Model.
*
* @throws DatamodelException
* @throws DriverNotFoundException
* @throws DriverNotValidException
* @throws ModelNotValidException
* @throws ModelNotFoundException
*/
private function loadModels()
{
// Determine Models
$models = array();
if(property_exists($this, 'models')) {
$models = $this->models;
}
if(!is_array($models)) {
$models = array($models);
}
// Load Models
foreach($models as $model)
{
// Load class
Model::load($model);
// Construct Model
$modelName = ucfirst(strtolower($model));
$this->$modelName = Model::factory($model);
}
}
}
?>

64
core/Request.inc Normal file
View file

@ -0,0 +1,64 @@
<?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\core;
/**
* Base class to represent a request.
*
* @author coderkun <olli@coderkun.de>
*/
class Request
{
/**
* Passed parameters
*
* @var array
*/
protected $params = array();
/**
* Get a parameter.
*
* @param int $index Index of parameter
* @param string $defaultIndex Index of default configuration value for this parameter
* @return string Value of parameter
*/
public function getParam($index, $defaultIndex=null)
{
// Return parameter
if(count($this->params) > $index) {
return $this->params[$index];
}
// Return default value
return \nre\core\Config::getDefault($defaultIndex);
}
/**
* Get all parameters from index on.
*
* @param int $offset Offset-index
* @return array Parameter values
*/
public function getParams($offset=0)
{
return array_slice($this->params, $offset);
}
}
?>

158
core/Response.inc Normal file
View file

@ -0,0 +1,158 @@
<?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\core;
/**
* Base class to represent a response.
*
* @author coderkun <olli@coderkun.de>
*/
class Response
{
/**
* Applied parameters
*
* @var array
*/
protected $params = array();
/**
* Generated output
*
* @var string
*/
private $output = '';
/**
* Abort futher execution
*
* @var bool
*/
private $exit = false;
/**
* Add a parameter.
*
* @param mixed $value Value of parameter
*/
public function addParam($value)
{
$this->params[] = $value;
}
/**
* Add multiple parameters.
*
* @param mixed $value1 Value of first parameter
* @param mixed Values of further parameters
*/
public function addParams($value1)
{
$this->params = array_merge(
$this->params,
func_get_args()
);
}
/**
* Delete all stored parameters (from offset on).
*
* @param int $offset Offset-index
*/
public function clearParams($offset=0)
{
$this->params = array_slice($this->params, 0, $offset);
}
/**
* Get a parameter.
*
* @param int $index Index of parameter
* @param string $defaultIndex Index of default configuration value for this parameter
* @return string Value of parameter
*/
public function getParam($index, $defaultIndex=null)
{
// Return parameter
if(count($this->params) > $index) {
return $this->params[$index];
}
// Return default value
return \nre\core\Config::getDefault($defaultIndex);
}
/**
* Get all parameters from index on.
*
* @param int $offset Offset-index
* @return array Parameter values
*/
public function getParams($offset=0)
{
return array_slice($this->params, $offset);
}
/**
* Set output.
*
* @param string $output Generated output
*/
public function setOutput($output)
{
$this->output = $output;
}
/**
* Get generated output.
*
* @return string Generated output
*/
public function getOutput()
{
return $this->output;
}
/**
* Set exit-state.
*
* @param bool $exit Abort further execution
*/
public function setExit($exit=true)
{
$this->exit = $exit;
}
/**
* Get exit-state.
*
* @return bool Abort further execution
*/
public function getExit()
{
return $this->exit;
}
}
?>

124
core/View.inc Normal file
View file

@ -0,0 +1,124 @@
<?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\core;
/**
* View.
*
* Class to encapsulate a template file and to provide rendering methods.
*
* @author coderkun <olli@coderkun.de>
*/
class View
{
/**
* Template filename
*
* @var string
*/
protected $templateFilename;
/**
* Load and instantiate the View of an Agent.
*
* @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 View($layoutName, $agentName, $action, $isToplevel);
}
/**
* Construct a new View.
*
* @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\CoreConfig::getClassDir('views').DS. strtolower($layoutName).DS;
// AgentName and Action
if(strtolower($agentName) != $layoutName || !$isToplevel) {
$fileName .= strtolower($agentName).DS.strtolower($action);
}
else {
$fileName .= strtolower($layoutName);
}
// 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;
}
/**
* Generate output
*
* @param array $data Data to have available in the template file
*/
public function render($data)
{
// Extract data
if(!is_null($data)) {
extract($data, EXTR_SKIP);
}
// Buffer output
ob_start();
// Include template
include($this->templateFilename);
// Return buffered output
return ob_get_clean();
}
/**
* Get template filename.
*
* @return string Template filename
*/
public function getTemplateFilename()
{
return $this->templateFilename;
}
}
?>

75
core/WebUtils.inc Normal file
View file

@ -0,0 +1,75 @@
<?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\core;
/**
* Class that holds several web-specific methods and properties.
*
* @author coderkun <olli@coderkun.de>
*/
class WebUtils
{
/**
* HTTP-statuscode 403: Forbidden
*
* @var int
*/
const HTTP_FORBIDDEN = 403;
/**
* HTTP-statuscode 404: Not Found
*
* @var int
*/
const HTTP_NOT_FOUND = 404;
/**
* HTTP-statuscode 503: Service Unavailable
*
* @var int
*/
const HTTP_SERVICE_UNAVAILABLE = 503;
/**
* HTTP-header strings
*
* @var array
*/
public static $httpStrings = array(
200 => 'OK',
304 => 'Not Modified',
403 => 'Forbidden',
404 => 'Not Found',
503 => 'Service Unavailable'
);
/**
* Get the HTTP-header of a HTTP-statuscode
*
* @param int $httpStatusCode HTTP-statuscode
* @return string HTTP-header of HTTP-statuscode
*/
public static function getHttpHeader($httpStatusCode)
{
if(!array_key_exists($httpStatusCode, self::$httpStrings)) {
$httpStatusCode = 200;
}
return sprintf("HTTP/1.1 %d %s\n", $httpStatusCode, self::$httpStrings[$httpStatusCode]);
}
}
?>

View file

@ -0,0 +1,87 @@
<?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\drivers;
/**
* Abstract class for implementing a database driver.
*
* @author coderkun <olli@coderkun.de>
*/
abstract class DatabaseDriver extends \nre\core\Driver
{
/**
* Driver class instance
*
* @static
* @var DatabaseDriver
*/
protected static $driver = null;
/**
* Connection resource
*
* @var resource
*/
protected $connection = null;
/**
* Singleton-pattern.
*
* @param array $config Database driver configuration
* @return DatabaseDriver Singleton-instance of database driver class
*/
public static function singleton($config)
{
// Singleton
if(self::$driver !== null) {
return self::$driver;
}
// Construct
$className = get_called_class();
self::$driver = new $className($config);
return self::$driver;
}
/**
* Construct a new database driver.
*
* @param array $config Connection and login settings
*/
protected function __construct($config)
{
parent::__construct();
// Establish connection
$this->connect($config);
}
/**
* Establish a connect to a MqSQL-database.
*
* @throws DatamodelException
* @param array $config Connection and login settings
*/
protected abstract function connect($config);
}
?>

169
drivers/MysqliDriver.inc Normal file
View file

@ -0,0 +1,169 @@
<?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\drivers;
/**
* Implementation of a database driver for MySQL-databases.
*
* @author coderkun <olli@coderkun.de>
*/
class MysqliDriver extends \nre\drivers\DatabaseDriver
{
/**
* Construct a MySQL-driver.
*
* @throws DatamodelException
* @param array $config Connection and login settings
*/
function __construct($config)
{
parent::__construct($config);
}
/**
* Execute a SQL-query.
*
* @throws DatamodelException
* @param string $query Query to run
* @param mixed Params
* @return array Result
*/
public function query($query)
{
// Prepare statement
if(!($stmt = $this->connection->prepare($query))) {
throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
}
try {
// Prepare data
$data = array();
// Bind parameters
$p = array_slice(func_get_args(), 1);
$params = array();
foreach($p as $key => $value) {
$params[$key] = &$p[$key];
}
if(count($params) > 0)
{
if(!(call_user_func_array(array($stmt, 'bind_param'), $params))) {
throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
}
}
// Execute query
if(!$stmt->execute()) {
throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
}
// Fetch result
if($result = $stmt->get_result()) {
while($row = $result->fetch_assoc()) {
$data[] = $row;
}
}
$stmt->close();
return $data;
}
catch(Exception $e) {
$stmt->close();
throw $e;
}
}
/**
* Return the last insert id (of the last insert-query).
*
* @return int Last insert id
*/
public function getInsertId()
{
return $this->connection->insert_id;
}
/**
* Enable/disable autocommit feature.
*
* @param boolean $autocommit Enable/disable autocommit
*/
public function setAutocommit($autocommit)
{
$this->connection->autocommit($autocommit);
}
/**
* Rollback the current transaction.
*/
public function rollback()
{
$this->connection->rollback();
}
/**
* Commit the current transaction.
*/
public function commit()
{
$this->connection->commit();
}
/**
* Establish a connect to a MqSQL-database.
*
* @throws DatamodelException
* @param array $config Connection and login settings
*/
protected function connect($config)
{
// Connect
$con = @new \mysqli(
$config['host'],
$config['user'],
$config['password'],
$config['db']
);
// Check connection
if($con->connect_error) {
throw new \nre\exceptions\DatamodelException($con->connect_error, $con->connect_errno);
}
// Set character encoding
if(!$con->set_charset('utf8')) {
throw new \nre\exceptions\DatamodelException($con->connect_error, $con->connect_errno);
}
// Save connection
$this->connection = $con;
}
}
?>

View file

@ -0,0 +1,51 @@
<?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\exceptions;
/**
* Exception: Access denied.
*
* @author coderkun <olli@coderkun.de>
*/
class AccessDeniedException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 85;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'access denied';
/**
* Consturct a new exception.
*/
function __construct()
{
parent::__construct(
self::MESSAGE,
self::CODE
);
}
}
?>

View file

@ -0,0 +1,77 @@
<?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\exceptions;
/**
* Exception: Action not found.
*
* @author coderkun <olli@coderkun.de>
*/
class ActionNotFoundException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 70;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'action not found';
/**
* Name of the action that was not found
*
* @var string
*/
private $action;
/**
* Construct a new exception.
*
* @param string $action Name of the action that was not found
*/
function __construct($action)
{
parent::__construct(
self::MESSAGE,
self::CODE,
$action
);
// Store values
$this->action = $action;
}
/**
* Get the name of the action that was not found.
*
* @return string Name of the action that was not found
*/
public function getAction()
{
return $this->action;
}
}
?>

View file

@ -0,0 +1,67 @@
<?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\exceptions;
/**
* Exception: Agent not found.
*
* @author coderkun <olli@coderkun.de>
*/
class AgentNotFoundException extends \nre\exceptions\ClassNotFoundException
{
/**
* Error code
*
* @var int
*/
const CODE = 66;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'agent not found';
/**
* Construct a new exception.
*
* @param string $agentName Name of the Agent that was not found
*/
function __construct($agentName)
{
parent::__construct(
$agentName,
self::MESSAGE,
self::CODE
);
}
/**
* Get the name of the Agent that was not found.
*
* @return string Name of the Agent that was not found
*/
public function getAgentName()
{
return $this->getClassName();
}
}
?>

View file

@ -0,0 +1,67 @@
<?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\exceptions;
/**
* Exception: Agent not valid.
*
* @author coderkun <olli@coderkun.de>
*/
class AgentNotValidException extends \nre\exceptions\ClassNotValidException
{
/**
* Error code
*
* @var int
*/
const CODE = 76;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'agent not valid';
/**
* Construct a new exception.
*
* @param string $agentName Name of the invalid Agent
*/
function __construct($agentName)
{
parent::__construct(
$agentName,
self::MESSAGE,
self::CODE
);
}
/**
* Get the name of the invalid Agent.
*
* @return string Name of the invalid Agent
*/
public function getAgentName()
{
return $this->getClassName();
}
}
?>

View file

@ -0,0 +1,77 @@
<?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\exceptions;
/**
* Exception: Class not found.
*
* @author coderkun <olli@coderkun.de>
*/
class ClassNotFoundException extends \nre\core\Exception
{
/**
* Error code
*
* @var int
*/
const CODE = 64;
/**
* Error message
*
* @var string
*/
const MESSAGE = 'class not found';
/**
* Name of the class that was not found
*
* @var string
*/
private $className;
/**
* Construct a new exception
*
* @param string $className Name of the class that was not found
*/
function __construct($className, $message=self::MESSAGE, $code=self::CODE)
{
parent::__construct(
$message,
$code,
$className
);
// Store values
$this->className = $className;
}
/**
* Get the name of the class that was not found.
*
* @return string Name of the class that was not found
*/
public function getClassName()
{
return $this->className;
}
}
?>

Some files were not shown because too many files have changed in this diff Show more