<?php
class Page_LocationInfo extends Page
{
private $action;
/**
* Called before any page rendering happens - early hook to check parameters etc.
*/
protected function doPreprocess()
{
User::load();
if (!User::isLoggedIn()) {
Message::addError('main.no-permission');
Util::redirect('?do=Main'); // does not return
}
$this->action = Request::post('action');
if ($this->action === 'updateOpeningTimeExpert') {
$this->updateOpeningTimeExpert();
} elseif ($this->action === 'updateOpeningTimeEasy') {
$this->updateOpeningTimeEasy();
} elseif ($this->action === 'updateConfig') {
$this->updateLocationConfig();
} elseif ($this->action === 'deleteServer') {
$this->deleteServer();
} elseif ($this->action === 'checkConnection') {
$this->checkConnection(Request::post('serverid', 0, 'int'));
} elseif ($this->action === 'updateServerSettings') {
$this->updateServerSettings();
} elseif (Request::isPost()) {
Messages::addWarning('main.invalid-action', $this->action);
}
if (Request::isPost()) {
Util::redirect('?do=locationinfo');
}
}
/**
* Menu etc. has already been generated, now it's time to generate page content.
*/
protected function doRender()
{
$this->getInfoScreenTable();
}
/**
* Deletes the server from the db.
*/
private function deleteServer()
{
$id = Request::post('serverid', false, 'int');
if ($id === false) {
Messages::addError('server-id-missing');
return;
}
Database::exec("DELETE FROM `locationinfo_coursebackend` WHERE serverid=:id", array('id' => $id));
}
/**
* Updated the config in the db.
*/
private function updateLocationConfig()
{
$result = array();
$locationid = Request::post('id', 0, 'int');
if ($locationid <= 0) {
Message::addError('location.invalid-location-id', $locationid);
Util::redirect('?do=locationinfo');
}
$result['language'] = Request::post('language', 'en', 'string');
$result['mode'] = Request::post('mode', 1, 'int');
$result['vertical'] = Request::post('vertical', false, 'bool');
$result['eco'] = Request::post('eco', false, 'bool');
$result['scaledaysauto'] = Request::post('scaledaysauto', false, 'bool');
$result['daystoshow'] = Request::post('daystoshow', 7, 'int');
$result['rotation'] = Request::post('rotation', 0, 'int');
$result['scale'] = Request::post('scale', 50, 'int');
$result['switchtime'] = Request::post('switchtime', 20, 'int');
$result['calupdate'] = Request::post('calupdate', 30, 'int');
$result['roomupdate'] = Request::post('roomupdate', 30, 'int');
$result['configupdate'] = Request::post('configupdate', 180, 'int');
$serverid = Request::post('serverid', 0, 'int');
$serverlocationid = Request::post('serverlocationid', '', 'string');
Database::exec("INSERT INTO `locationinfo_locationconfig` (locationid, serverid, serverlocationid, config, lastcalendarupdate)
VALUES (:id, :serverid, :serverlocationid, :config, 0)
ON DUPLICATE KEY UPDATE config = VALUES(config), serverid = VALUES(serverid),
serverlocationid = VALUES(serverlocationid), lastcalendarupdate = 0", array(
'id' => $locationid,
'config' => json_encode($result),
'serverid' => $serverid,
'serverlocationid' => $serverlocationid,
));
Message::addSuccess('config-saved');
Util::redirect('?do=locationinfo');
}
/**
* Updates the server settings in the db.
*/
private function updateServerSettings()
{
$serverid = Request::post('id', -1, 'int');
$servername = Request::post('name', 'unnamed', 'string');
$servertype = Request::post('type', '', 'string');
$backend = CourseBackend::getInstance($servertype);
if ($backend === false) {
Messages::addError('invalid-backend-type', $servertype);
Util::redirect('?do=locationinfo');
}
$tmptypeArray = $backend->getCredentialDefinitions();
$credentialsJson = array();
$counter = 0;
foreach ($tmptypeArray as $cred) {
$credentialsJson[$cred->property] = Request::post($counter);
$counter++;
}
$params = array(
'name' => $servername,
'type' => $servertype,
'credentials' => json_encode($credentialsJson)
);
if ($serverid === 0) {
Database::exec('INSERT INTO `locationinfo_coursebackend` (servername, servertype, credentials)
VALUES (:name, :type, :credentials)', $params);
$this->checkConnection(Database::lastInsertId());
} else {
$params['id'] = $serverid;
Database::exec('UPDATE `locationinfo_coursebackend`
SET servername = :name, servertype = :type, credentials = :credentials
WHERE serverid = :id', $params);
$this->checkConnection($serverid);
}
}
/**
* Updates the opening time in the db from the expert mode.
*/
private function updateOpeningTimeExpert()
{
$days = Request::post('days', array(), 'array');
$locationid = Request::post('id', 0, 'int');
$openingtime = Request::post('openingtime', array(), 'array');
$closingtime = Request::post('closingtime', array(), 'array');
$easyMode = Request::post('easyMode', false, 'bool');
$delete = Request::post('delete', array(), 'array');
$dontadd = Request::post('dontadd', array(), 'array');
$count = 0;
$result = array();
$resulttmp = array();
$deleteCounter = 0;
if (!$easyMode) {
$resulttmp = Database::queryFirst("SELECT openingtime FROM `locationinfo_locationconfig` WHERE locationid = :id", array('id' => $locationid));
if ($resulttmp !== false) {
$resulttmp = json_decode($resulttmp['openingtime'], true);
}
if (!is_array($resulttmp)) {
$resulttmp = array();
}
$index = 0;
foreach ($resulttmp as $day) {
$skip = false;
foreach ($delete as $del) {
if ($del == $index) {
$skip = true;
break;
}
}
if ($skip) {
$index++;
$deleteCounter++;
continue;
}
$result[] = $day;
$index++;
}
}
if (!empty($days) && !is_array($days)) {
Message::addError('no-days-selected');
Util::redirect('?do=locationinfo');
} else {
$dayz = array();
$da = array();
foreach ($days as $d) {
if ($d != '-') {
$da[] = $d;
} else {
$dayz[$count] = $da;
$da = array();
$count++;
}
}
$optime = array();
for ($x = 0; $x < $count; $x++) {
if ($dontadd[$x] == 'dontadd') {
continue;
}
$optime['days'] = $dayz[$x];
$optime['openingtime'] = $openingtime[$x];
$optime['closingtime'] = $closingtime[$x];
$result[] = $optime;
}
}
Database::exec("INSERT INTO `locationinfo_locationconfig` (locationid, openingtime)
VALUES (:id, :openingtime)
ON DUPLICATE KEY UPDATE openingtime = VALUES(openingtime)",
array('id' => $locationid, 'openingtime' => json_encode($result)));
if ($deleteCounter > 0) {
Message::addSuccess('deleted-x-entries', $deleteCounter);
}
if ($count > 0) {
Message::addSuccess('added-x-entries', $count);
}
Util::redirect('?do=locationinfo');
}
/**
* Updates the opening time in the db from the easy mode.
*/
private function updateOpeningTimeEasy()
{
$locationid = Request::post('id', 0, 'int');
$openingtime = Request::post('openingtime', array(), 'array');
$closingtime = Request::post('closingtime', array(), 'array');
$result = array();
$blocks = array(
0 => array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"),
1 => array("Saturday"),
2 => array("Sunday"),
);
foreach ($blocks as $idx => $days) {
//if (!empty($openingtime[$idx]) && !empty($closingtime[$idx])) {
$result[] = array(
'days' => $days,
'openingtime' => $openingtime[$idx],
'closingtime' => $closingtime[$idx],
);
//}
}
Database::exec("INSERT INTO `locationinfo_locationconfig` (locationid, openingtime)
VALUES (:id, :openingtime)
ON DUPLICATE KEY UPDATE openingtime = VALUES(openingtime)",
array('id' => $locationid, 'openingtime' => json_encode($result)));
Message::addSuccess('openingtime-updated');
Util::redirect('?do=locationinfo');
}
/**
* Checks if the server connection to a backend is valid.
*
* @param int $id Server id which connection should be checked.
*/
private function checkConnection($serverid = 0)
{
if ($serverid === 0) {
Util::traceError('checkConnection called with no server id');
}
$dbresult = Database::queryFirst("SELECT servertype, credentials
FROM `locationinfo_coursebackend`
WHERE serverid = :serverid", array('serverid' => $serverid));
$serverInstance = CourseBackend::getInstance($dbresult['servertype']);
if ($serverInstance === false) {
LocationInfo::setServerError($serverid, 'Unknown backend type: ' . $dbresult['servertype']);
return;
}
$credentialsOk = $serverInstance->setCredentials($serverid, json_decode($dbresult['credentials'], true));
if ($credentialsOk) {
$connectionOk = $serverInstance->checkConnection();
}
LocationInfo::setServerError($serverid, $serverInstance->getError());
}
/**
* Sets the new hidden value and checks childs and parents.
*
* @param int $id The location id which was toggled
* @param bool $hidden The hidden value true / false
*/
protected function toggleHidden($id, $hidden)
{
$locs = Location::getLocationsAssoc();
if (!isset($locs[$id]))
die('Invalid location id');
$loc = $locs[$id];
// The JSON to return, telling the client which locationids to update in the view
$return = array();
$return[] = array('locationid' => $id, 'hidden' => $hidden);
// Update the location, plus all child locations
$qs = '(?,?)' . str_repeat(',(?,?)', count($loc['children']));
$params = array($id, $hidden);
foreach ($loc['children'] as $child) {
$params[] = $child;
$params[] = $hidden;
$return[] = array('locationid' => $child, 'hidden' => $hidden);
}
Database::exec("INSERT INTO locationinfo_locationconfig (locationid, hidden)
VALUES $qs ON DUPLICATE KEY UPDATE hidden = VALUES(hidden)", $params);
// Handle parents - uncheck if not all children are checked
while ($loc['parentlocationid'] != 0) {
$stats = Database::queryFirst('SELECT Count(*) AS total, Sum(li.hidden > 0) AS hidecount FROM location l
LEFT JOIN locationinfo_locationconfig li USING (locationid)
WHERE l.parentlocationid = :parent', array('parent' => $loc['parentlocationid']));
$hidden = ($stats['total'] == $stats['hidecount']) ? 1 : 0;
$params = array('locationid' => $loc['parentlocationid'], 'hidden' => $hidden);
Database::exec('INSERT INTO locationinfo_locationconfig (locationid, hidden)
VALUES (:locationid, :hidden) ON DUPLICATE KEY UPDATE hidden = VALUES(hidden)', $params);
$return[] = $params;
$loc = $locs[$loc['parentlocationid']];
}
return $return;
}
/**
* Loads the Infoscreen page in the admin-panel and passes all needed information.
*/
protected function getInfoScreenTable()
{
$locations = Location::getLocations(0, 0, false, true);
// Get hidden state of all locations
$dbquery = Database::simpleQuery("SELECT li.locationid, li.hidden FROM `locationinfo_locationconfig` AS li");
while ($row = $dbquery->fetch(PDO::FETCH_ASSOC)) {
$locid = (int)$row['locationid'];
$locations[$locid]['hidden_checked'] = $row['hidden'] != 0 ? 'checked' : '';
}
// Get a list of all the backend types.
$servertypes = array();
$s_list = CourseBackend::getList();
foreach ($s_list as $s) {
$typeInstance = CourseBackend::getInstance($s);
$servertypes[$s] = $typeInstance->getDisplayName();
}
// Get the Serverlist from the DB and make it mustache accessable
$serverlist = array();
$dbquery2 = Database::simpleQuery("SELECT * FROM `locationinfo_coursebackend`");
while ($row = $dbquery2->fetch(PDO::FETCH_ASSOC)) {
if (isset($servertypes[$row['servertype']])) {
$row['typename'] = $servertypes[$row['servertype']];
} else {
$row['typename'] = '[' . $row['servertype'] . ']';
$row['disabled'] = 'disabled';
}
if (!empty($row['error'])) {
$row['autherror'] = true;
$error = json_decode($row['error'], true);
if (isset($error['timestamp'])) {
$time = date('Y/m/d H:i:s', $error['timestamp']);
} else {
$time = '???';
}
Message::addError('auth-failed', $row['servername'], $time, $error['error']);
}
$serverlist[] = $row;
}
// Pass the data to the html and render it.
Render::addTemplate('location-info', array(
'list' => array_values($locations),
'serverlist' => $serverlist,
));
}
/**
* AJAX
*/
protected function doAjax()
{
User::load();
if (!User::isLoggedIn()) {
die('Unauthorized');
}
$action = Request::any('action');
$id = Request::any('id', 0, 'int');
if ($action === 'timetable') {
$this->ajaxTimeTable($id);
} elseif ($action === 'config') {
$this->ajaxLoadLocationConfig($id);
} elseif ($action === 'serverSettings') {
$this->ajaxServerSettings($id);
} elseif ($action === 'hide') {
$this->ajaxHideLocation();
}
}
/**
* Request to deny displaying the door sign for the
* given location. Sends a list of all affected
* locations, so the client can update its view.
*/
private function ajaxHideLocation()
{
$locationId = Request::post('locationid', 0, 'int');
$hidden = Request::post('hidden', 0, 'int');
Header('Content-Type: application/json; charset=utf-8');
$ret = $this->toggleHidden($locationId, $hidden);
echo json_encode(array('changed' => $ret));
}
/**
* Ajax the server settings.
*
* @param int $id Serverid
*/
private function ajaxServerSettings($id)
{
$dbresult = Database::queryFirst('SELECT servername, servertype, credentials
FROM `locationinfo_coursebackend` WHERE serverid = :id', array('id' => $id));
// Credentials stuff.
$dbcredentials = json_decode($dbresult['credentials'], true);
// Get a list of all the backend types.
$serverBackends = array();
$s_list = CourseBackend::getList();
foreach ($s_list as $s) {
$backend['typ'] = $s;
$backendInstance = CourseBackend::getInstance($s);
$backend['display'] = $backendInstance->getDisplayName();
if ($backend['typ'] == $dbresult['servertype']) {
$backend['active'] = true;
} else {
$backend['active'] = false;
}
$credentials = $backendInstance->getCredentialDefinitions();
$backend['credentials'] = array();
$counter = 0;
foreach ($credentials as $cred) {
$credential['uid'] = $counter;
$credential['name'] = Dictionary::translateFile($s, $cred->property, true);
$credential['type'] = $cred->type;
$credential['title'] = Dictionary::translateFile($s, $cred->property . "_title");
if (Property::getPasswordFieldType() === 'text') {
$credential['mask'] = false;
} else {
if ($cred->type === "password") {
$credential['mask'] = true;
}
}
if ($backend['typ'] == $dbresult['servertype']) {
if (isset($dbcredentials[$cred->property])) {
$credential['value'] = $dbcredentials[$cred->property];
} else {
$credential['value'] = $cred->default;
}
}
$selection = array();
if (is_array($cred->type)) {
$selfirst = true;
foreach ($cred->type as $opt) {
$option['option'] = $opt;
if (isset($credential['value'])) {
if ($opt == $credential['value']) {
$option['active'] = true;
} else {
$option['active'] = false;
}
} else {
if ($selfirst) {
$option['active'] = true;
$selfirst = false;
} else {
$option['active'] = false;
}
}
$selection[] = $option;
}
$credential['type'] = "array";
$credential['array'] = $selection;
}
$backend['credentials'][] = $credential;
$counter++;
}
$serverBackends[] = $backend;
}
echo Render::parse('server-settings', array('id' => $id,
'name' => $dbresult['servername'],
'servertype' => $dbresult['servertype'],
'backendList' => array_values($serverBackends)));
}
/**
* Ajax the time table
*
* @param $id id of the location
*/
private function ajaxTimeTable($id)
{
$row = Database::queryFirst("SELECT openingtime FROM `locationinfo_locationconfig` WHERE locationid = :id", array('id' => $id));
if ($row !== false) {
$openingtimes = json_decode($row['openingtime'], true);
}
if (!is_array($openingtimes)) {
$openingtimes = array();
}
if ($this->isEasyMode($openingtimes)) {
echo Render::parse('timetable', array('id' => $id,
'openingtime0' => $openingtimes[0]['openingtime'],
'closingtime0' => $openingtimes[0]['closingtime'],
'openingtime1' => $openingtimes[1]['openingtime'],
'closingtime1' => $openingtimes[1]['closingtime'],
'openingtime2' => $openingtimes[2]['openingtime'],
'closingtime2' => $openingtimes[2]['closingtime'],
'easyMode' => true,
'expertMode' => false));
} else {
$index = 0;
foreach ($openingtimes as &$entry) {
$entry['days'] = implode(', ', $entry['days']);
$entry['index'] = $index++;
}
echo Render::parse('timetable', array('id' => $id,
'openingtimes' => array_values($openingtimes),
'easyMode' => false,
'expertMode' => true));
}
}
/**
* Checks if easymode or expert mode is active.
*
* @param $array Array of the saved openingtimes.
* @return bool True if easy mode, false if expert mode
*/
private function isEasyMode($array)
{
if (empty($array))
return true;
if (count($array) === 3
&& $array[0]['days'] == array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
&& $array[1]['days'][0] == "Saturday" && $array[2]['days'][0] == "Sunday"
) {
return true;
}
return false;
}
/**
* Ajax the config of a location.
*
* @param $id Location ID
*/
private function ajaxLoadLocationConfig($id)
{
// Get Config data from db
$location = Database::queryFirst("SELECT config, serverid, serverlocationid FROM `locationinfo_locationconfig` WHERE locationid = :id", array('id' => $id));
if ($location === false) {
die("Invalid location id: $id");
}
$config = json_decode($location['config'], true); // TODO: Validate we got an array, fill with defaults otherwise
// get Server / ID list
$dbq = Database::simpleQuery("SELECT serverid, servername FROM locationinfo_coursebackend ORDER BY servername ASC");
$serverList = array();
while ($row = $dbq->fetch(PDO::FETCH_ASSOC)) {
if ($row['serverid'] == $location['serverid']) {
$row['selected'] = 'selected';
}
$serverList[] = $row;
}
$langs = Dictionary::getLanguages(true);
foreach ($langs as &$lang) {
if ($lang['cc'] === $config['language']) {
$lang['selected'] = 'selected';
}
}
echo Render::parse('config', array(
'id' => $id,
'languages' => $langs,
'mode' => $config['mode'],
'vertical_checked' => $config['vertical'] ? 'checked' : '',
'eco_checked' => $config['eco'] ? 'checked' : '',
'scaledaysauto_checked' => $config['scaledaysauto'] ? 'checked' : '',
'daystoshow' => $config['daystoshow'],
'rotation' => $config['rotation'],
'scale' => $config['scale'],
'switchtime' => $config['switchtime'],
'calupdate' => $config['calupdate'],
'roomupdate' => $config['roomupdate'],
'configupdate' => $config['configupdate'],
'serverlist' => $serverList,
'serverid' => $location['serverid'],
'serverlocationid' => $location['serverlocationid']
));
}
}