diff options
Diffstat (limited to 'modules-available/remoteaccess')
12 files changed, 334 insertions, 63 deletions
diff --git a/modules-available/remoteaccess/api.inc.php b/modules-available/remoteaccess/api.inc.php index 2e1e4bf9..c558d126 100644 --- a/modules-available/remoteaccess/api.inc.php +++ b/modules-available/remoteaccess/api.inc.php @@ -5,27 +5,47 @@ if (substr($ip, 0, 7) === '::ffff:') $ip = substr($ip, 7); $password = Request::post('password', false, 'string'); if ($password !== false) { - $c = Database::queryFirst("SELECT machineuuid FROM machine WHERE clientip = :ip", ['ip' => $ip]); + $c = Database::queryFirst("SELECT machineuuid FROM machine + WHERE clientip = :ip + ORDER BY lastseen DESC + LIMIT 1", ['ip' => $ip]); if ($c !== false) { - Database::exec("INSERT INTO remoteaccess_machine (machineuuid, password) - VALUES (:uuid, :passwd) - ON DUPLICATE KEY UPDATE password = VALUES(password)", ['uuid' => $c['machineuuid'], 'passwd' => $password]); + $vncport = Request::post('vncport', 5900, 'int'); + Database::exec("INSERT INTO remoteaccess_machine (machineuuid, password, vncport) + VALUES (:uuid, :passwd, :vncport) + ON DUPLICATE KEY UPDATE + password = VALUES(password), vncport = VALUES(vncport)", + ['uuid' => $c['machineuuid'], 'passwd' => $password, 'vncport' => $vncport]); } exit; } $range = IpUtil::parseCidr(Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET)); -if ($range === false) { +if ($range === null) { die('No allowed IP defined'); } $iplong = ip2long($ip); -if (PHP_INT_SIZE === 4) { - $iplong = sprintf('%u', $iplong); -} if ($iplong < $range['start'] || $iplong > $range['end']) { die('Access denied'); } +$headers = getallheaders(); +$version = false; +if (!empty($headers['Bwlp-Plugin-Build-Revision'])) { + $version = substr($headers['Bwlp-Plugin-Build-Revision'], 0, 6); + if (!empty($headers['Bwlp-Plugin-Build-Timestamp'])) { + $ts = $headers['Bwlp-Plugin-Build-Timestamp']; + if (is_numeric($ts)) { + if ($ts > 9999999999) { + $ts = round($ts / 1000); + } + $ts = date('d.m.Y H:i', $ts); + } + $version .= ' (' . $ts . ')'; + } +} +Property::set(RemoteAccess::PROP_PLUGIN_VERSION, $version, 2880); + Header('Content-Type: application/json'); $remoteLocations = RemoteAccess::getEnabledLocations(); @@ -35,7 +55,7 @@ if (empty($remoteLocations)) { } else { // TODO fail-counter for WOL, so we can ignore machines that apparently can't be woken up // -> Reset counter in our ~poweron hook, but only if the time roughly matches a WOL attempt (within ~5 minutes) - $rows = Database::queryAll("SELECT m.clientip, m.locationid, m.state, ram.password, ram.woltime FROM machine m + $rows = Database::queryAll("SELECT m.clientip, m.locationid, m.state, ram.password, ram.vncport, ram.woltime FROM machine m LEFT JOIN remoteaccess_machine ram ON (ram.machineuuid = m.machineuuid AND (ram.password IS NOT NULL OR m.state <> 'IDLE')) LEFT JOIN runmode r ON (r.machineuuid = m.machineuuid) WHERE m.locationid IN (:locs) @@ -48,6 +68,7 @@ if (empty($remoteLocations)) { $row['wol_in_progress'] = true; } settype($row['locationid'], 'int'); + settype($row['vncport'], 'int'); unset($row['woltime']); } } diff --git a/modules-available/remoteaccess/baseconfig/getconfig.inc.php b/modules-available/remoteaccess/baseconfig/getconfig.inc.php index 2ebc97cb..182daef1 100644 --- a/modules-available/remoteaccess/baseconfig/getconfig.inc.php +++ b/modules-available/remoteaccess/baseconfig/getconfig.inc.php @@ -1,18 +1,50 @@ <?php -// Locations from closest to furthest (order) -$locationId = ConfigHolder::get('SLX_LOCATIONS'); -if ($locationId !== false) { +/** @var ?string $uuid */ +/** @var ?string $ip */ + +if ($uuid !== null) { + // Leave clients in any runmode alone + $res = Database::queryFirst('SELECT machineuuid FROM runmode WHERE machineuuid = :uuid', + ['uuid' => $uuid], true); + if (is_array($res)) + return; + + // Locations from closest to furthest (order) + $locationId = ConfigHolder::get('SLX_LOCATIONS'); + if ($locationId === null) + return; $locationId = (int)$locationId; - $ret = Database::queryFirst("SELECT locationid FROM remoteaccess_x_location WHERE locationid = :lid", + $ret = Database::queryFirst("SELECT l.locationid FROM remoteaccess_x_location l + INNER JOIN remoteaccess_group g USING (groupid) + WHERE locationid = :lid AND g.active = 1", ['lid' => $locationId], true); // TODO Remove true after next point release (2020-05-12) - if ($ret !== false) { - // TODO Properly merge - if (Property::get(RemoteAccess::PROP_TRY_VIRT_HANDOVER)) { - ConfigHolder::add("SLX_REMOTE_VNC", 'vmware virtualbox'); - } else { - ConfigHolder::add("SLX_REMOTE_VNC", 'x11vnc'); - } - ConfigHolder::add("SLX_REMOTE_HOST_ACCESS", Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET)); + if ($ret === false) + return; + // Special case – location admin can limit accessibility of this machine to never, or only when room is closed + $opts = Scheduler::getLocationOptions($locationId); + if ($opts['ra-mode'] === Scheduler::RA_NEVER) + return; // Completely disallowed + if ($opts['ra-mode'] === Scheduler::RA_SELECTIVE) { + // Only when room is closed + if (OpeningTimes::isRoomOpen($locationId, $opts['wol-offset'], $opts['sd-offset'])) + return; // Open, do not interfere with ongoing lectures etc., do nothing + } + // TODO Properly merge + if (Property::get(RemoteAccess::PROP_TRY_VIRT_HANDOVER)) { + ConfigHolder::add("SLX_REMOTE_VNC", 'vmware virtualbox'); + } else { + ConfigHolder::add("SLX_REMOTE_VNC", 'x11vnc'); + } + ConfigHolder::add("SLX_REMOTE_HOST_ACCESS", Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET)); + ConfigHolder::add('SLX_REMOTE_VNC_PORT', Property::get(RemoteAccess::PROP_VNC_PORT, 5900)); + ConfigHolder::add('SLX_RUNMODE_MODULE', 'remoteaccess'); + // No saver + $saverTimeout = ConfigHolder::get('SLX_SCREEN_SAVER_TIMEOUT'); + if (!is_numeric($saverTimeout) || $saverTimeout < 1800) { + ConfigHolder::add('SLX_SCREEN_SAVER_TIMEOUT', '1800', 1000); } + ConfigHolder::add('SLX_SCREEN_SAVER_GRACE_TIME', '86400', 1000); + // Autologin will never work as the machine is immediately in use and will never get assigned + ConfigHolder::add('SLX_AUTOLOGIN', 'OFF', 10000); } diff --git a/modules-available/remoteaccess/inc/remoteaccess.inc.php b/modules-available/remoteaccess/inc/remoteaccess.inc.php index 37d33d45..95ca3821 100644 --- a/modules-available/remoteaccess/inc/remoteaccess.inc.php +++ b/modules-available/remoteaccess/inc/remoteaccess.inc.php @@ -7,14 +7,32 @@ class RemoteAccess const PROP_TRY_VIRT_HANDOVER = 'remoteaccess.virthandover'; - public static function getEnabledLocations($group = 0) + const PROP_VNC_PORT = 'remoteaccess.vncport'; + + const PROP_PLUGIN_VERSION = 'remoteaccess.plugin-version'; + + /** + * Get a list of locationIds where remote access is enabled. If $filterOverridden is true, + * the list will not contain any locations where remote access is disabled via location override. + * @param int $group Group to get locations for, or '0' for all locations + * @param bool $filterOverridden iff true, remove any locations where remote access is currently disabled + */ + public static function getEnabledLocations(int $group = 0, bool $filterOverridden = true): array { if ($group === 0) { - return Database::queryColumnArray("SELECT DISTINCT rxl.locationid FROM remoteaccess_x_location rxl + $list = Database::queryColumnArray("SELECT DISTINCT rxl.locationid FROM remoteaccess_x_location rxl INNER JOIN remoteaccess_group g ON (g.groupid = rxl.groupid AND g.active = 1)"); - } - return Database::queryColumnArray("SELECT DISTINCT locationid FROM remoteaccess_x_location + } else { + $list = Database::queryColumnArray("SELECT DISTINCT locationid FROM remoteaccess_x_location WHERE groupid = :gid", ['gid' => $group]); + } + if (!$filterOverridden || !Module::isAvailable('rebootcontrol')) + return $list; + return array_filter($list, function (int $lid) { + $mode = Scheduler::getLocationOptions($lid)['ra-mode']; + return ($mode !== Scheduler::RA_NEVER + && ($mode !== Scheduler::RA_SELECTIVE || !OpeningTimes::isRoomOpen($lid, 5, 5))); + }); } public static function ensureMachinesRunning() @@ -24,41 +42,58 @@ class RemoteAccess return; } - $res = Database::simpleQuery("SELECT rg.groupid, rg.groupname, rg.wolcount, GROUP_CONCAT(rxl.locationid) AS locs FROM remoteaccess_group rg + $res = Database::simpleQuery("SELECT rg.groupid, rg.groupname, rg.wolcount, + GROUP_CONCAT(rxl.locationid) AS locs + FROM remoteaccess_group rg INNER JOIN remoteaccess_x_location rxl USING (groupid) WHERE rg.active = 1 GROUP BY groupid"); // Consider machines we tried to wake in the past 90 seconds as online $wolDeadline = time() - 90; - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - if ($row['wolcount'] <= 0) - continue; + foreach ($res as $row) { + $wantNum = $row['wolcount']; // This can't really be anything but a CSV list, but better be safe $locs = preg_replace('/[^0-9,]/', '', $row['locs']); - if (empty($locs)) - continue; - $active = Database::queryFirst("SELECT Count(*) AS cnt FROM machine m + if (!empty($locs)) { + // Filter out locations for which remote-access is disabled + $locArray = explode(',', $locs); + $locArray = array_filter($locArray, function (int $lid) { + $mode = Scheduler::getLocationOptions($lid)['ra-mode']; + return ($mode !== Scheduler::RA_NEVER + && ($mode !== Scheduler::RA_SELECTIVE || !OpeningTimes::isRoomOpen($lid, 5, 5))); + }); + $locs = implode(',', $locArray); + } + if ($wantNum > 0 && !empty($locs)) { + $active = Database::queryFirst("SELECT Count(*) AS cnt FROM machine m INNER JOIN remoteaccess_machine rm USING (machineuuid) WHERE m.locationid IN ($locs) AND (m.state = 'IDLE' OR rm.woltime > $wolDeadline)"); - $active = (isset($active['cnt']) ? $active['cnt'] : 0); - $wantNum = $row['wolcount'] - $active; - if ($wantNum <= 0) - continue; - self::tryWakeMachines($locs, $wantNum); + $active = ($active['cnt'] ?? 0); + $wantNum -= $active; + } + if ($wantNum > 0) { + $numFailed = self::tryWakeMachines($locs, $wantNum); + } else { + $numFailed = 0; + } + Database::exec("UPDATE remoteaccess_group SET unwoken = :num WHERE groupid = :groupid", + ['num' => $numFailed, 'groupid' => $row['groupid']]); } } - private static function tryWakeMachines($locs, $num) + private static function tryWakeMachines(string $locs, int $num): int { - $res = Database::simpleQuery("SELECT m.machineuuid, m.macaddr, m.clientip FROM machine m + if (empty($locs)) + return $num; + $res = Database::simpleQuery("SELECT m.machineuuid, m.macaddr, m.clientip, m.locationid FROM machine m LEFT JOIN remoteaccess_machine rm USING (machineuuid) WHERE m.locationid IN ($locs) AND m.state IN ('OFFLINE', 'STANDBY') ORDER BY rm.woltime ASC"); $NOW = time(); while ($num > 0) { $list = []; - for ($i = 0; $i < $num && $row = $res->fetch(PDO::FETCH_ASSOC); ++$i) { + for ($i = 0; $i < $num && ($row = $res->fetch()); ++$i) { $list[] = $row; Database::exec("INSERT INTO remoteaccess_machine (machineuuid, password, woltime) VALUES (:uuid, NULL, :now) @@ -68,7 +103,7 @@ class RemoteAccess if (empty($list)) break; // No more clients in this location RebootControl::wakeMachines($list, $fails); - $num -= count($list) - count($fails); + $num -= (count($list) - count($fails)); if (!empty($fails)) { $failIds = ArrayUtil::flattenByKey($fails, 'machineuuid'); // Reduce time so they won't be marked as wol_in_progress @@ -76,9 +111,7 @@ class RemoteAccess ['faketime' => $NOW - 95, 'fails' => $failIds]); } } - if ($num > 0) { - error_log("Could not wake $num clients in ($locs)..."); - } + return $num; } } diff --git a/modules-available/remoteaccess/install.inc.php b/modules-available/remoteaccess/install.inc.php index 11656218..2a6fec36 100644 --- a/modules-available/remoteaccess/install.inc.php +++ b/modules-available/remoteaccess/install.inc.php @@ -8,6 +8,7 @@ $dbret[] = tableCreate('remoteaccess_group', " `wolcount` smallint(11) NOT NULL, `passwd` varchar(100) NOT NULL, `active` tinyint(1) UNSIGNED NOT NULL DEFAULT '1', + `unwoken` int(10) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`groupid`) "); @@ -21,6 +22,7 @@ $dbret[] = tableCreate('remoteaccess_machine', " `machineuuid` char(36) CHARACTER SET ascii NOT NULL, `password` char(8) CHARACTER SET ascii NULL DEFAULT NULL, `woltime` int(10) UNSIGNED NOT NULL DEFAULT '0', + `vncport` smallint(5) UNSIGNED NOT NULL DEFAULT '5900', PRIMARY KEY (`machineuuid`) "); @@ -57,4 +59,22 @@ if (tableExists('remoteaccess_location') Database::exec("DROP TABLE remoteaccess_location"); } +// 2021-03-05: Add vncport column to machine table +if (!tableHasColumn('remoteaccess_machine', 'vncport')) { + $ret = Database::exec("ALTER TABLE remoteaccess_machine ADD COLUMN `vncport` smallint(5) UNSIGNED NOT NULL DEFAULT '5900'"); + if ($ret === false) { + finalResponse(UPDATE_FAILED, Database::lastError()); + } + $dbret[] = UPDATE_DONE; +} + +// 2022-06-01 Unwoken machines: Keeps track of how many machines could not be WOLed +if (!tableHasColumn('remoteaccess_group', 'unwoken')) { + $ret = Database::exec("ALTER TABLE remoteaccess_group ADD COLUMN `unwoken` int(10) UNSIGNED NOT NULL DEFAULT '0'"); + if ($ret === false) { + finalResponse(UPDATE_FAILED, Database::lastError()); + } + $dbret[] = UPDATE_DONE; +} + responseFromArray($dbret); diff --git a/modules-available/remoteaccess/lang/de/template-tags.json b/modules-available/remoteaccess/lang/de/template-tags.json index a5d9ef07..1a502a6b 100644 --- a/modules-available/remoteaccess/lang/de/template-tags.json +++ b/modules-available/remoteaccess/lang/de/template-tags.json @@ -3,15 +3,25 @@ "lang_allowAccessText": "IP-Adresse oder Netz in CIDR Notation, welches auf den VNC-Port des Clients zugreifen darf. (I.d.R. nur der Guacamole-Server)", "lang_allowedAccessToVncPort": "Erlaubte Quelle f\u00fcr VNC-Zugriff", "lang_assignLocations": "R\u00e4ume zuweisen", + "lang_clientVncPort": "VNC Port (Client)", "lang_general": "Allgemein", "lang_group": "Gruppe", "lang_groupListText": "Liste verf\u00fcgbarer Gruppen (\"virtuelle R\u00e4ume\")", "lang_groups": "Gruppen", "lang_keepAvailableWol": "WoL#", + "lang_location": "Ort", "lang_locationSelectionText": "Ausgew\u00e4hlte Orte werden in den Remote-Modus geschaltet (beim n\u00e4chsten Boot des Clients) und sind damit im Pool f\u00fcr den Fernzugriff.", + "lang_locations": "Konfigurierte Orte", + "lang_locationsInUse": "Liste der Orte, die in mindestens einer Gruppe verwendet werden", "lang_numLocs": "R\u00e4ume", + "lang_pluginVersion": "Plugin-Version", + "lang_pluginVersionOldOrUnknown": "Unbekannt oder zu alt", "lang_reallyDelete": "Wirklich l\u00f6schen?", "lang_remoteAccessSettings": "Einstellungen f\u00fcr den Fernzugriff", + "lang_roomRemoteAccessDisabled": "Zugriff f\u00fcr diesen Raum generell deaktiviert", + "lang_roomRemoteAccessWhenClosed": "Zugriff f\u00fcr diesen Raum deaktiviert, solange er laut \u00d6ffnungszeiten offen ist", "lang_tryVirtualizerHandover": "Versuche, VNC-Server des Virtualisierers zu verwenden", - "lang_tryVirtualizerText": "Wenn aktiviert wird versucht, nach dem Start einer VM die Verbindung auf den VNC-Server des Virtualisierers umzubuchen. Zumindest f\u00fcr VMware haben wir hier allerdings eher eine Verschlechterung der Performance beobachten k\u00f6nnen; au\u00dferdem bricht die Verbindung beim Handover manchmal ab -> Nur experimentell!" + "lang_tryVirtualizerText": "Wenn aktiviert wird versucht, nach dem Start einer VM die Verbindung auf den VNC-Server des Virtualisierers umzubuchen. Zumindest f\u00fcr VMware haben wir hier allerdings eher eine Verschlechterung der Performance beobachten k\u00f6nnen; au\u00dferdem bricht die Verbindung beim Handover manchmal ab -> Nur experimentell!", + "lang_vncPortText": "Port, auf dem die Clients auf VNC-Verbindungen warten. Bei Verwendung eines Ports ungleich 5900 bitte sicherstellen, dass das aktuelle Guacamole-Plugin verwendet wird.", + "lang_wolFailCount": "Anzahl erfolgloser WoL-Versuche" }
\ No newline at end of file diff --git a/modules-available/remoteaccess/lang/en/messages.json b/modules-available/remoteaccess/lang/en/messages.json new file mode 100644 index 00000000..15b7e06c --- /dev/null +++ b/modules-available/remoteaccess/lang/en/messages.json @@ -0,0 +1,8 @@ +{ + "group-added": "Group added", + "group-deleted": "Group {{0}} deleted", + "group-not-found": "Group {{0}} does not exist", + "group-updated": "Group {{0}} updated", + "locations-not-allowed": "You don't have permission to view some locations in group {{0}} ", + "settings-saved": "Settings saved" +}
\ No newline at end of file diff --git a/modules-available/remoteaccess/lang/en/module.json b/modules-available/remoteaccess/lang/en/module.json new file mode 100644 index 00000000..308aeb15 --- /dev/null +++ b/modules-available/remoteaccess/lang/en/module.json @@ -0,0 +1,4 @@ +{ + "module_name": "Remoteaccess", + "page_title": "Remoteaccess" +}
\ No newline at end of file diff --git a/modules-available/remoteaccess/lang/en/permissions.json b/modules-available/remoteaccess/lang/en/permissions.json new file mode 100644 index 00000000..e90ce398 --- /dev/null +++ b/modules-available/remoteaccess/lang/en/permissions.json @@ -0,0 +1,7 @@ +{ + "group.add": "Add new group", + "group.edit": "Edit or delete a group", + "group.locations": "Assign rooms to a group", + "set-proxy-ip": "Set allowed proxy IP(-Range)", + "view": "View page" +}
\ No newline at end of file diff --git a/modules-available/remoteaccess/lang/en/template-tags.json b/modules-available/remoteaccess/lang/en/template-tags.json new file mode 100644 index 00000000..037550e4 --- /dev/null +++ b/modules-available/remoteaccess/lang/en/template-tags.json @@ -0,0 +1,27 @@ +{ + "lang_add": "Add", + "lang_allowAccessText": "IP address (or net in CIDR notation) which is allowed to access the VNC port of the clients (usually only the guacamole proxy-server)", + "lang_allowedAccessToVncPort": "Allowed source for VNC-access", + "lang_assignLocations": "Assing locations", + "lang_clientVncPort": "VNC port (client)", + "lang_general": "General", + "lang_group": "Group", + "lang_groupListText": "Available groups (\"virtual locations\")", + "lang_groups": "Groups", + "lang_keepAvailableWol": "WoL#", + "lang_location": "Location", + "lang_locationSelectionText": "Clients in the selected locations will start the remoteaccess-mode after the next reboot.", + "lang_locations": "Configured locations", + "lang_locationsInUse": "List of locations that are active in at least one group", + "lang_numLocs": "Locations", + "lang_pluginVersion": "Plugin version", + "lang_pluginVersionOldOrUnknown": "Unknown or too old", + "lang_reallyDelete": "Delete?", + "lang_remoteAccessSettings": "Settings for remoteaccess", + "lang_roomRemoteAccessDisabled": "Remote access for this room is disabled via override", + "lang_roomRemoteAccessWhenClosed": "Remote access for this room is disabled while the room is open (according to its schedule)", + "lang_tryVirtualizerHandover": "Try to use VNC-server of the hypervisor", + "lang_tryVirtualizerText": "If activated the system tries to change the remote VNC-connection to the internal VNC-server of the hypervisor after VM start.\r\nAt least in the case of VMware it seems to reduce performance and sometimes the connection during handover is lost.\r\n-> Just experimental!", + "lang_vncPortText": "Port on which clients will wait for VNC connections. Please make sure you're running the latest version of the Guacamole plugin when changing this to something other than 5900.", + "lang_wolFailCount": "Number of unsuccesful WoL attempts" +}
\ No newline at end of file diff --git a/modules-available/remoteaccess/page.inc.php b/modules-available/remoteaccess/page.inc.php index 68781ffa..ba248b4d 100644 --- a/modules-available/remoteaccess/page.inc.php +++ b/modules-available/remoteaccess/page.inc.php @@ -29,10 +29,10 @@ class Page_RemoteAccess extends Page Database::exec("UPDATE remoteaccess_group SET groupname = :name, wolcount = :wol, passwd = :passwd, active = :active WHERE groupid = :id", [ 'id' => $id, - 'name' => isset($group['groupname']) ? $group['groupname'] : $id, - 'wol' => isset($group['wolcount']) ? $group['wolcount'] : 0, - 'passwd' => isset($group['passwd']) ? $group['passwd'] : 0, - 'active' => isset($group['active']) && $group['active'] ? 1 : 0, + 'name' => $group['groupname'] ?? $id, + 'wol' => $group['wolcount'] ?? 0, + 'passwd' => $group['passwd'] ?? 0, + 'active' => (int)($group['active'] ?? 0), ]); } Message::addSuccess('settings-saved'); @@ -40,6 +40,7 @@ class Page_RemoteAccess extends Page User::assertPermission('set-proxy-ip'); Property::set(RemoteAccess::PROP_ALLOWED_VNC_NET, Request::post('allowed-source', '', 'string')); Property::set(RemoteAccess::PROP_TRY_VIRT_HANDOVER, Request::post('virt-handover', false, 'int')); + Property::set(RemoteAccess::PROP_VNC_PORT, Request::post('vncport', 5900, 'int')); Message::addSuccess('settings-saved'); } elseif ($action === 'delete-group') { User::assertPermission('group.edit'); @@ -91,28 +92,62 @@ class Page_RemoteAccess extends Page if ($groupid === false) { // Edit list of groups and their settings $groups = Database::queryAll("SELECT g.groupid, g.groupname, g.wolcount, g.passwd, - Count(l.locationid) AS locs, If(g.active, 'checked', '') AS checked - FROM remoteaccess_group g LEFT JOIN remoteaccess_x_location l USING (groupid) + Count(l.locationid) AS locs, If(g.active, 'checked', '') AS checked, unwoken + FROM remoteaccess_group g + LEFT JOIN remoteaccess_x_location l USING (groupid) GROUP BY g.groupid, g.groupname ORDER BY g.groupname ASC"); $data = [ 'allowed-source' => Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET), 'virt-handover_checked' => Property::get(RemoteAccess::PROP_TRY_VIRT_HANDOVER) ? 'checked' : '', + 'vncport' => Property::get(RemoteAccess::PROP_VNC_PORT, 5900), 'groups' => $groups, ]; + $data['plugin_version'] = Property::get(RemoteAccess::PROP_PLUGIN_VERSION); Permission::addGlobalTags($data['perms'], null, ['group.locations', 'group.add', 'group.edit', 'set-proxy-ip']); + // List of locations used in at least one group + $res = Database::simpleQuery("SELECT l.locationid, l.locationname, g.groupid, g.groupname, g.active + FROM location l + INNER JOIN remoteaccess_x_location rxl USING (locationid) + INNER JOIN remoteaccess_group g USING (groupid) + ORDER BY locationname, locationid"); + $data['locations'] = []; + $last = null; + foreach ($res as $row) { + if ($last === null || $last['locationid'] !== $row['locationid']) { + unset($last); + $last = [ + 'locationid' => $row['locationid'], + 'locationname' => $row['locationname'], + 'lclass' => 'slx-strike', + 'groups' => [], + ]; + $data['locations'][] =& $last; + } + $last['groups'][] = [ + 'groupid' => $row['groupid'], + 'groupname' => $row['groupname'], + 'gclass' => $row['active'] ? '' : 'slx-strike', + ]; + if ($row['active']) { + $last['lclass'] = ''; + } + } + unset($last); + $this->addSchedulerTags($data['locations']); Render::addTemplate('edit-settings', $data); } else { // Edit locations for group $group = $this->groupNameOrFail($groupid); $locationList = Location::getLocationsAssoc(); - $enabled = RemoteAccess::getEnabledLocations($groupid); + $enabled = RemoteAccess::getEnabledLocations($groupid, false); $allowed = User::getAllowedLocations('group.locations'); foreach ($enabled as $lid) { if (isset($locationList[$lid])) { $locationList[$lid]['checked'] = 'checked'; } } + $this->addSchedulerTags($locationList); foreach ($locationList as $lid => &$loc) { if (!in_array($lid, $allowed)) { $loc['disabled'] = 'disabled'; @@ -133,7 +168,7 @@ class Page_RemoteAccess extends Page * @param int $groupid group to check * @return bool if we have permission for all the locations assigned to group */ - private function checkGroupLocations($groupid) + private function checkGroupLocations(int $groupid): bool { $allowed = User::getAllowedLocations('group.locations'); if (in_array(0, $allowed)) @@ -144,4 +179,18 @@ class Page_RemoteAccess extends Page return empty($diff); } + private function addSchedulerTags(array &$locationList) + { + if (!Module::isAvailable('rebootcontrol')) + return; + foreach ($locationList as $lid => &$loc) { + $options = Scheduler::getLocationOptions($loc['locationid'] ?? $lid); + if ($options['ra-mode'] === Scheduler::RA_SELECTIVE) { + $loc['ra_selective'] = true; + } elseif ($options['ra-mode'] === Scheduler::RA_NEVER) { + $loc['ra_never'] = true; + } + } + } + } diff --git a/modules-available/remoteaccess/templates/edit-group.html b/modules-available/remoteaccess/templates/edit-group.html index 0f09f071..93fa66be 100644 --- a/modules-available/remoteaccess/templates/edit-group.html +++ b/modules-available/remoteaccess/templates/edit-group.html @@ -30,9 +30,17 @@ <label></label> </div> </td> - <td class="text-nowrap"> + <td class="slx-smallcol text-nowrap"> <div style="display:inline-block;width:{{depth}}em"></div> <label for="loc-check-{{locationid}}" class="{{disabled}}">{{locationname}}</label> + </td> + <td> + {{#ra_never}} + <span class="glyphicon glyphicon-remove text-danger" title="{{lang_roomRemoteAccessDisabled}}"></span> + {{/ra_never}} + {{#ra_selective}} + <span class="glyphicon glyphicon-time text-danger" title="{{lang_roomRemoteAccessWhenClosed}}"></span> + {{/ra_selective}} </td> </tr> {{/locations}} diff --git a/modules-available/remoteaccess/templates/edit-settings.html b/modules-available/remoteaccess/templates/edit-settings.html index 3c890b91..4c4c011a 100644 --- a/modules-available/remoteaccess/templates/edit-settings.html +++ b/modules-available/remoteaccess/templates/edit-settings.html @@ -4,13 +4,29 @@ <form method="post" action="?do=remoteaccess"> <input type="hidden" name="token" value="{{token}}"> - <div class="form-group"> - <label> - {{lang_allowedAccessToVncPort}} - <input type="text" class="form-control" name="allowed-source" value="{{allowed-source}}" - required {{perms.set-proxy-ip.disabled}}> - </label> - <p>{{lang_allowAccessText}}</p> + <div class="row"> + <div class="form-group col-md-6"> + <label> + {{lang_allowedAccessToVncPort}} + <input type="text" class="form-control" name="allowed-source" value="{{allowed-source}}" + required {{perms.set-proxy-ip.disabled}}> + </label> + <p>{{lang_allowAccessText}}</p> + </div> + <div class="form-group col-md-6"> + <label> + {{lang_clientVncPort}} + <input type="number" class="form-control" name="vncport" value="{{vncport}}" min="1025" max="65535" + required {{perms.set-proxy-ip.disabled}}> + </label> + <p>{{lang_vncPortText}}</p> + <div class="text-right"> + {{lang_pluginVersion}}: {{plugin_version}} + {{^plugin_version}} + {{lang_pluginVersionOldOrUnknown}} + {{/plugin_version}} + </div> + </div> </div> <div class="form-group"> <div class="checkbox"> @@ -64,9 +80,14 @@ <span class="glyphicon glyphicon-edit"></span> </a> </td> - <td> + <td class="input-group"> <input type="number" class="form-control" name="group[{{groupid}}][wolcount]" value="{{wolcount}}" {{perms.group.edit.disabled}}> + {{#unwoken}} + <span class="input-group-addon" title="{{lang_wolFailCount}}"> + <span class="glyphicon glyphicon-remove"></span>{{unwoken}} + </span> + {{/unwoken}} </td> <td> <input type="text" class="form-control" name="group[{{groupid}}][passwd]" value="{{passwd}}" @@ -87,4 +108,35 @@ </button> </div> <div class="clearfix"></div> -</form>
\ No newline at end of file +</form> + +<h3>{{lang_locations}}</h3> + +<p>{{lang_locationsInUse}}</p> + +<table class="table"> + <thead> + <tr> + <th>{{lang_location}}</th> + <th>{{lang_groups}}</th> + </tr> + </thead> + <tbody> + {{#locations}} + <tr> + <td class="{{lclass}}"> + {{locationname}} + {{#ra_never}} + <span class="glyphicon glyphicon-remove text-danger" title="{{lang_roomRemoteAccessDisabled}}"></span> + {{/ra_never}} + {{#ra_selective}} + <span class="glyphicon glyphicon-time text-danger" title="{{lang_roomRemoteAccessWhenClosed}}"></span> + {{/ra_selective}} + </td> + <td>{{#groups}} + [<a class="{{gclass}}" href="?do=remoteaccess&groupid={{groupid}}">{{groupname}}</a>] + {{/groups}}</td> + </tr> + {{/locations}} + </tbody> +</table>
\ No newline at end of file |