diff options
Diffstat (limited to 'modules-available/roomplanner')
36 files changed, 258 insertions, 145 deletions
diff --git a/modules-available/roomplanner/api.inc.php b/modules-available/roomplanner/api.inc.php index 8ddb945c..1af25ca8 100644 --- a/modules-available/roomplanner/api.inc.php +++ b/modules-available/roomplanner/api.inc.php @@ -5,14 +5,14 @@ if (Request::any('show') === 'svg') { $ret = PvsGenerator::generateSvg(Request::any('locationid', false, 'int'), Request::any('machineuuid', false, 'string'), Request::any('rotate', 0, 'int'), - Request::any('scale', 1, 'float')); + Request::any('scale', 1, 'float'), + Request::any('url', false, 'bool')); if ($ret === false) { if (Request::any('fallback', 0, 'int') === 0) { Header('HTTP/1.1 404 Not Found'); exit; } $ret = <<<EOF -<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 64 64" height="64" width="64"> <g> <path d="M 0,0 64,64 Z" style="stroke:#ff0000;stroke-width:5" /> @@ -22,7 +22,7 @@ if (Request::any('show') === 'svg') { EOF; } Header('Content-Type: image/svg+xml'); - die($ret); + die('<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . $ret); } // PVS.ini diff --git a/modules-available/roomplanner/hooks/client-update.inc.php b/modules-available/roomplanner/hooks/client-update.inc.php new file mode 100644 index 00000000..a8ffd555 --- /dev/null +++ b/modules-available/roomplanner/hooks/client-update.inc.php @@ -0,0 +1,19 @@ +<?php + +// Either poweron or user logged in +if ($type === '~poweron' || ($type === '~runstate' && $used === 1 && $old['state'] !== 'OCCUPIED')) { + // Get all the clients that are managers for rooms this client is a tutor for. + // Start in the machine table aliased tut, map $ip to client uuid, then look this + // up in the location_roomplan table as tutoruuid, get the according managerip, + // look this one up again in machine table aliased mgr to finally get the according + // mac address of that manager. We need that for WOL. + $managers = Database::queryAll('SELECT mgr.machineuuid, mgr.clientip, mgr.macaddr + FROM machine tut + INNER JOIN location_roomplan lr ON (tut.machineuuid = lr.tutoruuid) + INNER JOIN machine mgr ON (lr.managerip = mgr.clientip) + WHERE tut.clientip = :tutorip', ['tutorip' => $ip]); + if (!empty($managers) && Module::isAvailable('rebootcontrol')) { + // Create WOL job + RebootControl::wakeMachines($managers); + } +}
\ No newline at end of file diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/copier-east.png b/modules-available/roomplanner/images/electricalDevices_wIP/copier-east.png Binary files differnew file mode 100644 index 00000000..e5b6d562 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/copier-east.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/copier-north.png b/modules-available/roomplanner/images/electricalDevices_wIP/copier-north.png Binary files differnew file mode 100644 index 00000000..9d12ff3c --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/copier-north.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/copier.png b/modules-available/roomplanner/images/electricalDevices_wIP/copier-south.png Binary files differindex 24cdc2ae..24cdc2ae 100644 --- a/modules-available/roomplanner/images/electricalDevices_wIP/copier.png +++ b/modules-available/roomplanner/images/electricalDevices_wIP/copier-south.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/copier-west.png b/modules-available/roomplanner/images/electricalDevices_wIP/copier-west.png Binary files differnew file mode 100644 index 00000000..3d4dd6ad --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/copier-west.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/pc.png b/modules-available/roomplanner/images/electricalDevices_wIP/pc.png Binary files differdeleted file mode 100644 index d1c9417d..00000000 --- a/modules-available/roomplanner/images/electricalDevices_wIP/pc.png +++ /dev/null diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/printer-east.png b/modules-available/roomplanner/images/electricalDevices_wIP/printer-east.png Binary files differnew file mode 100644 index 00000000..5ebe9866 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/printer-east.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/printer-north.png b/modules-available/roomplanner/images/electricalDevices_wIP/printer-north.png Binary files differnew file mode 100644 index 00000000..675e1788 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/printer-north.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/printer.png b/modules-available/roomplanner/images/electricalDevices_wIP/printer-south.png Binary files differindex ec851e04..ec851e04 100644 --- a/modules-available/roomplanner/images/electricalDevices_wIP/printer.png +++ b/modules-available/roomplanner/images/electricalDevices_wIP/printer-south.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/printer-west.png b/modules-available/roomplanner/images/electricalDevices_wIP/printer-west.png Binary files differnew file mode 100644 index 00000000..99033b92 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/printer-west.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/telephone-east.png b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-east.png Binary files differnew file mode 100644 index 00000000..3581ff67 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-east.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/telephone-north.png b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-north.png Binary files differnew file mode 100644 index 00000000..8c6fb85d --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-north.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/telephone.png b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-south.png Binary files differindex 207bfe56..207bfe56 100644 --- a/modules-available/roomplanner/images/electricalDevices_wIP/telephone.png +++ b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-south.png diff --git a/modules-available/roomplanner/images/electricalDevices_wIP/telephone-west.png b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-west.png Binary files differnew file mode 100644 index 00000000..89780d44 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_wIP/telephone-west.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen.png b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-east.png Binary files differindex de05797c..de05797c 100644 --- a/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen.png +++ b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-east.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-north.png b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-north.png Binary files differnew file mode 100644 index 00000000..52b650a0 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-north.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-south.png b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-south.png Binary files differnew file mode 100644 index 00000000..8c4bfb7f --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-south.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-west.png b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-west.png Binary files differnew file mode 100644 index 00000000..39708ba5 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/flatscreen-west.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/lamp.png b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-east.png Binary files differindex 584ea1d9..584ea1d9 100644 --- a/modules-available/roomplanner/images/electricalDevices_woIP/lamp.png +++ b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-east.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/lamp-north.png b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-north.png Binary files differnew file mode 100644 index 00000000..e9805690 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-north.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/lamp-south.png b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-south.png Binary files differnew file mode 100644 index 00000000..96b8bbc1 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-south.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/lamp-west.png b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-west.png Binary files differnew file mode 100644 index 00000000..1c6203a0 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/lamp-west.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera.png b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-east.png Binary files differindex c57833b2..c57833b2 100644 --- a/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera.png +++ b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-east.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-north.png b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-north.png Binary files differnew file mode 100644 index 00000000..0ce942e5 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-north.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-south.png b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-south.png Binary files differnew file mode 100644 index 00000000..9914e553 --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-south.png diff --git a/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-west.png b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-west.png Binary files differnew file mode 100644 index 00000000..175502fd --- /dev/null +++ b/modules-available/roomplanner/images/electricalDevices_woIP/tvcamera-west.png diff --git a/modules-available/roomplanner/inc/composedroom.inc.php b/modules-available/roomplanner/inc/composedroom.inc.php index cdd50984..3ee892db 100644 --- a/modules-available/roomplanner/inc/composedroom.inc.php +++ b/modules-available/roomplanner/inc/composedroom.inc.php @@ -98,7 +98,7 @@ class ComposedRoom extends Room return $this->orientation; } - public function subLocationIds() + public function subLocationIds(): array { return $this->list; } @@ -108,7 +108,7 @@ class ComposedRoom extends Room return $this->controlRoom; } - public function machineCount() + public function machineCount(): int { $sum = 0; foreach ($this->list as $lid) { @@ -117,10 +117,9 @@ class ComposedRoom extends Room return $sum; } - public function getSize(&$width, &$height) + public function getSize(?int &$width, ?int &$height) { $horz = ($this->orientation == 'horizontal'); - $width = $height = 0; foreach ($this->list as $locId) { self::$rooms[$locId]->getSize($w, $h); $width = $horz ? $width + $w : max($width, $w); @@ -128,7 +127,7 @@ class ComposedRoom extends Room } } - public function getIniClientSection(&$i, $offX = 0, $offY = 0) + public function getIniClientSection(int &$i, int $offX = 0, int $offY = 0) { if (!$this->enabled) return false; @@ -154,10 +153,10 @@ class ComposedRoom extends Room return $out; } - public function getShiftedArray($offX = 0, $offY = 0) + public function getShiftedArray(int $offX = 0, int $offY = 0): ?array { if (!$this->enabled) - return false; + return null; if ($this->orientation == 'horizontal') { $x = 1; $y = 0; @@ -168,7 +167,7 @@ class ComposedRoom extends Room $ret = []; foreach ($this->list as $locId) { $new = self::$rooms[$locId]->getShiftedArray($offX, $offY); - if ($new !== false) { + if ($new !== null) { $ret = array_merge($ret, $new); self::$rooms[$locId]->getSize($w, $h); $offX += $w * $x; @@ -176,7 +175,7 @@ class ComposedRoom extends Room } } if (empty($ret)) - return false; + return null; return $ret; } @@ -194,12 +193,12 @@ class ComposedRoom extends Room return false; } - public function isLeaf() + public function isLeaf(): bool { return false; } - public function shouldSkip() + public function shouldSkip(): bool { return !$this->enabled; } diff --git a/modules-available/roomplanner/inc/pvsgenerator.inc.php b/modules-available/roomplanner/inc/pvsgenerator.inc.php index 0275054b..f3c5c838 100644 --- a/modules-available/roomplanner/inc/pvsgenerator.inc.php +++ b/modules-available/roomplanner/inc/pvsgenerator.inc.php @@ -3,7 +3,7 @@ class PvsGenerator { - public static function generate() + public static function generate(): string { /* collect names and build room blocks - filter empty rooms while at it */ $roomNames = array(); @@ -36,7 +36,7 @@ class PvsGenerator * @param Room $room room/location data as fetched from db * @return string|false .ini section for room, or false if room is empty */ - private static function generateRoomBlock($room) + private static function generateRoomBlock(Room $room) { $room->getSize($sizeX, $sizeY); if ($sizeX === 0 || $sizeY === 0) @@ -78,7 +78,7 @@ class PvsGenerator * @param float $scale scaling factor for output * @return string SVG */ - public static function generateSvg($locationId = false, $highlightUuid = false, $rotate = 0, $scale = 1) + public static function generateSvg($locationId = false, $highlightUuid = false, int $rotate = 0, $scale = 1, $links = false, array $present = null) { if ($locationId === false) { $locationId = Database::queryFirst('SELECT fixedlocationid FROM machine @@ -91,13 +91,13 @@ class PvsGenerator } // Load room $room = Room::get($locationId); - if ($room === false) + if ($room === null) return false; $room->getSize($sizeX, $sizeY); if ($sizeX === 0 || $sizeY === 0) return false; // Empty - $machines = $room->getShiftedArray(); + $machines = $room->getShiftedArray() ?? []; $ORIENTATION = ['north' => 2, 'east' => 3, 'south' => 0, 'west' => 1]; if (is_string($highlightUuid)) { $highlightUuid = strtoupper($highlightUuid); @@ -105,7 +105,7 @@ class PvsGenerator // Figure out autorotate $auto = ($rotate < 0); if ($auto && $highlightUuid !== false) { - foreach ($machines as &$machine) { + foreach ($machines as $machine) { if ($machine['machineuuid'] === $highlightUuid) { $rotate = 4 - $ORIENTATION[$machine['rotation']]; // Reverse rotation break; @@ -117,6 +117,8 @@ class PvsGenerator foreach ($machines as &$machine) { if ($machine['machineuuid'] === $highlightUuid) { $machine['class'] = 'hl'; + } elseif (!empty($present) && !in_array($machine['machineuuid'], $present)) { + $machine['class'] = 'muted'; } $machine['rotation'] = $ORIENTATION[$machine['rotation']] * 90; } @@ -140,6 +142,7 @@ class PvsGenerator 'centerY' => $centerY, 'rotate' => $rotate * 90, 'machines' => $machines, + 'links' => $links, 'line' => ['x' => $sizeX, 'y' => $sizeY], ], 'roomplanner'); // FIXME: Needs module param if called from api.inc.php } @@ -173,14 +176,12 @@ class PvsGenerator /** * Get display name for manager of given locationId. * Hook for "runmode" module to resolve mode name. - * @param $locationId - * @return bool|string */ - public static function getManagerName($locationId) + public static function getManagerName(int $locationId): ?string { $names = Location::getNameChain($locationId); if ($names === false) - return false; + return null; return implode(' / ', $names); } diff --git a/modules-available/roomplanner/inc/room.inc.php b/modules-available/roomplanner/inc/room.inc.php index 855bdbcf..880cb6d0 100644 --- a/modules-available/roomplanner/inc/room.inc.php +++ b/modules-available/roomplanner/inc/room.inc.php @@ -28,11 +28,11 @@ abstract class Room 'SELECT lr.locationid, lr.managerip, lr.tutoruuid, lr.roomplan, m.clientip as tutorip FROM location_roomplan lr LEFT JOIN machine m ON (lr.tutoruuid = m.machineuuid)'); - while ($row = $ret->fetch(PDO::FETCH_ASSOC)) { - $row = self::loadSingleRoom($row); - if ($row === false) + foreach ($ret as $row) { + $room = self::loadSingleRoom($row); + if ($room === null) continue; - self::$rooms[$row->locationId] = $row; + self::$rooms[$room->locationId] = $room; } foreach (self::$rooms as $room) { $room->sanitize(); @@ -42,14 +42,14 @@ abstract class Room /** * Instantiate ComposedRoom or MachineGroup depending on contents of $row * @param array $row DB row from location_roomplan. - * @return Room|false Room instance, false on error + * @return ?Room Room instance, null on error */ - private static function loadSingleRoom($row) + private static function loadSingleRoom(array $row): ?Room { $locations = Location::getLocationsAssoc(); settype($row['locationid'], 'int'); if (!isset($locations[$row['locationid']])) - return false; + return null; if ($locations[$row['locationid']]['isleaf']) return new SimpleRoom($row); return new ComposedRoom($row, false); @@ -59,7 +59,7 @@ abstract class Room * Get array of all rooms with room plan * @return Room[] */ - public static function getAll() + public static function getAll(): array { self::init(); return self::$rooms; @@ -68,9 +68,9 @@ abstract class Room /** * Get room instance for given location * @param int $locationId room to get - * @return Room|false requested room, false if not configured or not found + * @return ?Room requested room, false if not configured or not found */ - public static function get($locationId) + public static function get(int $locationId): ?Room { if (self::$rooms === null) { $room = Database::queryFirst( @@ -79,8 +79,10 @@ abstract class Room LEFT JOIN machine m ON (lr.tutoruuid = m.machineuuid) WHERE lr.locationid = :lid', ['lid' => $locationId]); if ($room === false) - return false; + return null; $room = self::loadSingleRoom($room); + if ($room === null) + return null; // If it's a leaf room we probably don't need any other rooms, return it if ($room->isLeaf()) return $room; @@ -89,7 +91,7 @@ abstract class Room } if (isset(self::$rooms[$locationId])) return self::$rooms[$locationId]; - return false; + return null; } public function __construct($row) @@ -102,35 +104,34 @@ abstract class Room /** * @return int number of machines in this room */ - abstract public function machineCount(); + abstract public function machineCount(): int; /** * Size of this room, returned by reference. - * @param int $width OUT width of room - * @param int $height OUT height of room + * + * @param int|null $width OUT width of room + * @param int|null $height OUT height of room */ - abstract public function getSize(&$width, &$height); + abstract public function getSize(?int &$width, ?int &$height); /** * Get clients in this room in .ini format for PVS. * Adjusted so the top/left client is at (0|0), which * is further adjustable with $offX and $offY. + * * @param int $i offset for indexing clients * @param int $offX positional X offset for clients * @param int $offY positional Y offset for clients * @return string|false */ - abstract public function getIniClientSection(&$i, $offX = 0, $offY = 0); + abstract public function getIniClientSection(int &$i, int $offX = 0, int $offY = 0); /** * Get clients in this room as array. * Adjusted so the top/left client is at (0|0), which *is further adjustable with $offX and $offY. - * @param int $offX - * @param int $offY - * @return array */ - abstract public function getShiftedArray($offX = 0, $offY = 0); + abstract public function getShiftedArray(int $offX = 0, int $offY = 0): ?array; /** * @return string|false IP address of manager. @@ -145,12 +146,12 @@ abstract class Room /** * @return bool true if this is a simple/leaf room, false for composed rooms. */ - abstract public function isLeaf(); + abstract public function isLeaf(): bool; /** * @return bool should this room be skipped from output? true for empty SimpleRoom or disabled ComposedRoom. */ - abstract public function shouldSkip(); + abstract public function shouldSkip(): bool; /** * Sanitize this room's data. @@ -160,7 +161,7 @@ abstract class Room /** * @return string get room's name. */ - public function locationName() + public function locationName(): string { return $this->locationName; } @@ -168,7 +169,7 @@ abstract class Room /** * @return int get room's id. */ - public function locationId() + public function locationId(): int { return $this->locationId; } diff --git a/modules-available/roomplanner/inc/simpleroom.inc.php b/modules-available/roomplanner/inc/simpleroom.inc.php index 78db6c4a..b4d3e744 100644 --- a/modules-available/roomplanner/inc/simpleroom.inc.php +++ b/modules-available/roomplanner/inc/simpleroom.inc.php @@ -11,6 +11,7 @@ class SimpleRoom extends Room private $tutorIp = false; + /** @var ?string */ private $managerIp = false; public function __construct($row) @@ -21,7 +22,7 @@ class SimpleRoom extends Room 'SELECT machineuuid, clientip, position FROM machine WHERE fixedlocationid = :locationid', ['locationid' => $locationId]); - while ($clientRow = $ret->fetch(PDO::FETCH_ASSOC)) { + foreach ($ret as $clientRow) { $position = json_decode($clientRow['position'], true); if ($position === false || !isset($position['gridRow']) || !isset($position['gridCol'])) @@ -55,27 +56,29 @@ class SimpleRoom extends Room } } - public function machineCount() + public function machineCount(): int { return count($this->machines); } - public function getSize(&$width, &$height) + public function getSize(?int &$width, ?int &$height) { if (empty($this->machines)) { $width = $height = 0; return; } + $minX = $minY = $maxX = $maxY = 0; $this->boundingBox($minX, $minY, $maxX, $maxY); // client's size that cannot be configured as of today $width = max($maxX - $minX + self::CLIENT_SIZE, 1); $height = max($maxY - $minY + self::CLIENT_SIZE, 1); } - public function getIniClientSection(&$i, $offX = 0, $offY = 0) + public function getIniClientSection(int &$i, int $offX = 0, int $offY = 0): string { /* output individual client positions, shift coordinates to requested position */ $out = ''; + $minX = $minY = $maxX = $maxY = 0; $this->boundingBox($minX, $minY, $maxX, $maxY); foreach ($this->machines as $pos) { $i++; @@ -86,10 +89,11 @@ class SimpleRoom extends Room return $out; } - public function getShiftedArray($offX = 0, $offY = 0) + public function getShiftedArray(int $offX = 0, int $offY = 0): ?array { /* output individual client positions, shift coordinates to requested position */ $ret = []; + $minX = $minY = $maxX = $maxY = 0; $this->boundingBox($minX, $minY, $maxX, $maxY); foreach ($this->machines as $pos) { $pos['gridCol'] += $offX - $minX; @@ -100,7 +104,7 @@ class SimpleRoom extends Room return $ret; } - private function boundingBox(&$minX, &$minY, &$maxX, &$maxY) + private function boundingBox(int &$minX, int &$minY, int &$maxX, int &$maxY): void { if ($this->bb !== false) { $minX = $this->bb[0]; @@ -130,12 +134,12 @@ class SimpleRoom extends Room return $this->tutorIp; } - public function isLeaf() + public function isLeaf(): bool { return true; } - public function shouldSkip() + public function shouldSkip(): bool { return empty($this->machines); } diff --git a/modules-available/roomplanner/install.inc.php b/modules-available/roomplanner/install.inc.php index 13365fe1..05fd7589 100644 --- a/modules-available/roomplanner/install.inc.php +++ b/modules-available/roomplanner/install.inc.php @@ -47,7 +47,7 @@ if (tableHasColumn('location_roomplan', 'dedicatedmgr')) { if ($ret === false) { $res[] = UPDATE_FAILED; } else { - while ($row = $ret->fetch(PDO::FETCH_ASSOC)) { + foreach ($ret as $row) { $dedi = $row['dedicatedmgr'] != 0; $data = json_encode(array('dedicatedmgr' => $dedi)); Database::exec("INSERT IGNORE INTO runmode (machineuuid, module, modeid, modedata, isclient) diff --git a/modules-available/roomplanner/page.inc.php b/modules-available/roomplanner/page.inc.php index 529dca40..94bc3f78 100644 --- a/modules-available/roomplanner/page.inc.php +++ b/modules-available/roomplanner/page.inc.php @@ -4,14 +4,14 @@ class Page_Roomplanner extends Page { /** - * @var int locationid of location we're editing + * @var ?int locationid of location we're editing, or null if unknown/not set */ - private $locationid = false; + private $locationid = null; /** * @var array location data from location table */ - private $location = false; + private $location = null; /** * @var string action to perform @@ -25,8 +25,8 @@ class Page_Roomplanner extends Page private function loadRequestedLocation() { - $this->locationid = Request::get('locationid', false, 'integer'); - if ($this->locationid !== false) { + $this->locationid = Request::get('locationid', null, 'integer'); + if ($this->locationid !== null) { $locs = Location::getLocationsAssoc(); if (isset($locs[$this->locationid])) { $this->location = $locs[$this->locationid]; @@ -46,11 +46,11 @@ class Page_Roomplanner extends Page $this->action = Request::any('action', 'show', 'string'); $this->loadRequestedLocation(); - if ($this->locationid === false) { + if ($this->locationid === null) { Message::addError('need-locationid'); Util::redirect('?do=locations'); } - if ($this->location === false) { + if ($this->location === null) { Message::addError('locations.invalid-location-id', $this->locationid); Util::redirect('?do=locations'); } @@ -79,7 +79,12 @@ class Page_Roomplanner extends Page private function showLeafEditor() { - $config = Database::queryFirst('SELECT roomplan, managerip, tutoruuid FROM location_roomplan WHERE locationid = :locationid', ['locationid' => $this->locationid]); + $config = Database::queryFirst('SELECT roomplan, managerip, tutoruuid + FROM location_roomplan + WHERE locationid = :locationid', ['locationid' => $this->locationid]); + if ($config === false) { + $config = ['managerip' => '', 'tutoruuid' => '']; + } $runmode = RunMode::getForMode(Page::getModule(), $this->locationid, true); if (empty($runmode)) { $config['dedicatedmgr'] = false; @@ -90,12 +95,6 @@ class Page_Roomplanner extends Page $data = json_decode($runmode['modedata'], true); $config['dedicatedmgr'] = (isset($data['dedicatedmgr']) && $data['dedicatedmgr']); } - if ($config !== false) { - $managerIp = $config['managerip']; - $dediMgr = $config['dedicatedmgr'] ? 'checked' : ''; - } else { - $dediMgr = $managerIp = ''; - } $furniture = $this->getFurniture($config); $subnetMachines = $this->getPotentialMachines(); $machinesOnPlan = $this->getMachinesOnPlan($config['tutoruuid']); @@ -103,13 +102,15 @@ class Page_Roomplanner extends Page $canEdit = User::hasPermission('edit', $this->locationid); $params = [ 'location' => $this->location, - 'managerip' => $managerIp, - 'dediMgrChecked' => $dediMgr, + 'managerip' => $config['managerip'], + 'dediMgrChecked' => $config['dedicatedmgr'] ? 'checked' : '', 'subnetMachines' => json_encode($subnetMachines), 'locationid' => $this->locationid, 'roomConfiguration' => json_encode($roomConfig), 'edit_disabled' => $canEdit ? '' : 'disabled', - 'statistics_disabled' => Module::get('statistics') !== false && User::hasPermission('.statistics.machine.view-details') ? '' : 'disabled', + 'statistics_disabled' => + (Module::get('statistics') !== false && User::hasPermission('.statistics.machine.view-details')) + ? '' : 'disabled', ]; Render::addTemplate('header', $params); if ($canEdit) { @@ -122,9 +123,10 @@ class Page_Roomplanner extends Page private function showComposedEditor() { // Load settings - $row = Database::queryFirst("SELECT locationid, roomplan FROM location_roomplan WHERE locationid = :lid", [ - 'lid' => $this->locationid, - ]); + $row = Database::queryFirst("SELECT locationid, roomplan + FROM location_roomplan + WHERE locationid = :lid", + ['lid' => $this->locationid]); $room = new ComposedRoom($row); $params = [ 'location' => $this->location, @@ -161,7 +163,7 @@ class Page_Roomplanner extends Page $this->action = Request::any('action', false, 'string'); if ($this->action === 'getmachines') { - + // Load suggestions when typing in the search box of the "add machine" pop-up User::load(); $locations = User::getAllowedLocations('edit'); if (empty($locations)) { @@ -190,7 +192,7 @@ class Page_Roomplanner extends Page $returnObject = ['machines' => []]; - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { + foreach ($result as $row) { if (!Location::isFixedLocationValid($roomLocationId, $row['subnetlocationid'])) continue; if (empty($row['hostname'])) { @@ -202,11 +204,12 @@ class Page_Roomplanner extends Page } echo json_encode($returnObject); } elseif ($this->action === 'save') { + // Save roomplan - give feedback if it failed so the window can stay open $this->loadRequestedLocation(); - if ($this->locationid === false) { + if ($this->locationid === null) { die('Missing locationid in save data'); } - if ($this->location === false) { + if ($this->location === null) { die('Location with id ' . $this->locationid . ' does not exist.'); } $this->handleSaveRequest(true); @@ -223,11 +226,9 @@ class Page_Roomplanner extends Page if ($leaf !== $this->isLeaf) { if ($isAjax) { die('Leaf mode mismatch. Did you restructure locations while editing this room?'); - } else { - Message::addError('leaf-mode-mismatch'); - Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } - return; + Message::addError('leaf-mode-mismatch'); + Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } if ($this->isLeaf) { $this->saveLeafRoom($isAjax); @@ -244,10 +245,9 @@ class Page_Roomplanner extends Page if (!is_array($config) || !isset($config['furniture']) || !isset($config['computers'])) { if ($isAjax) { die('JSON data incomplete'); - } else { - Message::addError('json-data-invalid'); - Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } + Message::addError('json-data-invalid'); + Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } $tutorUuid = Request::post('tutoruuid', '', 'string'); if (empty($tutorUuid)) { @@ -257,10 +257,9 @@ class Page_Roomplanner extends Page if ($ret === false) { if ($isAjax) { die('Invalid tutor UUID'); - } else { - Message::addError('invalid-tutor-uuid'); - Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } + Message::addError('invalid-tutor-uuid'); + Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } } $this->saveRoomConfig($config['furniture'], $tutorUuid); @@ -276,10 +275,9 @@ class Page_Roomplanner extends Page if ($res === false) { if ($isAjax) { die('Error writing config to DB'); - } else { - Message::addError('db-error'); - Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } + Message::addError('db-error'); + Util::redirect("?do=roomplanner&locationid={$this->locationid}&action=show"); } } @@ -292,11 +290,15 @@ class Page_Roomplanner extends Page } } - protected function saveComputerConfig($computers, $oldComputers) + /** + * @param array $computers Deserialized json from browser with all the computers + * @param array $oldComputers Deserialized old roomplan from database, used to find removed computers + */ + protected function saveComputerConfig(array $computers, array $oldComputers) { $oldUuids = []; - /* collect all uuids from the old computers */ + /* collect all uuids from the old roomplan */ foreach ($oldComputers['computers'] as $c) { $oldUuids[] = $c['muuid']; } @@ -313,12 +315,12 @@ class Page_Roomplanner extends Page if (!isset($computer['gridRow'])) { $computer['gridRow'] = 0; } else { - $this->sanitizeNumber($computer['gridRow'], 0, 32 * 4); + Util::clamp($computer['gridRow'], 0, 32 * 4); } if (!isset($computer['gridCol'])) { $computer['gridCol'] = 0; } else { - $this->sanitizeNumber($computer['gridCol'], 0, 32 * 4); + Util::clamp($computer['gridCol'], 0, 32 * 4); } $position = json_encode(['gridRow' => $computer['gridRow'], @@ -329,6 +331,7 @@ class Page_Roomplanner extends Page ['locationid' => $this->locationid, 'muuid' => $computer['muuid'], 'position' => $position]); } + // Get all computers that were removed from the roomplan and reset their data in DB $toDelete = array_diff($oldUuids, $newUuids); foreach ($toDelete as $d) { @@ -336,7 +339,7 @@ class Page_Roomplanner extends Page } } - protected function saveRoomConfig($furniture, $tutorUuid) + protected function saveRoomConfig(?array $furniture, ?string $tutorUuid) { $obj = json_encode(['furniture' => $furniture]); $managerIp = Request::post('managerip', '', 'string'); @@ -347,13 +350,11 @@ class Page_Roomplanner extends Page 'locationid' => $this->locationid, 'roomplan' => $obj, 'managerip' => $managerIp, - 'tutoruuid' => $tutorUuid + 'tutoruuid' => $tutorUuid, ]); // See if the client is known, set run-mode - if (empty($managerIp)) { - RunMode::deleteMode(Page::getModule(), $this->locationid); - } else { - RunMode::deleteMode(Page::getModule(), $this->locationid); + RunMode::deleteMode(Page::getModule(), (string)$this->locationid); + if (!empty($managerIp)) { $pc = Statistics::getMachinesByIp($managerIp, Machine::NO_DATA, 'lastseen DESC'); if (!empty($pc)) { $dedicated = (Request::post('dedimgr') === 'on'); @@ -365,22 +366,27 @@ class Page_Roomplanner extends Page } } - protected function getFurniture($config) + protected function getFurniture(array $config): array { - if ($config === false) - return array(); + if (empty($config['roomplan'])) + return []; $config = json_decode($config['roomplan'], true); if (!is_array($config)) - return array(); + return []; return $config; } - protected function getMachinesOnPlan($tutorUuid) + /** + * @return array{computers: array} + */ + protected function getMachinesOnPlan(?string $tutorUuid): array { - $result = Database::simpleQuery('SELECT machineuuid, macaddr, clientip, hostname, position FROM machine WHERE fixedlocationid = :locationid', + $result = Database::simpleQuery('SELECT machineuuid, macaddr, clientip, hostname, position + FROM machine + WHERE fixedlocationid = :locationid', ['locationid' => $this->locationid]); $machines = []; - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { + foreach ($result as $row) { $machine = []; $pos = json_decode($row['position'], true); if ($pos === false || !isset($pos['gridRow']) || !isset($pos['gridCol'])) { @@ -407,7 +413,7 @@ class Page_Roomplanner extends Page return ['computers' => $machines]; } - protected function getPotentialMachines() + protected function getPotentialMachines(): array { $result = Database::simpleQuery('SELECT m.machineuuid, m.macaddr, m.clientip, m.hostname, l.locationname AS otherroom, m.fixedlocationid FROM machine m @@ -416,7 +422,7 @@ class Page_Roomplanner extends Page $machines = []; - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { + foreach ($result as $row) { if (empty($row['hostname'])) { $row['hostname'] = $row['clientip']; } diff --git a/modules-available/roomplanner/style.css b/modules-available/roomplanner/style.css index 70feb946..0ee6d923 100644 --- a/modules-available/roomplanner/style.css +++ b/modules-available/roomplanner/style.css @@ -112,11 +112,6 @@ div.vertical div.img { [itemlook="door-wn"] { background: url('images/wall/door-wn.png') no-repeat;} [itemlook="door-ws"] { background: url('images/wall/door-ws.png') no-repeat;} -[itemlook="copier"] { - background: url('images/electricalDevices_wIP/copier.png') no-repeat; - } - - [itemlook|="pc"] { border: 1px solid #999; border-radius: 4px; @@ -139,30 +134,102 @@ div.vertical div.img { } -[itemlook="printer"] { - background: url('images/electricalDevices_wIP/printer.png') no-repeat; +[itemlook="copier-east"] { + background: url('images/electricalDevices_wIP/copier-east.png') no-repeat; +} - } +[itemlook="copier-south"] { + background: url('images/electricalDevices_wIP/copier-south.png') no-repeat; +} -[itemlook="telephone"] { - background: url('images/electricalDevices_wIP/telephone.png') no-repeat; +[itemlook="copier-west"] { + background: url('images/electricalDevices_wIP/copier-west.png') no-repeat; +} - } +[itemlook="copier-north"] { + background: url('images/electricalDevices_wIP/copier-north.png') no-repeat; +} -[itemlook="flatscreen"] { - background: url('images/electricalDevices_woIP/flatscreen.png') no-repeat; +[itemlook="printer-east"] { + background: url('images/electricalDevices_wIP/printer-east.png') no-repeat; +} - } +[itemlook="printer-south"] { + background: url('images/electricalDevices_wIP/printer-south.png') no-repeat; +} -[itemlook="lamp"] { - background: url('images/electricalDevices_woIP/lamp.png') no-repeat; +[itemlook="printer-west"] { + background: url('images/electricalDevices_wIP/printer-west.png') no-repeat; +} - } +[itemlook="printer-north"] { + background: url('images/electricalDevices_wIP/printer-north.png') no-repeat; +} -[itemlook="tvcamera"] { - background: url('images/electricalDevices_woIP/tvcamera.png') no-repeat; +[itemlook="telephone-east"] { + background: url('images/electricalDevices_wIP/telephone-east.png') no-repeat; +} - } +[itemlook="telephone-south"] { + background: url('images/electricalDevices_wIP/telephone-south.png') no-repeat; +} + +[itemlook="telephone-west"] { + background: url('images/electricalDevices_wIP/telephone-west.png') no-repeat; +} + +[itemlook="telephone-north"] { + background: url('images/electricalDevices_wIP/telephone-north.png') no-repeat; +} + + +[itemlook="flatscreen-east"] { + background: url('images/electricalDevices_woIP/flatscreen-east.png') no-repeat; +} + +[itemlook="flatscreen-south"] { + background: url('images/electricalDevices_woIP/flatscreen-south.png') no-repeat; +} + +[itemlook="flatscreen-west"] { + background: url('images/electricalDevices_woIP/flatscreen-west.png') no-repeat; +} + +[itemlook="flatscreen-north"] { + background: url('images/electricalDevices_woIP/flatscreen-north.png') no-repeat; +} + +[itemlook="lamp-east"] { + background: url('images/electricalDevices_woIP/lamp-east.png') no-repeat; +} + +[itemlook="lamp-south"] { + background: url('images/electricalDevices_woIP/lamp-south.png') no-repeat; +} + +[itemlook="lamp-west"] { + background: url('images/electricalDevices_woIP/lamp-west.png') no-repeat; +} + +[itemlook="lamp-north"] { + background: url('images/electricalDevices_woIP/lamp-north.png') no-repeat; +} + +[itemlook="tvcamera-east"] { + background: url('images/electricalDevices_woIP/tvcamera-east.png') no-repeat; +} + +[itemlook="tvcamera-south"] { + background: url('images/electricalDevices_woIP/tvcamera-south.png') no-repeat; +} + +[itemlook="tvcamera-west"] { + background: url('images/electricalDevices_woIP/tvcamera-west.png') no-repeat; +} + +[itemlook="tvcamera-north"] { + background: url('images/electricalDevices_woIP/tvcamera-north.png') no-repeat; +} [itemlook="4chairs1squaretable"] { background: url('images/furniture/4chairs1squaretable.png') no-repeat; diff --git a/modules-available/roomplanner/templates/item-selector.html b/modules-available/roomplanner/templates/item-selector.html index 6bc226cb..f4680cf1 100644 --- a/modules-available/roomplanner/templates/item-selector.html +++ b/modules-available/roomplanner/templates/item-selector.html @@ -90,15 +90,15 @@ data-height="100" data-width="100" title="PC" noresize=1></div> </li> <li> - <div itemtype="pc" itemlook="copier" class="draggable" style="width:100px; height:100px;" + <div itemtype="pc" itemlook="copier-south" class="draggable" style="width:100px; height:100px;" data-height="100" data-width="100" title="{{lang_photocopier}}" noresize=1></div> </li> <li> - <div itemtype="pc" itemlook="printer" class="draggable" style="width:100px; height:100px;" + <div itemtype="pc" itemlook="printer-south" class="draggable" style="width:100px; height:100px;" data-height="100" data-width="100" title="{{lang_printer}}" noresize=1></div> </li> <li> - <div itemtype="pc" itemlook="telephone" class="draggable" style="width:100px; height:100px;" + <div itemtype="pc" itemlook="telephone-south" class="draggable" style="width:100px; height:100px;" data-height="100" data-width="100" title="{{lang_telephone}}" noresize=1></div> </li> </ul> @@ -107,15 +107,15 @@ <div role="tabpanel" class="tab-pane" id="electricaldevices"> <ul class="toollist"> <li> - <div itemtype="furniture" itemlook="flatscreen" class="draggable" style="width:75px; height:100px;" + <div itemtype="furniture" itemlook="flatscreen-east" class="draggable" style="width:75px; height:100px;" data-height="100" data-width="75" title="{{lang_flatscreen}}"></div> </li> <li> - <div itemtype="furniture" itemlook="lamp" class="draggable" style="width:125px; height:50px;" + <div itemtype="furniture" itemlook="lamp-east" class="draggable" style="width:125px; height:50px;" data-height="50" data-width="125" title="{{lang_deskLamp}}"></div> </li> <li> - <div itemtype="furniture" itemlook="tvcamera" class="draggable" style="width:125px; height:50px;" + <div itemtype="furniture" itemlook="tvcamera-east" class="draggable" style="width:125px; height:50px;" data-height="50" data-width="125" title="{{lang_projector}}"></div> </li> </ul> diff --git a/modules-available/roomplanner/templates/svg-plan.html b/modules-available/roomplanner/templates/svg-plan.html index a2ecd5a7..c75e01f8 100644 --- a/modules-available/roomplanner/templates/svg-plan.html +++ b/modules-available/roomplanner/templates/svg-plan.html @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" @@ -18,9 +17,17 @@ stroke-width: .2; fill: url(#screen); } - rect.hl { + g.hl rect.scrn { fill: url(#screenhl); } + g.muted rect.scrn { + fill: url(#muted); + stroke: #777; + } + g.muted rect.kb { + fill: #eee; + stroke: #777; + } ]]> </style> <defs> @@ -32,13 +39,20 @@ <stop offset="0%" stop-color="#afa" /> <stop offset="100%" stop-color="#074" /> </radialGradient> + <radialGradient id="muted" cx=".4" cy=".3" r="1"> + <stop offset="0%" stop-color="#fff" /> + <stop offset="100%" stop-color="#999" /> + </radialGradient> </defs> <g transform="scale({{scale}}) rotate({{rotate}} {{centerX}} {{centerY}})"> <line x1="0" y1="{{line.y}}" x2="{{line.x}}" y2="{{line.y}}" style="stroke:#555;stroke-width:.2;opacity:.5" /> {{#machines}} - <g transform="translate({{gridCol}} {{gridRow}})"> + {{#links}} + <a xlink:href="./?do=statistics&uuid={{machineuuid}}"> + {{/links}} + <g transform="translate({{gridCol}} {{gridRow}})" class="{{class}}"> <rect transform="rotate({{rotation}} 1.9 1.9)" x=".1" y="2.6" @@ -52,9 +66,11 @@ ry=".4" height="2.2" width="3.4" - class="scrn {{class}}" - /> + class="scrn" /> </g> + {{#links}} + </a> + {{/links}} {{/machines}} </g> </svg> |