<?php
class InfoPanel
{
/**
* Gets the config of the location.
*
* @param int $locationID ID of the location
* @param ?array $config the panel config will be returned here
* @return ?string panel type, null if not exists
*/
public static function getConfig(string $paneluuid, ?array &$config): ?string
{
$panel = Database::queryFirst('SELECT panelname, panelconfig, paneltype, locationids FROM locationinfo_panel WHERE paneluuid = :paneluuid',
compact('paneluuid'));
if ($panel === false) {
return null;
}
$config = LocationInfo::defaultPanelConfig($panel['paneltype']);
if ($panel['paneltype'] === 'URL') {
// Shortcut for URL redirect
$config = json_decode($panel['panelconfig'], true) + $config;
return $panel['paneltype'];
}
$locations = Location::getLocationsAssoc();
$overrides = false;
if (!empty($panel['panelconfig'])) {
$json = json_decode($panel['panelconfig'], true);
if (is_array($json)) {
// Put location-specific overrides in separate variable for later use
if (isset($json['overrides']) && is_array($json['overrides'])) {
$overrides = $json['overrides'];
}
unset($json['overrides']);
$config = $json + $config;
}
}
if (isset($config['showtitle']) && $config['showtitle']) {
$config['title'] = $panel['title'];
}
$config['locations'] = array();
$lids = array_map('intval', explode(',', $panel['locationids']));
// Locations -
if ($panel['paneltype'] === 'SUMMARY') {
$lids = Location::getRecursiveFlat($lids);
$lids = array_keys($lids);
foreach ($lids as $lid) {
$config['locations'][$lid] = array('id' => $lid);
}
}
if ($panel['paneltype'] === 'DEFAULT') {
foreach ($lids as $lid) {
$config['locations'][$lid] = array(
'id' => $lid,
'name' => isset($locations[$lid]) ? $locations[$lid]['locationname'] : 'noname00.pas',
);
// Now apply any overrides from above
if (isset($overrides[$lid]) && is_array($overrides[$lid])) {
$config['locations'][$lid]['config'] = $overrides[$lid];
}
}
self::appendMachineData($config['locations'], $lids, true, $config['hostname']);
}
self::appendOpeningTimes($config['locations'], $lids);
$config['locations'] = array_values($config['locations']);
$config['time'] = date('Y-n-j-G-') . (int)date('i') . '-' . (int)(date('s'));
return $panel['paneltype'];
}
/**
* {"language":"de","mode":1,"vertical":true,"eco":false,"scaledaysauto":true,"daystoshow":7,"rotation":0,"scale":56,"switchtime":10,"calupdate":120,"roomupdate":20,
* "overrides": { "12" : { "mode":4} }
* Gets the location info of the given locations.
* Append to passed array which is expected to
* map location ids to properties of that location.
* A new key 'machines' will be created in each
* entry of $array that will take all the machine data.
*
* @param array $array location list to populate with machine data
* @param bool $withPosition Defines if coords should be included or not.
*/
public static function appendMachineData(array &$array, array $idList, bool $withPosition = false, bool $withHostname = false): void
{
if (empty($idList))
return;
$ignoreList = array();
if (Module::isAvailable('runmode')) {
// Ignore clients with special runmode not marked as still being a client
$ignoreList = RunMode::getAllClients(false, false);
}
$extraCols = '';
if ($withPosition) {
$extraCols .= 'm.position,';
}
if ($withHostname) {
$extraCols .= 'm.hostname,';
}
$query = "SELECT m.locationid, m.fixedlocationid, m.machineuuid, $extraCols m.logintime,
m.lastseen, m.lastboot, m.state, m.currentrunmode
FROM machine m
WHERE m.locationid IN (:idlist)";
$dbquery = Database::simpleQuery($query, array('idlist' => $idList));
// Iterate over matching machines
foreach ($dbquery as $row) {
if (isset($ignoreList[$row['machineuuid']]))
continue;
settype($row['locationid'], 'int');
if (!isset($array[$row['locationid']])) {
$array[$row['locationid']] = array('id' => $row['locationid'], 'machines' => array());
}
if (!isset($array[$row['locationid']]['machines'])) {
$array[$row['locationid']]['machines'] = array();
}
// Compact the pc data in one array.
$pc = array('id' => $row['machineuuid']);
if ($withPosition && $row['locationid'] == $row['fixedlocationid'] && !empty($row['position'])) {
// check fixed* == locationid to ignore stale position data in relocated clients
$position = json_decode($row['position'], true);
if (isset($position['gridCol']) && isset($position['gridRow'])) {
$pc['x'] = $position['gridCol'];
$pc['y'] = $position['gridRow'];
if (!empty($position['overlays']) && is_array($position['overlays'])) {
$pc['overlays'] = $position['overlays'];
}
}
}
if ($withHostname) {
if (ip2long($row['hostname']) !== false) {
$pc['host'] = $row['hostname'];
} else {
$i = strpos($row['hostname'], '.');
if ($i === false) {
$pc['host'] = $row['hostname'];
} else {
$pc['host'] = substr($row['hostname'], 0, $i);
}
}
}
$pc['runmode'] = $row['currentrunmode'];
$pc['pcState'] = LocationInfo::getPcState($row);
//$pc['pcState'] = ['BROKEN', 'OFFLINE', 'IDLE', 'OCCUPIED', 'STANDBY'][mt_rand(0,4)]; // XXX
// Add the array to the machines list.
$array[$row['locationid']]['machines'][] = $pc;
}
}
/**
* Gets the Opening time of the given locations.
*
* @param array $array list of locations, indexed by locationId
* @param int[] $idList list of locations
*/
public static function appendOpeningTimes(array &$array, array $idList): void
{
// First, lets get all the parent ids for the given locations
// in case we need to get inherited opening times
$allIds = self::getLocationsWithParents($idList);
if (empty($allIds))
return;
$res = Database::simpleQuery("SELECT locationid, openingtime FROM location
WHERE locationid IN (:lids)", array('lids' => $allIds));
$openingTimes = array();
foreach ($res as $row) {
$openingTimes[(int)$row['locationid']] = $row;
}
// Now we got all the calendars for locations and parents
// Iterate over the locations we're actually interested in
$locations = Location::getLocationsAssoc();
foreach ($idList as $locationId) {
if (empty($locationId))
continue;
// Start checking at actual location...
$currentId = $locationId;
while ($currentId !== 0) {
if (!empty($openingTimes[$currentId]['openingtime'])) {
$cal = json_decode($openingTimes[$currentId]['openingtime'], true);
if (is_array($cal)) {
$cal = self::formatOpeningtime($cal);
}
if (!empty($cal)) {
// Got a valid calendar
if (!isset($array[$locationId])) {
$array[$locationId] = array('id' => $locationId);
}
$array[$locationId]['openingtime'] = $cal;
break;
}
}
// Keep trying with parent
if (!isset($locations[$currentId]))
break;
$currentId = $locations[$currentId]['parentlocationid'];
}
}
}
/**
* Returns all the passed location ids and appends
* all their direct and indirect parent location ids.
*
* @param int[] $idList location ids
* @return int[] more location ids
*/
private static function getLocationsWithParents(array $idList): array
{
$locations = Location::getLocationsAssoc();
$allIds = $idList;
foreach ($idList as $id) {
if (isset($locations[$id]['parents'])) {
$allIds = array_merge($allIds, $locations[$id]['parents']);
}
}
return array_map('intval', $allIds);
}
// ########## <Openingtime> ##########
/**
* Format the openingtime in the frontend needed format.
* One key per week day, which contains an array of {
* 'HourOpen' => hh, 'MinutesOpen' => mm,
* 'HourClose' => hh, 'MinutesClose' => mm }
*
* @param array $openingtime The opening time in the db saved format.
* @return array The opening time in the frontend needed format.
*/
private static function formatOpeningtime(array $openingtime): array
{
$result = array();
foreach ($openingtime as $entry) {
$openTime = explode(':', $entry['openingtime']);
$closeTime = explode(':', $entry['closingtime']);
if (count($openTime) !== 2 || count($closeTime) !== 2)
continue;
$convertedTime = array(
'HourOpen' => $openTime[0],
'MinutesOpen' => $openTime[1],
'HourClose' => $closeTime[0],
'MinutesClose' => $closeTime[1],
);
foreach ($entry['days'] as $day) {
if (!isset($result[$day])) {
$result[$day] = array();
}
$result[$day][] = $convertedTime;
}
}
return $result;
}
}