summaryrefslogtreecommitdiffstats
path: root/modules-available/locations/pages/locations.inc.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/locations/pages/locations.inc.php')
-rw-r--r--modules-available/locations/pages/locations.inc.php271
1 files changed, 271 insertions, 0 deletions
diff --git a/modules-available/locations/pages/locations.inc.php b/modules-available/locations/pages/locations.inc.php
new file mode 100644
index 00000000..275aafdb
--- /dev/null
+++ b/modules-available/locations/pages/locations.inc.php
@@ -0,0 +1,271 @@
+<?php
+
+class SubPage
+{
+
+ public static function doPreprocess($action)
+ {
+ if ($action === 'addlocations') {
+ self::addLocations();
+ return true;
+ }
+ return false;
+ }
+
+ public static function doRender($getAction)
+ {
+ if ($getAction === false) {
+ if (User::hasPermission('location.view')) {
+ // OK
+ } elseif (User::hasPermission('subnets.edit')) {
+ // Fallback to something else?
+ Util::redirect('?do=locations&page=subnets');
+ } else {
+ // Trigger permission denied by asserting non-existent permission
+ User::assertPermission('location.view');
+ }
+ }
+ if ($getAction === false) {
+ self::showLocationList();
+ return true;
+ }
+ return false;
+ }
+
+ public static function doAjax($action)
+ {
+ return false;
+ }
+
+ private static function addLocations()
+ {
+ $names = Request::post('newlocation', false);
+ $parents = Request::post('newparent', []);
+ if (!is_array($names) || !is_array($parents)) {
+ Message::addError('main.empty-field');
+ Util::redirect('?do=Locations');
+ }
+ $locs = Location::getLocations();
+ $count = 0;
+ foreach ($names as $idx => $name) {
+ $name = trim($name);
+ if (empty($name))
+ continue;
+ $parent = isset($parents[$idx]) ? (int)$parents[$idx] : 0;
+ 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) {
+ if ($loc['locationid'] == $parent) {
+ $ok = true;
+ }
+ }
+ if (!$ok) {
+ Message::addWarning('main.value-invalid', 'parentlocationid', $parent);
+ continue;
+ }
+ }
+ Database::exec("INSERT INTO location (parentlocationid, locationname)"
+ . " VALUES (:parent, :name)", array(
+ 'parent' => $parent,
+ 'name' => $name
+ ));
+ $count++;
+ }
+ Message::addSuccess('added-x-entries', $count);
+ Util::redirect('?do=Locations');
+ }
+
+ public static function showLocationList()
+ {
+ // Warn admin about overlapping subnet definitions
+ $overlapSelf = $overlapOther = true;
+ LocationUtil::getOverlappingSubnets($overlapSelf, $overlapOther);
+ // Find machines assigned to a room with a UUID mismatch
+ $mismatchMachines = LocationUtil::getMachinesWithLocationMismatch(0, true);
+ $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) {
+ $unassigned = 0;
+ $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)) {
+ $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 ($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'];
+ foreach ($loc['parents'] as $pid) {
+ 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;
+ if (Module::isAvailable('sysconfig')) {
+ $confs = SysConfig::getAll();
+ foreach ($confs as $conf) {
+ if (strlen($conf['locs']) === 0)
+ continue;
+ $confLocs = explode(',', $conf['locs']);
+ foreach ($confLocs as $locId) {
+ settype($locId, 'int');
+ if ($locId === 0) {
+ $defaultConfig = $conf['title'];
+ }
+ if (!isset($locationList[$locId]))
+ continue;
+ $locationList[$locId] += array('configName' => $conf['title'], 'configClass' => 'slx-bold');
+ }
+ }
+ self::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`
+ WHERE locationid IN (:allowedLocationIds) GROUP BY locationid", compact('allowedLocationIds'));
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $lid = (int)$row['locationid'];
+ if (isset($locationList[$lid])) {
+ $locationList[$lid]['overriddenVars'] = $row['cnt'];
+ }
+ }
+ // Confusing because the count might be inaccurate within a branch
+ //$this->propagateFields($locationList, '', 'overriddenVars', 'overriddenClass');
+ }
+ // Show ipxe menu
+ if (Module::isAvailable('serversetup') && class_exists('IPxe')) {
+ $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'];
+ }
+ }
+ self::propagateFields($locationList, '', 'customMenu', 'customMenuClass');
+ }
+
+ $addAllowedLocs = User::getAllowedLocations("location.add");
+ $addAllowedList = Location::getLocations(0, 0, true);
+ foreach ($addAllowedList as &$loc) {
+ if (!in_array($loc["locationid"], $addAllowedLocs)) {
+ $loc["disabled"] = "disabled";
+ }
+ }
+ unset($loc);
+
+ // Output
+ $data = array(
+ 'list' => array_values($locationList),
+ 'havestatistics' => Module::get('statistics') !== false,
+ 'havebaseconfig' => Module::get('baseconfig') !== false,
+ 'havesysconfig' => Module::get('sysconfig') !== false,
+ 'haveipxe' => Module::isAvailable('serversetup') && class_exists('IPxe'),
+ 'overlapSelf' => $overlapSelf,
+ 'overlapOther' => $overlapOther,
+ 'mismatchMachines' => $mismatchMachines,
+ 'unassignedCount' => $unassigned,
+ 'unassignedLoad' => ($unassigned ? (round(($unassignedLoad / $unassigned) * 100) . ' %') : ''),
+ 'defaultConfig' => $defaultConfig,
+ '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);
+ }
+
+ private static 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]);
+ }
+ }
+
+} \ No newline at end of file