summaryrefslogtreecommitdiffstats
path: root/modules-available/locations
diff options
context:
space:
mode:
authorroot2019-02-19 18:53:50 +0100
committerroot2019-02-19 18:53:50 +0100
commit0ad4c0f8196b61699754762aacbaab0223478ab9 (patch)
treede434c4aea8d07ecd01cd3badd48d057d62c2d1b /modules-available/locations
parent[usb-lock-off] Edit rule cleanup and fix of the dropdown boxes. (diff)
parent[statistics] Fix RAM change warning to handle increase too (diff)
downloadslx-admin-usb-lock-off.tar.gz
slx-admin-usb-lock-off.tar.xz
slx-admin-usb-lock-off.zip
Merge branch 'master' into usb-lock-offusb-lock-off
Diffstat (limited to 'modules-available/locations')
-rw-r--r--modules-available/locations/config.json4
-rw-r--r--modules-available/locations/inc/location.inc.php4
-rw-r--r--modules-available/locations/lang/de/messages.json1
-rw-r--r--modules-available/locations/lang/de/permissions.json14
-rw-r--r--modules-available/locations/lang/de/template-tags.json5
-rw-r--r--modules-available/locations/lang/en/messages.json1
-rw-r--r--modules-available/locations/lang/en/permissions.json14
-rw-r--r--modules-available/locations/lang/en/template-tags.json5
-rw-r--r--modules-available/locations/page.inc.php328
-rw-r--r--modules-available/locations/permissions/permissions.json32
-rw-r--r--modules-available/locations/templates/location-subnets.html44
-rw-r--r--modules-available/locations/templates/locations.html50
-rw-r--r--modules-available/locations/templates/subnets.html8
13 files changed, 307 insertions, 203 deletions
diff --git a/modules-available/locations/config.json b/modules-available/locations/config.json
index 706412d0..110f8b67 100644
--- a/modules-available/locations/config.json
+++ b/modules-available/locations/config.json
@@ -1,3 +1,3 @@
{
- "category":"main.content"
-}
+ "category": "main.content"
+} \ No newline at end of file
diff --git a/modules-available/locations/inc/location.inc.php b/modules-available/locations/inc/location.inc.php
index 0576e660..8db0c5f3 100644
--- a/modules-available/locations/inc/location.inc.php
+++ b/modules-available/locations/inc/location.inc.php
@@ -251,7 +251,7 @@ class Location
{
$ids = array();
foreach ($tree as $node) {
- $ids[] = $node['locationid'];
+ $ids[] = (int)$node['locationid'];
if (!empty($node['children'])) {
$ids = array_merge($ids, self::extractIds($node['children']));
}
@@ -429,7 +429,7 @@ class Location
foreach ($self as $entry) {
if (!isset($locs[$entry]))
continue;
- $overlapSelf[]['locationname'] = $locs[$entry['locationid']]['locationname'];
+ $overlapSelf[]['locationname'] = $locs[$entry]['locationname'];
}
}
if ($overlapOther) {
diff --git a/modules-available/locations/lang/de/messages.json b/modules-available/locations/lang/de/messages.json
index 95002ee7..6b682c7e 100644
--- a/modules-available/locations/lang/de/messages.json
+++ b/modules-available/locations/lang/de/messages.json
@@ -3,6 +3,7 @@
"invalid-location-id": "Ung\u00fcltige Orts-id: {{0}}",
"location-deleted": "Location wurde gel\u00f6scht (Locations: {{0}}, Subnets: {{1}})",
"location-updated": "Location {{0}} wurde aktualisiert",
+ "no-permission-location": "Keine Rechte f\u00fcr Ort {{0}}",
"parameter-missing": "Fehlender Parameter: {{0}}",
"subnets-created": "Subnetze angelegt: {{0}}",
"subnets-deleted": "Subnetze gel\u00f6scht: {{0}}",
diff --git a/modules-available/locations/lang/de/permissions.json b/modules-available/locations/lang/de/permissions.json
index 46dea864..8a9336b3 100644
--- a/modules-available/locations/lang/de/permissions.json
+++ b/modules-available/locations/lang/de/permissions.json
@@ -1,9 +1,9 @@
{
- "location.view": "Räume anschauen.",
- "location.edit": "Räume bearbeiten.",
- "location.add": "Räume hinzufügen.",
- "location.delete": "Räume löschen.",
- "subnet.edit": "Subnetze bearbeiten.",
- "subnet.add": "Subnetze hinzufügen.",
- "subnet.delete": "Subnetze löschen."
+ "location.add": "R\u00e4ume\/Orte hinzuf\u00fcgen.",
+ "location.delete": "R\u00e4ume\/Orte l\u00f6schen.",
+ "location.edit.name": "Orte umbenennen.",
+ "location.edit.parent": "Den \u00fcbergeordneten Ort eines Ortes \u00e4ndern.",
+ "location.edit.subnets": "Die IP-Ranges eines Ortes \u00e4ndern.",
+ "location.view": "R\u00e4ume anschauen.",
+ "subnets.edit": "Subnetze mittels der Subnetz\u00fcbersicht \u00e4ndern."
} \ No newline at end of file
diff --git a/modules-available/locations/lang/de/template-tags.json b/modules-available/locations/lang/de/template-tags.json
index 04d10d06..96273ce4 100644
--- a/modules-available/locations/lang/de/template-tags.json
+++ b/modules-available/locations/lang/de/template-tags.json
@@ -3,10 +3,11 @@
"lang_areYouSureNoUndo": "Sind Sie sicher? Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.",
"lang_assignSubnetExplanation": "Rechner, die in einen der hier aufgef\u00fchrten Adressbereiche fallen, werden diesem Ort zugeschrieben und erhalten damit z.B. f\u00fcr diesen Raum angepasste Veranstaltungslisten.",
"lang_assignedSubnets": "Zugeordnete Subnetze bzw. IP-Bereiche",
+ "lang_bootMenu": "Bootmen\u00fc",
"lang_deleteChildLocations": "Untergeordnete Orte ebenfalls l\u00f6schen",
"lang_deleteLocation": "Ort l\u00f6schen",
"lang_deleteSubnet": "Bereich l\u00f6schen",
- "lang_deleteSubnetWarning": "Alle zum L\u00f6schen markierten Subnetze werden gelöscht. Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.",
+ "lang_deleteSubnetWarning": "Alle zum L\u00f6schen markierten Subnetze werden gel\u00f6scht. Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.",
"lang_editConfigVariables": "Konfig.-Variablen",
"lang_editRoomplan": "Raumplan bearbeiten",
"lang_endAddress": "Endadresse",
@@ -22,10 +23,10 @@
"lang_machineLoad": "Besetzt",
"lang_matchingMachines": "Enthaltene Rechner",
"lang_name": "Name",
- "lang_noParent": "Kein \u00fcbergeordneter Ort",
"lang_overrideCount": "Angepasst",
"lang_parentLocation": "\u00dcbergeordneter Ort",
"lang_referencingLectures": "Veranstaltungen",
+ "lang_showRoomplan": "Raumplan anzeigen",
"lang_startAddress": "Startadresse",
"lang_subnet": "IP-Bereich",
"lang_sysConfig": "Lokalisierung",
diff --git a/modules-available/locations/lang/en/messages.json b/modules-available/locations/lang/en/messages.json
index fca00c7c..95788c47 100644
--- a/modules-available/locations/lang/en/messages.json
+++ b/modules-available/locations/lang/en/messages.json
@@ -3,6 +3,7 @@
"invalid-location-id": "Invalid location id: {{0}}",
"location-deleted": "Location has been deleted (locations: {{0}}, subnets: {{1}})",
"location-updated": "Location {{0}} has been updated",
+ "no-permission-location": "No permissions for location {{0}}",
"parameter-missing": "Missing parameter: {{0}}",
"subnets-created": "{{0}} subnet(s) created",
"subnets-deleted": "{{0}} subnet(s) deleted",
diff --git a/modules-available/locations/lang/en/permissions.json b/modules-available/locations/lang/en/permissions.json
index db0ac5f6..1d01a9d1 100644
--- a/modules-available/locations/lang/en/permissions.json
+++ b/modules-available/locations/lang/en/permissions.json
@@ -1,9 +1,9 @@
{
- "location.view": "View locations.",
- "location.edit": "Edit locations.",
- "location.add": "Add locations.",
- "location.delete": "Delete locations.",
- "subnet.edit": "Edit subnets.",
- "subnet.add": "Add subnets.",
- "subnet.delete": "Delete subnets."
+ "location.add": "Add locations.",
+ "location.delete": "Delete locations.",
+ "location.edit.name": "Rename locations.",
+ "location.edit.parent": "Change the parent location of a location.",
+ "location.edit.subnets": "Edit the IP ranges of a location.",
+ "location.view": "View locations.",
+ "subnets.edit": "Edit subnets via the subnet overview."
} \ No newline at end of file
diff --git a/modules-available/locations/lang/en/template-tags.json b/modules-available/locations/lang/en/template-tags.json
index ddb90f83..64211e27 100644
--- a/modules-available/locations/lang/en/template-tags.json
+++ b/modules-available/locations/lang/en/template-tags.json
@@ -3,6 +3,7 @@
"lang_areYouSureNoUndo": "Are you sure? This cannot be undone!",
"lang_assignSubnetExplanation": "Client machines which fall into an IP range listed below will be assigned to this location and will see an according lecture list (e.g. they will see lectures that are exclusively assigned to this location).",
"lang_assignedSubnets": "Assigned subnets \/ IP ranges",
+ "lang_bootMenu": "Boot menu",
"lang_deleteChildLocations": "Delete child locations aswell",
"lang_deleteLocation": "Delete location",
"lang_deleteSubnet": "Delete range",
@@ -22,14 +23,14 @@
"lang_machineLoad": "In use",
"lang_matchingMachines": "Matching clients",
"lang_name": "Name",
- "lang_noParent": "No parent",
"lang_overrideCount": "Overridden",
"lang_parentLocation": "Parent location",
"lang_referencingLectures": "Assigned Lectures",
+ "lang_showRoomplan": "Show room plan",
"lang_startAddress": "Start address",
"lang_subnet": "IP range",
"lang_sysConfig": "Localization\/Integration",
"lang_thisListByLocation": "Locations",
"lang_thisListBySubnet": "Subnets",
"lang_unassignedMachines": "Machines not matching any location"
-}
+} \ No newline at end of file
diff --git a/modules-available/locations/page.inc.php b/modules-available/locations/page.inc.php
index 0cfa5b90..2d8f5ff9 100644
--- a/modules-available/locations/page.inc.php
+++ b/modules-available/locations/page.inc.php
@@ -24,10 +24,14 @@ class Page_Locations extends Page
} elseif ($this->action === 'updatesubnets') {
$this->updateSubnets();
}
+ if (Request::isPost()) {
+ Util::redirect('?do=locations');
+ }
}
private function updateSubnets()
{
+ User::assertPermission('subnets.edit', NULL, '?do=locations');
$count = 0;
$starts = Request::post('startaddr', false);
$ends = Request::post('endaddr', false);
@@ -47,12 +51,6 @@ class Page_Locations extends Page
Message::addError('main.value-invalid', 'locationid', $loc);
continue;
}
-
- $oldLoc = Database::queryFirst("SELECT locationid FROM subnet WHERE subnetid = :subnetid", array("subnetid" => $subnetid))["locationid"];
- if (($loc == $oldLoc && !User::hasPermission("subnet.edit", $loc)) ||
- ($loc != $oldLoc && (!User::hasPermission("subnet.delete", $oldLoc) || !User::hasPermission("subnet.add", $loc))))
- continue;
-
$range = $this->rangeToLongVerbose($start, $end);
if ($range === false)
continue;
@@ -63,7 +61,7 @@ class Page_Locations extends Page
}
AutoLocation::rebuildAll();
Message::addSuccess('subnets-updated', $count);
- Util::redirect('?do=Locations&action=showsubnets');
+ Util::redirect('?do=Locations');
}
private function addLocations()
@@ -81,8 +79,10 @@ class Page_Locations extends Page
if (empty($name))
continue;
$parent = isset($parents[$idx]) ? (int)$parents[$idx] : 0;
- if (!User::hasPermission("location.add", $parent))
+ if (!User::hasPermission("location.add", $parent)) {
+ Message::addError('no-permission-location', isset($locs[$parent]) ? $locs[$parent]['locationname'] : $parent);
continue;
+ }
if ($parent !== 0) {
$ok = false;
foreach ($locs as $loc) {
@@ -123,24 +123,16 @@ class Page_Locations extends Page
$change = false;
// Delete location?
if ($locationId === $del) {
- if (!User::hasPermission("location.delete", $locationId)) {
- Message::addError('main.no-permission', 'locationid', $locationId);
- Util::redirect('?do=Locations');
- }
+ User::assertPermission("location.delete", $locationId, '?do=locations');
$this->deleteLocation($location);
$change = true;
}
// Update subnets
$change |= $this->updateLocationSubnets();
-
- if (User::hasPermission("subnet.add", $locationId)) {
- // Insert subnets
- $change |= $this->addNewLocationSubnets($location);
- }
- if (User::hasPermission("location.edit", $locationId)) {
- // Update location!
- $change |= $this->updateLocationData($location);
- }
+ // Insert subnets
+ $change |= $this->addNewLocationSubnets($location);
+ // Update location!
+ $change |= $this->updateLocationData($location);
if ($change) {
// In case subnets or tree layout changed, recalc this
@@ -176,13 +168,17 @@ class Page_Locations extends Page
$locationId = (int)$location['locationid'];
$newParent = Request::post('parentlocationid', false, 'integer');
$newName = Request::post('locationname', false, 'string');
- if ($newName === false || preg_match('/^\s*$/', $newName)) {
+ if (!User::hasPermission('location.edit.name', $locationId)) {
+ $newName = $location['locationname'];
+ } elseif ($newName === false || preg_match('/^\s*$/', $newName)) {
if ($newName !== false) {
Message::addWarning('main.value-invalid', 'location name', $newName);
}
$newName = $location['locationname'];
}
- if ($newParent === false) {
+ if ($newParent === false || !User::hasPermission('location.edit.parent', $locationId)
+ || !User::hasPermission('location.edit.parent', $newParent)
+ || !User::hasPermission('location.edit.*', $location['parentlocationid'])) {
$newParent = $location['parentlocationid'];
} else if ($newParent !== 0) {
$rows = Location::queryLocations();
@@ -213,13 +209,15 @@ class Page_Locations extends Page
private function updateLocationSubnets()
{
- $change = false;
-
$locationId = Request::post('locationid', false, 'integer');
+ if (!User::hasPermission('location.edit.subnets', $locationId))
+ return false;
+
+ $change = false;
// Deletion first
$dels = Request::post('deletesubnet', false);
- if (is_array($dels) && User::hasPermission("subnet.delete", $locationId)) {
+ if (is_array($dels)) {
$count = 0;
$stmt = Database::prepare('DELETE FROM subnet WHERE subnetid = :id');
foreach ($dels as $key => $value) {
@@ -234,8 +232,6 @@ class Page_Locations extends Page
$change = true;
}
}
- if (!User::hasPermission("subnet.edit", $locationId))
- return $change;
// Now actual updates
$starts = Request::post('startaddr', false);
@@ -267,8 +263,11 @@ class Page_Locations extends Page
private function addNewLocationSubnets($location)
{
- $change = false;
$locationId = (int)$location['locationid'];
+ if (!User::hasPermission('location.edit.subnets', $locationId))
+ return false;
+
+ $change = false;
$starts = Request::post('newstartaddr', false);
$ends = Request::post('newendaddr', false);
if (!is_array($starts) || !is_array($ends)) {
@@ -310,36 +309,32 @@ class Page_Locations extends Page
protected function doRender()
{
- $getAction = Request::get('action');
- if (empty($getAction)) {
- // Until we have a main landing page?
- Util::redirect('?do=Locations&action=showlocations');
+ $getAction = Request::get('action', false, 'string');
+ if ($getAction === false) {
+ if (User::hasPermission('location.view')) {
+ Util::redirect('?do=locations&action=showlocations');
+ } elseif (User::hasPermission('subnets.edit')) {
+ Util::redirect('?do=locations&action=showsubnets');
+ } else {
+ // Trigger permission denied by asserting non-existent permission
+ User::assertPermission('location.view');
+ }
}
if ($getAction === 'showsubnets') {
- $res = Database::simpleQuery("SELECT subnetid, startaddr, endaddr, locationid FROM subnet
- WHERE locationid IN (:locations) ORDER BY startaddr ASC",
- array("locations" => User::getAllowedLocations("location.view")));
- $allowedLocs = User::getAllowedLocations("subnet.add");
+ User::assertPermission('subnets.edit', NULL, '?do=locations');
+ $res = Database::simpleQuery("SELECT subnetid, startaddr, endaddr, locationid FROM subnet");
$rows = array();
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
$row['startaddr'] = long2ip($row['startaddr']);
$row['endaddr'] = long2ip($row['endaddr']);
$row['locations'] = Location::getLocations($row['locationid']);
-
- foreach ($row['locations'] as &$loc) {
- if (!(in_array($loc["locationid"], $allowedLocs) || $loc["locationid"] == $row['locationid'])) {
- $loc["disabled"] = "disabled";
- }
- }
-
- $row['editThisSubnetAllowed'] = User::hasPermission("subnet.edit", $row['locationid']);
- $row['deleteThisSubnetAllowed'] = User::hasPermission("subnet.delete", $row['locationid']);
$rows[] = $row;
}
-
- Render::addTemplate('subnets', array('list' => $rows, 'editSubnetAllowed' => User::hasPermission("subnet.edit")));
+ Render::addTemplate('subnets', array('list' => $rows));
} elseif ($getAction === 'showlocations') {
$this->showLocationList();
+ } else {
+ Util::redirect('?do=locations');
}
}
@@ -349,38 +344,88 @@ class Page_Locations extends Page
$overlapSelf = $overlapOther = true;
Location::getOverlappingSubnets($overlapSelf, $overlapOther);
//$locs = Location::getLocations(0, 0, false, true);
- $locs = Location::getLocationsAssoc();
+ $locationList = Location::getLocationsAssoc();
+ unset($locationList[0]);
// Statistics: Count machines for each subnet
$unassigned = false;
+ $unassignedLoad = 0;
+
+ // Filter view: Remove locations we can't reach at all, but show parents to locations
+ // we have permission to, so the tree doesn't look all weird
+ $visibleLocationIds = $allowedLocationIds = User::getAllowedLocations("location.view");
+ foreach ($allowedLocationIds as $lid) {
+ if (!isset($locationList[$lid]))
+ continue;
+ $visibleLocationIds = array_merge($visibleLocationIds, $locationList[$lid]['parents']);
+ }
+ $visibleLocationIds = array_unique($visibleLocationIds);
+ foreach (array_keys($locationList) as $lid) {
+ if (User::hasPermission('.baseconfig.view', $lid)) {
+ $visibleLocationIds[] = $lid;
+ } else {
+ $locationList[$lid]['havebaseconfig'] = false;
+ }
+ if (User::hasPermission('.sysconfig.config.view-list', $lid)) {
+ $visibleLocationIds[] = $lid;
+ } else {
+ $locationList[$lid]['havesysconfig'] = false;
+ }
+ if (User::hasPermission('.statistics.view.list', $lid)) {
+ $visibleLocationIds[] = $lid;
+ } else {
+ $locationList[$lid]['havestatistics'] = false;
+ }
+ if (User::hasPermission('.serversetup.ipxe.menu.assign', $lid)) {
+ $visibleLocationIds[] = $lid;
+ } else {
+ $locationList[$lid]['haveipxe'] = false;
+ }
+ if (!in_array($lid, $visibleLocationIds)) {
+ unset($locationList[$lid]);
+ } elseif (!in_array($lid, $allowedLocationIds)) {
+ $locationList[$lid]['show-only'] = true;
+ }
+ }
+
+ // Client statistics
if (Module::get('statistics') !== false) {
- $DL = time() - 605;
$unassigned = 0;
- $res = Database::simpleQuery("SELECT locationid, Count(*) AS cnt, Sum(If(lastseen > $DL AND logintime <> 0, 1, 0)) AS used
- FROM machine GROUP BY locationid");
+ $extra = '';
+ if (in_array(0, $allowedLocationIds)) {
+ $extra = ' OR locationid IS NULL';
+ }
+ $res = Database::simpleQuery("SELECT locationid, Count(*) AS cnt, Sum(If(state = 'OCCUPIED', 1, 0)) AS used
+ FROM machine WHERE (locationid IN (:allowedLocationIds) $extra) GROUP BY locationid", compact('allowedLocationIds'));
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $loc = (int)$row['locationid'];
- if (isset($locs[$loc])) {
- $locs[$loc]['clientCount'] = $row['cnt'];
- $locs[$loc]['clientLoad'] = round(100 * $row['used'] / $row['cnt']) . '%';
+ $locId = (int)$row['locationid'];
+ if (isset($locationList[$locId])) {
+ $locationList[$locId]['clientCount'] = $row['cnt'];
+ $locationList[$locId]['clientLoad'] = round(100 * $row['used'] / $row['cnt']) . ' %';
} else {
$unassigned += $row['cnt'];
+ $unassignedLoad += $row['used'];
}
}
unset($loc);
- foreach ($locs as &$loc) {
+ foreach ($locationList as &$loc) {
+ if (!in_array($loc['locationid'], $allowedLocationIds))
+ continue;
+ if (!isset($loc['clientCountSum'])) {
+ $loc['clientCountSum'] = 0;
+ }
if (!isset($loc['clientCount'])) {
$loc['clientCount'] = 0;
$loc['clientLoad'] = '0%';
}
- $loc['clientCountSum'] = $loc['clientCount'];
- }
- unset($loc);
- foreach ($locs as $loc) {
+ $loc['clientCountSum'] += $loc['clientCount'];
foreach ($loc['parents'] as $pid) {
- $locs[(int)$pid]['hasChild'] = true;
- $locs[(int)$pid]['clientCountSum'] += $loc['clientCount'];
+ if (!in_array($pid, $allowedLocationIds))
+ continue;
+ $locationList[(int)$pid]['hasChild'] = true;
+ $locationList[(int)$pid]['clientCountSum'] += $loc['clientCount'];
}
}
+ unset($loc);
}
// Show currently active sysconfig for each location
$defaultConfig = false;
@@ -390,85 +435,77 @@ class Page_Locations extends Page
if (strlen($conf['locs']) === 0)
continue;
$confLocs = explode(',', $conf['locs']);
- foreach ($confLocs as $loc) {
- settype($loc, 'int');
- if ($loc === 0) {
+ foreach ($confLocs as $locId) {
+ settype($locId, 'int');
+ if ($locId === 0) {
$defaultConfig = $conf['title'];
}
- if (!isset($locs[$loc]))
+ if (!isset($locationList[$locId]))
continue;
- $locs[$loc] += array('configName' => $conf['title'], 'configClass' => 'slx-bold');
+ $locationList[$locId] += array('configName' => $conf['title'], 'configClass' => 'slx-bold');
}
}
- $depth = array();
- foreach ($locs as &$loc) {
- $d = $loc['depth'];
- if (!isset($loc['configName'])) {
- // Has no explicit config assignment
- if ($d === 0) {
- $loc['configName'] = $defaultConfig;
- } else {
- $loc['configName'] = $depth[$d - 1];
- }
- $loc['configClass'] = 'gray';
- }
- $depth[$d] = $loc['configName'];
- unset($depth[$d + 1]);
- }
- unset($loc);
+ $this->propagateFields($locationList, $defaultConfig, 'configName', 'configClass');
}
// Count overridden config vars
if (Module::get('baseconfig') !== false) {
- $res = Database::simpleQuery("SELECT locationid, Count(*) AS cnt FROM `setting_location` GROUP BY locationid");
+ $res = Database::simpleQuery("SELECT locationid, Count(*) AS cnt FROM `setting_location`
+ WHERE locationid IN (:allowedLocationIds) GROUP BY locationid", compact('allowedLocationIds'));
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
$lid = (int)$row['locationid'];
- if (isset($locs[$lid])) {
- $locs[$lid]['overriddenVars'] = $row['cnt'];
+ if (isset($locationList[$lid])) {
+ $locationList[$lid]['overriddenVars'] = $row['cnt'];
}
}
- }
-
- $allowedLocs = User::getAllowedLocations("location.view");
- $withParents = array();
- foreach ($allowedLocs as $loc) {
- $withParents = array_merge($withParents, Location::getLocationRootChain($loc));
- }
-
- foreach ($locs as $key => $loc) {
- if (!in_array($loc["locationid"], $withParents)) {
- unset($locs[$key]);
- } elseif (!in_array($loc["locationid"], $allowedLocs)) {
- $id = $locs[$key]["locationid"];
- $name = $locs[$key]["locationname"];
- $depth = $locs[$key]["depth"];
- $locs[$key] = array("locationid" => $id, "locationname" => $name, "depth" => $depth, "linkClass" => "not-allowed");
+ // Confusing because the count might be inaccurate within a branch
+ //$this->propagateFields($locationList, '', 'overriddenVars', 'overriddenClass');
+ }
+ // Show ipxe menu
+ if (Module::get('serversetup') !== false) {
+ $res = Database::simpleQuery("SELECT ml.locationid, m.title, ml.defaultentryid FROM serversetup_menu m
+ INNER JOIN serversetup_menu_location ml USING (menuid)
+ WHERE locationid IN (:allowedLocationIds) GROUP BY locationid", compact('allowedLocationIds'));
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $lid = (int)$row['locationid'];
+ if (isset($locationList[$lid])) {
+ if ($row['defaultentryid'] !== null) {
+ $row['title'] .= '(*)';
+ }
+ $locationList[$lid]['customMenu'] = $row['title'];
+ }
}
+ $this->propagateFields($locationList, '', 'customMenu', 'customMenuClass');
}
$addAllowedLocs = User::getAllowedLocations("location.add");
- $addAllowedLocs[] = 0;
$addAllowedList = Location::getLocations(0, 0, true);
foreach ($addAllowedList as &$loc) {
if (!in_array($loc["locationid"], $addAllowedLocs)) {
$loc["disabled"] = "disabled";
}
}
+ unset($loc);
// Output
- Render::addTemplate('locations', array(
- 'list' => array_values($locs),
+ $data = array(
+ 'list' => array_values($locationList),
'havestatistics' => Module::get('statistics') !== false,
'havebaseconfig' => Module::get('baseconfig') !== false,
'havesysconfig' => Module::get('sysconfig') !== false,
+ 'haveipxe' => Module::get('serversetup') !== false,
'overlapSelf' => $overlapSelf,
'overlapOther' => $overlapOther,
'haveOverlapSelf' => !empty($overlapSelf),
'haveOverlapOther' => !empty($overlapOther),
'unassignedCount' => $unassigned,
+ 'unassignedLoad' => round(($unassignedLoad / $unassigned) * 100) . ' %',
'defaultConfig' => $defaultConfig,
- 'addAllowed' => User::hasPermission("location.add"),
- 'addAllowedList' => array_values($addAllowedList)
- ));
+ 'addAllowedList' => array_values($addAllowedList),
+ );
+ // TODO: Buttons for config vars and sysconfig are currently always shown, as their availability
+ // depends on permissions in the according modules, not this one
+ Permission::addGlobalTags($data['perms'], NULL, ['subnets.edit', 'location.add']);
+ Render::addTemplate('locations', $data);
}
/*
@@ -491,9 +528,7 @@ class Page_Locations extends Page
{
$locationId = Request::any('locationid', 0, 'integer');
- if (!User::hasPermission("location.view", $locationId)) {
- die('Permission denied');
- }
+ User::assertPermission("location.view", $locationId);
$loc = Database::queryFirst('SELECT locationid, parentlocationid, locationname FROM location WHERE locationid = :lid',
array('lid' => $locationId));
@@ -516,11 +551,16 @@ class Page_Locations extends Page
'parents' => Location::getLocations($loc['parentlocationid'], $locationId, true)
);
- $allowedLocs = User::getAllowedLocations("location.edit");
- $allowedLocs[] = 0;
- foreach ($data['parents'] as &$parent) {
- if (!(in_array($parent["locationid"], $allowedLocs) || $parent["locationid"] == $loc['parentlocationid'])) {
- $parent["disabled"] = "disabled";
+ // Disable locations in the parent selector where the user cannot change to
+ if (!User::hasPermission('location.edit.*', $loc['parentlocationid'])
+ || !User::hasPermission('location.edit.parent', $locationId)) {
+ $allowedLocs = [];
+ } else {
+ $allowedLocs = User::getAllowedLocations("location.edit.*");
+ foreach ($data['parents'] as &$parent) {
+ if (!(in_array($parent["locationid"], $allowedLocs) || $parent["locationid"] == $loc['parentlocationid'])) {
+ $parent["disabled"] = "disabled";
+ }
}
}
@@ -534,19 +574,25 @@ class Page_Locations extends Page
// Get clients matching this location's subnet(s)
$count = $online = $used = 0;
if (Module::get('statistics') !== false) {
- $mres = Database::simpleQuery("SELECT lastseen, logintime FROM machine"
+ $mres = Database::simpleQuery("SELECT state FROM machine"
. " WHERE machine.locationid = :lid", array('lid' => $locationId));
- $DL = time() - 605;
while ($row = $mres->fetch(PDO::FETCH_ASSOC)) {
$count++;
- if ($row['lastseen'] > $DL) {
+ if ($row['state'] === 'IDLE') {
$online++;
- if ($row['logintime'] != 0) {
- $used++;
- }
+ }
+ if ($row['state'] === 'OCCUPIED') {
+ $online++;
+ $used++;
}
}
$data['haveStatistics'] = true;
+ // Link
+ if (User::hasPermission('.statistics.view.list')) {
+ $data['statsLink'] = 'list';
+ } elseif (User::hasPermission('.statistics.view.summary')) {
+ $data['statsLink'] = 'summary';
+ }
}
$data['machines'] = $count;
$data['machines_online'] = $online;
@@ -554,18 +600,13 @@ class Page_Locations extends Page
$data['used_percent'] = $count === 0 ? 0 : round(($used / $count) * 100);
- $data['havebaseconfig'] = Module::get('baseconfig') !== false;
- $data['havesysconfig'] = Module::get('sysconfig') !== false;
- $data['editAllowed'] = User::hasPermission("location.edit", $locationId);
- $data['deleteAllowed'] = User::hasPermission("location.delete", $locationId);
- $data['editSubnetAllowed'] = User::hasPermission("subnet.edit", $locationId);
- $data['deleteSubnetAllowed'] = User::hasPermission("subnet.delete", $locationId);
- $data['addSubnetAllowed'] = User::hasPermission("subnet.add", $locationId);
- $data['saveButton'] = $data['editAllowed'] || $data['editSubnetAllowed'] || $data['deleteSubnetAllowed'] || $data['addSubnetAllowed'];
+ Permission::addGlobalTags($data['perms'], $locationId, ['location.edit.name', 'location.edit.subnets', 'location.delete', '.roomplanner.edit'], 'save_button');
+ if (empty($allowedLocs)) {
+ $data['perms']['location']['edit']['parent']['disabled'] = 'disabled';
+ } else {
+ unset($data['perms']['save_button']);
+ }
- // echo '<pre>';
- // var_dump($data);
- // echo '</pre>';
echo Render::parse('location-subnets', $data);
}
@@ -605,4 +646,23 @@ class Page_Locations extends Page
return $result;
}
+ private function propagateFields(&$locationList, $defaultValue, $name, $class)
+ {
+ $depth = array();
+ foreach ($locationList as &$loc) {
+ $d = $loc['depth'];
+ if (!isset($loc[$name])) {
+ // Has no explicit config assignment
+ if ($d === 0) {
+ $loc[$name] = $defaultValue;
+ } else {
+ $loc[$name] = $depth[$d - 1];
+ }
+ $loc[$class] = 'gray';
+ }
+ $depth[$d] = $loc[$name];
+ unset($depth[$d + 1]);
+ }
+ }
+
}
diff --git a/modules-available/locations/permissions/permissions.json b/modules-available/locations/permissions/permissions.json
index 609a673a..18b24a73 100644
--- a/modules-available/locations/permissions/permissions.json
+++ b/modules-available/locations/permissions/permissions.json
@@ -1,9 +1,23 @@
-[
- "location.view",
- "location.edit",
- "location.add",
- "location.delete",
- "subnet.edit",
- "subnet.add",
- "subnet.delete"
-] \ No newline at end of file
+{
+ "location.add": {
+ "location-aware": true
+ },
+ "location.delete": {
+ "location-aware": true
+ },
+ "location.edit.name": {
+ "location-aware": true
+ },
+ "location.edit.subnets": {
+ "location-aware": true
+ },
+ "location.edit.parent": {
+ "location-aware": true
+ },
+ "location.view": {
+ "location-aware": true
+ },
+ "subnets.edit": {
+ "location-aware": false
+ }
+} \ No newline at end of file
diff --git a/modules-available/locations/templates/location-subnets.html b/modules-available/locations/templates/location-subnets.html
index 2cc8e98b..69e369c2 100644
--- a/modules-available/locations/templates/location-subnets.html
+++ b/modules-available/locations/templates/location-subnets.html
@@ -8,17 +8,17 @@
<button type="submit" class="btn btn-primary">Save</button>
</div>
<div class="row">
- <div class="{{^editAllowed}}disabled{{/editAllowed}}">
+ <div>
<div class="col-sm-6">
<div class="input-group">
<span class="input-group-addon slx-ga">{{lang_name}}</span>
- <input class="form-control" type="text" name="locationname" value="{{locationname}}" pattern=".*\S.*">
+ <input {{perms.location.edit.name.disabled}} class="form-control" type="text" name="locationname" value="{{locationname}}" pattern=".*\S.*">
</div>
</div>
<div class="col-sm-6">
<div class="input-group">
<span class="input-group-addon slx-ga2">{{lang_parentLocation}}</span>
- <select class="form-control" name="parentlocationid">
+ <select class="form-control" name="parentlocationid" {{perms.location.edit.parent.disabled}}>
{{#parents}}
<option {{disabled}} value="{{locationid}}" {{#selected}}selected="selected"{{/selected}}>{{locationpad}} {{locationname}}</option>
{{/parents}}
@@ -40,11 +40,11 @@
{{#list}}
<tr class="cidrmagic">
<td>{{subnetid}}</td>
- <td class="{{^editSubnetAllowed}}disabled{{/editSubnetAllowed}}"><input class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
- <td class="{{^editSubnetAllowed}}disabled{{/editSubnetAllowed}}"><input class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
+ <td><input {{perms.location.edit.subnets.disabled}} class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
+ <td><input {{perms.location.edit.subnets.disabled}} class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
<td class="danger">
<div class="checkbox text-center" style="margin-left: 9px">
- <input {{^deleteSubnetAllowed}}disabled{{/deleteSubnetAllowed}} type="checkbox" name="deletesubnet[{{subnetid}}]" value="on">
+ <input {{perms.location.edit.subnets.disabled}} type="checkbox" name="deletesubnet[{{subnetid}}]" value="on">
<label class="text-left"></label>
</div>
</td>
@@ -52,7 +52,7 @@
{{/list}}
<tr id="loc-sub-{{locationid}}">
<td colspan="4">
- <button {{^addSubnetAllowed}}disabled{{/addSubnetAllowed}} class="btn btn-success btn-sm pull-right" type="button" onclick="slxAddSubnetRow(this, {{locationid}})" title="{{lang_addNewSubnet}}">
+ <button {{perms.location.edit.subnets.disabled}} class="btn btn-success btn-sm pull-right" type="button" onclick="slxAddSubnetRow(this, {{locationid}})" title="{{lang_addNewSubnet}}">
<span class="glyphicon glyphicon-plus"></span> {{lang_subnet}}
</button>
</td>
@@ -69,24 +69,30 @@
{{/haveDozmod}}
{{#haveStatistics}}
<div>
- <span class="slx-ga2">{{lang_matchingMachines}}:</span> <a href="?do=Statistics&amp;show=list&amp;filters=location={{locationid}}">{{machines}} / {{machines_online}} / {{machines_used}} ({{used_percent}}%)</a>
+ <span class="slx-ga2">{{lang_matchingMachines}}:</span>
+ {{#statsLink}}
+ <a href="?do=Statistics&amp;show={{statsLink}}&amp;filters=location={{locationid}}">
+ {{/statsLink}}
+ {{machines}} / {{machines_online}} / {{machines_used}} ({{used_percent}}%)
+ {{#statsLink}}
+ </a>
+ {{/statsLink}}
</div>
{{/haveStatistics}}
</div>
<div class="col-md-4 text-center">
- <div class="btn-group">
- {{#roomplanner}}
- <a class="btn btn-default" href="?do=roomplanner&amp;locationid={{locationid}}" target="_blank"
- onclick="window.open(this.href, '_blank', 'toolbar=0,scrollbars,resizable');return false">
- <span class="glyphicon glyphicon-move"></span> {{lang_editRoomplan}}
- </a>
- {{/roomplanner}}
- </div>
-
+ {{#roomplanner}}
+ <a class="btn btn-default" href="?do=roomplanner&amp;locationid={{locationid}}" target="_blank"
+ onclick="window.open(this.href, '_blank', 'toolbar=0,scrollbars,resizable');return false">
+ <span class="glyphicon glyphicon-move"></span>
+ {{^perms.roomplanner.edit.disabled}}{{lang_editRoomplan}}{{/perms.roomplanner.edit.disabled}}
+ {{#perms.roomplanner.edit.disabled}}{{lang_showRoomplan}}{{/perms.roomplanner.edit.disabled}}
+ </a>
+ {{/roomplanner}}
</div>
<div class="col-md-4 text-right">
- <button style="margin-right: 10px" {{^deleteAllowed}}disabled{{/deleteAllowed}} type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteLocationModal{{locationid}}"><span class="glyphicon glyphicon-trash"></span> {{lang_deleteLocation}}</button>
- <button onclick="deleteSubnetWarning('{{locationid}}')" {{^saveButton}}disabled{{/saveButton}} type="button" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ <button {{perms.location.delete.disabled}} type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteLocationModal{{locationid}}"><span class="glyphicon glyphicon-trash"></span> {{lang_deleteLocation}}</button>
+ <button onclick="deleteSubnetWarning('{{locationid}}')" {{perms.save_button.disabled}} type="button" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</div>
diff --git a/modules-available/locations/templates/locations.html b/modules-available/locations/templates/locations.html
index be3d5115..06d32020 100644
--- a/modules-available/locations/templates/locations.html
+++ b/modules-available/locations/templates/locations.html
@@ -1,7 +1,13 @@
<div>
<div class="btn-group pull-right">
- <a href="?do=Locations&amp;action=showlocations" class="btn btn-default active"><span class="glyphicon glyphicon-home"></span> {{lang_thisListByLocation}}</a>
- <a href="?do=Locations&amp;action=showsubnets" class="btn btn-default"><span class="glyphicon glyphicon-list-alt"></span> {{lang_thisListBySubnet}}</a>
+ <a href="?do=Locations&amp;action=showlocations" class="btn btn-default active">
+ <span class="glyphicon glyphicon-home"></span>
+ {{lang_thisListByLocation}}
+ </a>
+ <a href="?do=Locations&amp;action=showsubnets" class="btn btn-default {{perms.subnets.edit.disabled}}">
+ <span class="glyphicon glyphicon-list-alt"></span>
+ {{lang_thisListBySubnet}}
+ </a>
</div>
<h1>{{lang_locationsMainHeading}}</h1>
@@ -31,15 +37,25 @@
<th class="text-nowrap">
{{#havesysconfig}}{{lang_sysConfig}}{{/havesysconfig}}
</th>
+ <th class="text-nowrap">
+ {{#haveipxe}}{{lang_bootMenu}}{{/haveipxe}}
+ </th>
</tr>
{{#list}}
<tr>
<td>
<div style="display:inline-block;width:{{depth}}em"></div>
- <a href="#" class="{{linkClass}}" onclick="slxOpenLocation(this, {{locationid}}); return false">{{locationname}}{{^linkClass}} <b class="caret"></b>{{/linkClass}}</a>
+ {{#show-only}}
+ <span>{{locationname}}</span>
+ {{/show-only}}
+ {{^show-only}}
+ <a href="#" onclick="slxOpenLocation(this, {{locationid}}); return false">
+ {{locationname}}
+ <b class="caret"></b>
+ </a>
+ {{/show-only}}
</td>
<td class="text-nowrap" align="right">
- {{^linkClass}}
{{#havestatistics}}
<a href="?do=Statistics&amp;show=list&amp;filters=location={{locationid}}">&nbsp;{{clientCount}}&nbsp;</a>
<span style="display:inline-block;width:5ex">
@@ -48,17 +64,13 @@
{{/hasChild}}
</span>
{{/havestatistics}}
- {{/linkClass}}
</td>
<td class="text-nowrap" align="right">
- {{^linkClass}}
{{#havestatistics}}
{{clientLoad}}
{{/havestatistics}}
- {{/linkClass}}
</td>
- <td class="text-nowrap">
- {{^linkClass}}
+ <td class="text-nowrap {{overriddenClass}}">
{{#havebaseconfig}}
<div class="pull-right" style="z-index:-1">
<a class="btn btn-default btn-xs" href="?do=baseconfig&amp;module=locations&amp;locationid={{locationid}}"><span class="glyphicon glyphicon-edit"></span></a>
@@ -67,10 +79,8 @@
{{lang_overrideCount}}: {{overriddenVars}}&emsp;&emsp;
{{/overriddenVars}}
{{/havebaseconfig}}
- {{/linkClass}}
</td>
<td class="text-nowrap">
- {{^linkClass}}
{{#havesysconfig}}
<div class="pull-right">
<a class="btn btn-default btn-xs" href="?do=sysconfig&amp;locationid={{locationid}}"><span class="glyphicon glyphicon-edit"></span></a>
@@ -79,7 +89,16 @@
{{configName}}&emsp;&emsp;
</span>
{{/havesysconfig}}
- {{/linkClass}}
+ </td>
+ <td class="text-nowrap">
+ {{#haveipxe}}
+ <div class="pull-right">
+ <a class="btn btn-default btn-xs" href="?do=serversetup&amp;show=assignlocation&amp;locationid={{locationid}}"><span class="glyphicon glyphicon-edit"></span></a>
+ </div>
+ <span class="{{customMenuClass}}">
+ {{customMenu}}&emsp;&emsp;
+ </span>
+ {{/haveipxe}}
</td>
</tr>
{{/list}}
@@ -90,9 +109,10 @@
<a href="?do=Statistics&amp;show=list&amp;filters=location=0">
&nbsp;{{unassignedCount}}&nbsp;
</a>
+ <span style="display:inline-block;width:5ex"></span>
</td>
<td class="text-nowrap" align="right">
- {{clientLoad}}
+ {{unassignedLoad}}
</td>
<td></td>
<td>{{defaultConfig}}</td>
@@ -106,7 +126,7 @@
<tr id="lasttr">
<td width="60%">&emsp;</td>
<td class="text-right" colspan="2">
- <button {{^addAllowed}}disabled{{/addAllowed}} class="btn btn-success" type="button" onclick="slxAddLocationRow()">
+ <button {{perms.location.add.disabled}} class="btn btn-success" type="button" onclick="slxAddLocationRow()">
<span class="glyphicon glyphicon-plus"></span> {{lang_location}}
</button>
<button id="saveLocationRows" type="submit" class="btn btn-primary collapse">
@@ -163,7 +183,7 @@ function slxOpenLocation(e, lid) {
}
return;
}
- var td = $('<td>').attr('colspan', '5').css('padding', '0px 0px 12px');
+ var td = $('<td>').attr('colspan', '6').css('padding', '0px 0px 12px');
var tr = $('<tr>').attr('id', 'location-details-' + lid);
tr.append(td);
$(e).closest('tr').addClass('active slx-bold').after(tr);
diff --git a/modules-available/locations/templates/subnets.html b/modules-available/locations/templates/subnets.html
index cb7fb758..d027d800 100644
--- a/modules-available/locations/templates/subnets.html
+++ b/modules-available/locations/templates/subnets.html
@@ -17,9 +17,9 @@
{{#list}}
<tr class="cidrmagic">
<td>{{subnetid}}</td>
- <td class="{{^editThisSubnetAllowed}}disabled{{/editThisSubnetAllowed}}"><input class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}"></td>
- <td class="{{^editThisSubnetAllowed}}disabled{{/editThisSubnetAllowed}}"><input class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}"></td>
- <td class="{{^deleteThisSubnetAllowed}}disabled{{/deleteThisSubnetAllowed}}">
+ <td><input class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}"></td>
+ <td><input class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}"></td>
+ <td>
<select class="form-control" name="location[{{subnetid}}]">
{{#locations}}
<option {{disabled}} value="{{locationid}}" {{#selected}}selected="selected"{{/selected}}>{{locationpad}} {{locationname}}</option>
@@ -30,7 +30,7 @@
{{/list}}
</table>
<div class="text-right" style="margin-bottom: 20px">
- <button {{^editSubnetAllowed}}disabled{{/editSubnetAllowed}} type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</form>
</div>