fixed stretching for narrow crossword quests

This commit is contained in:
Daniel 2014-04-26 15:42:29 +02:00
commit c1a314f6e7
3452 changed files with 593206 additions and 0 deletions

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);
}
}