summaryrefslogtreecommitdiffstats
path: root/modules-available/runmode
diff options
context:
space:
mode:
authorSimon Rettberg2018-02-27 13:05:21 +0100
committerSimon Rettberg2018-02-27 13:05:21 +0100
commit47d1e28478a78eb8d275553cb44693a61b597307 (patch)
tree447bbbd333f19db716e6f0a1b773f21d01d72301 /modules-available/runmode
parent[dnbd3] Add permissions (diff)
downloadslx-admin-47d1e28478a78eb8d275553cb44693a61b597307.tar.gz
slx-admin-47d1e28478a78eb8d275553cb44693a61b597307.tar.xz
slx-admin-47d1e28478a78eb8d275553cb44693a61b597307.zip
[runmode] Support permissions supplied by module; fix handling of deleteUrl modules
Diffstat (limited to 'modules-available/runmode')
-rw-r--r--modules-available/runmode/inc/runmode.inc.php14
-rw-r--r--modules-available/runmode/page.inc.php282
-rw-r--r--modules-available/runmode/permissions/permissions.json5
-rw-r--r--modules-available/runmode/templates/machine-selector.html31
-rw-r--r--modules-available/runmode/templates/module-machine-list.html4
5 files changed, 242 insertions, 94 deletions
diff --git a/modules-available/runmode/inc/runmode.inc.php b/modules-available/runmode/inc/runmode.inc.php
index 2c8083ca..174fb675 100644
--- a/modules-available/runmode/inc/runmode.inc.php
+++ b/modules-available/runmode/inc/runmode.inc.php
@@ -28,7 +28,7 @@ class RunMode
/**
* @param string $machineuuid
- * @param string $moduleId
+ * @param string|\Module $moduleId
* @param string|null $modeId an ID specific to the module to further specify the run mode, NULL to delete the run mode entry
* @param string|null $modeData optional, additional data for the run mode
* @param bool|null $isClient whether to count the machine as a client (in statistics etc.) NULL for looking at module's general runmode config
@@ -284,6 +284,11 @@ class RunModeModuleConfig
*/
public $deleteUrlSnippet = false;
+ /**
+ * @var string|false Permission to check when accessing/assigning
+ */
+ public $permission = false;
+
public function __construct($file)
{
$data = json_decode(file_get_contents($file), true);
@@ -298,6 +303,7 @@ class RunModeModuleConfig
$this->loadType($data, 'noSysconfig', 'boolean');
$this->loadType($data, 'allowGenericEditor', 'boolean');
$this->loadType($data, 'deleteUrlSnippet', 'string');
+ $this->loadType($data, 'permission', 'string');
}
private function loadType($data, $key, $type)
@@ -311,4 +317,10 @@ class RunModeModuleConfig
$this->{$key} = $data[$key];
return true;
}
+
+ public function userHasPermission($locationId)
+ {
+ return $this->permission === false || User::hasPermission($this->permission, $locationId);
+ }
+
}
diff --git a/modules-available/runmode/page.inc.php b/modules-available/runmode/page.inc.php
index 8feb097e..9f2c2f44 100644
--- a/modules-available/runmode/page.inc.php
+++ b/modules-available/runmode/page.inc.php
@@ -14,79 +14,142 @@ class Page_RunMode extends Page
Util::redirect('?do=main');
}
$action = Request::post('action', false, 'string');
- if ($action !== false) {
- $this->handleAction($action);
+ if ($action === 'save-mode') {
+ $this->handleSaveMode();
+ } elseif ($action === 'delete-machine') {
+ $this->handleDeleteMachine();
+ }
+ if (Request::isPost()) {
Util::redirect('?do=runmode');
}
}
- private function handleAction($action)
+ private function handleSaveMode()
{
- if ($action === 'save-mode') {
- $machines = array_filter(Request::post('machines', [], 'array'), 'is_string');
- $module = Request::post('module', false, 'string');
- $modeId = Request::post('modeid', false, 'string');
- $modConfig = RunMode::getModuleConfig($module);
- if ($modConfig === false) {
- Message::addError('runmode.module-hasnt-runmode', $module);
- return;
- }
- if (!$modConfig->allowGenericEditor) {
- Message::addError('runmode.cannot-edit-module', $module);
- return;
- }
- $test = RunMode::getModeName($module, $modeId);
- if ($test === false) {
- Message::addError('runmode.invalid-modeid', $module, $modeId);
- return;
- }
- $active = 0;
- foreach ($machines as $machine) {
- $oldMode = RunMode::getRunMode($machine, 0);
- if ($oldMode !== false) {
- $oldModule = RunMode::getModuleConfig($oldMode['module']);
- if ($oldModule !== false && (!$oldModule->allowGenericEditor || $oldModule->deleteUrlSnippet !== false)) {
- Message::addError('runmode.machine-still-assigned', $machine, $oldMode['module']);
- continue;
- }
+ $machines = array_unique(array_filter(Request::post('machines', [], 'array'), 'is_string'));
+ $module = Request::post('module', false, 'string');
+ $modeId = Request::post('modeid', false, 'string');
+ $modConfig = RunMode::getModuleConfig($module);
+ if ($modConfig === false) {
+ Message::addError('runmode.module-hasnt-runmode', $module);
+ return;
+ }
+ if (!$modConfig->allowGenericEditor) {
+ Message::addError('runmode.cannot-edit-module', $module);
+ return;
+ }
+ $test = RunMode::getModeName($module, $modeId);
+ if ($test === false) {
+ Message::addError('runmode.invalid-modeid', $module, $modeId);
+ return;
+ }
+ // Query existing entries first (for delete - see below)
+ $existing = [];
+ if ($modConfig->permission !== false) {
+ $existing = RunMode::getForMode($module, $modeId, true, true);
+ }
+ // Before doing anything, check if the user has the proper permission for any location - if not, nothing to do
+ if (!$modConfig->userHasPermission(null)) {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=runmode');
+ }
+ $active = 0;
+ foreach ($machines as $machine) {
+ if (isset($existing[$machine])) {
+ if (!$modConfig->userHasPermission($existing[$machine]['locationid'])) {
+ // Machine was already assigned to this runmode, and user has no permission for its location
+ unset($existing[$machine]);
+ continue; // So keep it as-is and skip
}
- $ret = RunMode::setRunMode($machine, $module, $modeId, null, null);
- if ($ret) {
- $active++;
+ // User has permission to add this existing machine, keep going so meta data could be updated
+ unset($existing[$machine]);
+ } else {
+ // Not existing yet in this module/mode combo, but check if it is assigned to some other run mode
+ $machineLocation = false;
+ $oldMachineMode = RunMode::getRunMode($machine, RunMode::DATA_MACHINE_DATA | RunMode::DATA_DETAILED);
+ if ($oldMachineMode !== false) {
+ $machineLocation = $oldMachineMode['locationid'];
+ $oldModule = RunMode::getModuleConfig($oldMachineMode['module']);
+ if ($oldModule !== false) {
+ if ($oldMachineMode['module'] !== $module || $oldMachineMode['modeid'] !== $modeId) {
+ if (!$oldModule->allowGenericEditor || $oldModule->deleteUrlSnippet !== false) {
+ Message::addError('runmode.machine-still-assigned', $machine, $oldMachineMode['module']);
+ continue;
+ }
+ }
+ // Permissions for old runmode
+ if (!$oldModule->userHasPermission($oldMachineMode['locationid'])) {
+ // Show same error message as above - might help the user figure out they have no perm to remove it
+ Message::addError('runmode.machine-still-assigned', $machine, $oldMachineMode['module']);
+ continue;
+ }
+ }
} else {
- Message::addError('runmode.machine-not-found', $machine);
+ // Not existing, no old mode - query machine to get location, so we can do a perm-check for new loc
+ $m = Statistics::getMachine($machine, Machine::NO_DATA);
+ if ($m !== false) {
+ $machineLocation = $m->locationid;
+ }
+ }
+ if ($machineLocation !== false && !$modConfig->userHasPermission($machineLocation)) {
+ Message::addError('runmode.machine-no-permission', $machine);
+ continue;
}
}
+ $ret = RunMode::setRunMode($machine, $module, $modeId, null, null);
+ if ($ret) {
+ $active++;
+ } else {
+ Message::addError('runmode.machine-not-found', $machine);
+ }
+ }
+ // Make sure inaccessible machines (no permission for location) are preserved on delete
+ // Add existing but inaccessible to list
+ foreach ($existing as $e) {
+ if (!$modConfig->userHasPermission($e['locationid'])) {
+ $machines[] = $e['machineuuid'];
+ }
+ }
+ if ($modConfig->deleteUrlSnippet === false) {
$deleted = Database::exec('DELETE FROM runmode
WHERE module = :module AND modeid = :modeId AND machineuuid NOT IN (:machines)',
compact('module', 'modeId', 'machines'));
- Message::addSuccess('runmode.enabled-removed-save', $active, $deleted);
- Util::redirect('?do=runmode&module=' . $module . '&modeid=' . $modeId, true);
- } elseif ($action === 'delete-machine') {
- $machineuuid = Request::post('machineuuid', false, 'string');
- if ($machineuuid === false) {
- Message::addError('main.parameter-missing', 'machineuuid');
- return;
- }
- $mode = RunMode::getRunMode($machineuuid);
- if ($mode === false) {
- Message::addError('runmode.machine-not-found', $machineuuid);
- return;
- }
- $modConfig = RunMode::getModuleConfig($mode['module']);
- if ($modConfig === false) {
- Message::addError('module-hasnt-runmode', $mode['moduleName']);
- return;
- }
- if (!$modConfig->allowGenericEditor) {
- Message::addError('runmode.cannot-edit-module', $mode['moduleName']);
- return;
- }
- if (RunMode::setRunMode($machineuuid, null, null)) {
- Message::addSuccess('machine-removed', $machineuuid);
- } else {
- Message::addWarning('machine-not-runmode', $machineuuid);
- }
+ } else {
+ $deleted = 0;
+ }
+ Message::addSuccess('runmode.enabled-removed-save', $active, $deleted);
+ Util::redirect('?do=runmode&module=' . $module . '&modeid=' . $modeId, true);
+ }
+
+ private function handleDeleteMachine()
+ {
+ $machineuuid = Request::post('machineuuid', false, 'string');
+ if ($machineuuid === false) {
+ Message::addError('main.parameter-missing', 'machineuuid');
+ return;
+ }
+ $mode = RunMode::getRunMode($machineuuid, RunMode::DATA_MACHINE_DATA | RunMode::DATA_DETAILED);
+ if ($mode === false) {
+ Message::addError('runmode.machine-not-found', $machineuuid);
+ return;
+ }
+ $modConfig = RunMode::getModuleConfig($mode['module']);
+ if ($modConfig === false) {
+ Message::addError('module-hasnt-runmode', $mode['moduleName']);
+ return;
+ }
+ if (!$modConfig->allowGenericEditor || $modConfig->deleteUrlSnippet !== false) {
+ Message::addError('runmode.cannot-edit-module', $mode['moduleName']);
+ return;
+ }
+ if (!$modConfig->userHasPermission($mode['locationid'])) {
+ Message::addError('runmode.machine-no-permission', $machineuuid);
+ return;
+ }
+ if (RunMode::setRunMode($machineuuid, null, null)) {
+ Message::addSuccess('machine-removed', $machineuuid);
+ } else {
+ Message::addWarning('machine-not-runmode', $machineuuid);
}
}
@@ -117,7 +180,13 @@ class Page_RunMode extends Page
$modeId = Request::get('modeid', false, 'string');
if ($modeId !== false) {
// Show edit page for specific module-mode combo
- $this->renderModuleMode($module, $modeId);
+ $this->renderModuleMode($module, $modeId, $config);
+ return;
+ }
+ // Permissions
+ if (!$config->userHasPermission(null) && !User::hasPermission('list-all')) {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=runmode');
return;
}
// Show list of machines with assigned mode for this module
@@ -152,6 +221,16 @@ class Page_RunMode extends Page
$modules[$row['module']]['list'][] = $row;
}
foreach ($modules as $moduleId => $rows) {
+ if ($onlyModule === false) {
+ // Permissions - not required if rendering specific module, since it's been already done
+ if ($rows['config']->userHasPermission(null)) {
+ $disabled = '';
+ } elseif (User::hasPermission('list-all')) {
+ $disabled = 'disabled';
+ } else {
+ continue;
+ } // </Permissions>
+ }
$module = Module::get($moduleId);
if ($module === false)
continue;
@@ -161,7 +240,8 @@ class Page_RunMode extends Page
'modulename' => $module->getDisplayName(),
'module' => $moduleId,
'canedit' => $config !== false && $config->allowGenericEditor && $config->deleteUrlSnippet === false,
- 'deleteUrl' => $config->deleteUrlSnippet
+ 'deleteUrl' => $config->deleteUrlSnippet,
+ 'disabled' => $disabled,
));
}
}
@@ -169,8 +249,9 @@ class Page_RunMode extends Page
/**
* @param \Module $module
* @param string $modeId
+ * @param \RunModeModuleConfig $config
*/
- private function renderModuleMode($module, $modeId)
+ private function renderModuleMode($module, $modeId, $config)
{
$moduleId = $module->getIdentifier();
$modeName = RunMode::getModeName($moduleId, $modeId);
@@ -186,39 +267,78 @@ class Page_RunMode extends Page
Message::addError('runmode.cannot-edit-module', $moduleId);
Util::redirect($redirect);
}
+ // Permissions
+ if ($config->userHasPermission(null)) {
+ $disabled = '';
+ } elseif (User::hasPermission('list-all')) {
+ $disabled = 'disabled';
+ } else {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=runmode');
+ return;
+ }
+ $machines = RunMode::getForMode($module, $modeId, true);
+ if ($config->permission !== false) {
+ $allowed = User::getAllowedLocations($config->permission);
+ $machines = array_values(array_filter($machines, function ($item) use ($allowed) {
+ return in_array($item['locationid'], $allowed);
+ }));
+ }
Render::addTemplate('machine-selector', [
'module' => $moduleId,
'modeid' => $modeId,
'moduleName' => $module->getDisplayName(),
'modeName' => $modeName,
- 'machines' => json_encode(RunMode::getForMode($module, $modeId, true)),
+ 'machines' => json_encode($machines),
'redirect' => $redirect,
+ 'disabled' => $disabled,
+ 'add-only' => $config->deleteUrlSnippet !== false,
]);
}
protected function doAjax()
{
$action = Request::any('action', false, 'string');
+ if ($action !== 'getmachines')
+ return;
+ $query = Request::get('query', false, 'string');
+ if (strlen($query) < 2)
+ return;
- if ($action === 'getmachines') {
- $query = Request::get('query', false, 'string');
-
- $result = Database::simpleQuery('SELECT m.machineuuid, m.macaddr, m.clientip, m.hostname, m.locationid, '
- . 'r.module, r.modeid '
- . 'FROM machine m '
- . 'LEFT JOIN runmode r USING (machineuuid) '
- . 'WHERE machineuuid LIKE :query '
- . ' OR macaddr LIKE :query '
- . ' OR clientip LIKE :query '
- . ' OR hostname LIKE :query '
- . ' LIMIT 100', ['query' => "%$query%"]);
+ User::load();
+ $config = RunMode::getModuleConfig(Request::any('module', '', 'string'));
+ $returnObject = ['machines' => []];
- $returnObject = [
- 'machines' => $result->fetchAll(PDO::FETCH_ASSOC)
- ];
+ if ($config !== false) {
+ $params = ['query' => "%$query%"];
+ if ($config->permission === false) {
+ // Global
+ $condition = '1';
+ } else {
+ $params['locations'] = User::getAllowedLocations($config->permission);
+ $condition = 'locationid IN (:locations)';
+ if (in_array(0, $params['locations'])) {
+ $condition .= ' OR locationid IS NULL';
+ }
+ }
+ if ($config->permission === false || !empty($params['locations'])) {
+ $result = Database::simpleQuery("SELECT m.machineuuid, m.macaddr, m.clientip, m.hostname, m.locationid,
+ r.module, r.modeid
+ FROM machine m
+ LEFT JOIN runmode r USING (machineuuid)
+ WHERE ($condition) AND (machineuuid LIKE :query
+ OR macaddr LIKE :query
+ OR clientip LIKE :query
+ OR hostname LIKE :query)
+ LIMIT 100", $params);
- echo json_encode($returnObject);
+ $returnObject = [
+ 'machines' => $result->fetchAll(PDO::FETCH_ASSOC)
+ ];
+ }
}
+ echo json_encode($returnObject);
+
}
} \ No newline at end of file
diff --git a/modules-available/runmode/permissions/permissions.json b/modules-available/runmode/permissions/permissions.json
new file mode 100644
index 00000000..53dfdab0
--- /dev/null
+++ b/modules-available/runmode/permissions/permissions.json
@@ -0,0 +1,5 @@
+{
+ "list-all": {
+ "location-aware": false
+ }
+} \ No newline at end of file
diff --git a/modules-available/runmode/templates/machine-selector.html b/modules-available/runmode/templates/machine-selector.html
index 7f37f5a2..8b608f7e 100644
--- a/modules-available/runmode/templates/machine-selector.html
+++ b/modules-available/runmode/templates/machine-selector.html
@@ -1,12 +1,7 @@
<h1>{{lang_assignRunmodeToMachine}}</h1>
<h2>{{moduleName}} // {{modeName}}</h2>
-<p>{{lang_assignMachineIntroText}}</p>
-<div class="hidden">
- {{#machines}}
- <div id="qex-{{machineuuid}}">{{hostname}}</div>
- {{/machines}}
-</div>
+<p>{{lang_assignMachineIntroText}}</p>
<h4>{{lang_addNewMachines}}</h4>
<form method="post" action="?do=runmode">
@@ -15,13 +10,18 @@
<input type="hidden" name="module" value="{{module}}" id="i-module">
<input type="hidden" name="modeid" value="{{modeid}}" id="i-modeid">
<input type="hidden" name="redirect" value="{{redirect}}">
- <select id="machine-sel" name="machines[]" multiple>
+ <select id="machine-sel" name="machines[]" multiple {{disabled}}>
</select>
<div class="buttonbar">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <button type="submit" class="btn btn-primary" {{disabled}}>{{lang_save}}</button>
</div>
</form>
+{{#add-only}}
+ <h4>{{lang_existingClients}}</h4>
+ <div id="existing-list"></div>
+{{/add-only}}
+
<script type="application/javascript"><!--
const MODULE = document.getElementById('i-module').value;
@@ -58,7 +58,7 @@ function loadMachines(query, callback) {
}
}
$.ajax({
- url: '?do=runmode&action=getmachines&query=' + encodeURIComponent(query),
+ url: '?do=runmode&action=getmachines&module={{module}}&query=' + encodeURIComponent(query),
type: 'GET',
dataType: 'json',
error: function () {
@@ -120,6 +120,17 @@ document.addEventListener('DOMContentLoaded', function () {
})();
});
var old = {{{machines}}} || [];
+ var list = $('#existing-list');
+ if (list.length !== 0) {
+ old.forEach(function (x) { list.append(renderMachineOption(x, function(str) {
+ return (str + '')
+ .replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;');
+ }))});
+ old = [];
+ }
var $box = $('#machine-sel').selectize({
options: old,
items: old.map(function(x) { return x.machineuuid; }),
@@ -132,7 +143,7 @@ document.addEventListener('DOMContentLoaded', function () {
load: loadMachines,
maxItems: null,
sortField: 'hostname',
- sortDirection: 'asc',
+ sortDirection: 'asc'
});
});
diff --git a/modules-available/runmode/templates/module-machine-list.html b/modules-available/runmode/templates/module-machine-list.html
index 283fb393..89424922 100644
--- a/modules-available/runmode/templates/module-machine-list.html
+++ b/modules-available/runmode/templates/module-machine-list.html
@@ -36,12 +36,12 @@
</td>
<td class="text-center">
{{#canedit}}
- <button type="submit" class="btn btn-danger btn-sm" name="machineuuid" value="{{machineuuid}}">
+ <button type="submit" class="btn btn-danger btn-sm" name="machineuuid" value="{{machineuuid}}" {{disabled}}>
<span class="glyphicon glyphicon-trash"></span>
</button>
{{/canedit}}
{{#deleteUrl}}
- <a class="btn btn-default btn-sm" href="?do={{module}}&amp;{{deleteUrl}}{{modeid}}">
+ <a class="btn btn-default btn-sm {{disabled}}" href="?do={{module}}&amp;{{deleteUrl}}{{modeid}}">
<span class="glyphicon glyphicon-edit"></span>
</a>
{{/deleteUrl}}