diff options
author | root | 2019-02-19 18:53:50 +0100 |
---|---|---|
committer | root | 2019-02-19 18:53:50 +0100 |
commit | 0ad4c0f8196b61699754762aacbaab0223478ab9 (patch) | |
tree | de434c4aea8d07ecd01cd3badd48d057d62c2d1b /modules-available/permissionmanager | |
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) | |
download | slx-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/permissionmanager')
25 files changed, 902 insertions, 476 deletions
diff --git a/modules-available/permissionmanager/api.inc.php b/modules-available/permissionmanager/api.inc.php deleted file mode 100644 index 0d84ebce..00000000 --- a/modules-available/permissionmanager/api.inc.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php - -echo json_encode(array( - 'key' => 'value', - 'number' => 123, - 'list' => array(1,2,3,4,5,6,'foo') -)); diff --git a/modules-available/permissionmanager/clientscript.js b/modules-available/permissionmanager/clientscript.js index 4770fa6a..90d66688 100644 --- a/modules-available/permissionmanager/clientscript.js +++ b/modules-available/permissionmanager/clientscript.js @@ -10,36 +10,21 @@ document.addEventListener("DOMContentLoaded", function() { plugins: ["remove_button"] })[0].selectize; - // If Site gets refreshed, all data-selectizeCounts will be reset to 0, so delete the filters from the selectize - selectize.clear(); - - selectize.on("item_add", function (value, $item) { - // When first item gets added the filter isn't empty anymore, so hide all rows - if (selectize.items.length === 1) { - $(".dataTable tbody").find("tr").hide(); - } - // Find all rows which shall be shown and increase their counter by 1 - $(".roleid-" + value).closest("tr").each(function () { - $(this).data("selectizeCount", $(this).data("selectizeCount") + 1); - $(this).show(); - }); - }); - - selectize.on("item_remove", function (value, $item) { - // When no items in the filter, show all rows again - if (selectize.items.length === 0) { - $(".dataTable tbody").find("tr").show(); + var $body = $(".dataTable tbody"); + var filterFunc = function(value) { + var selected = selectize.getValue(); + if (!selected || !selected.length) { + $body.find("tr").show(); } else { - // Find all rows which have the delete role, decrease their counter by 1 - $(".roleid-" + value).closest("tr").each(function () { - $(this).data("selectizeCount", $(this).data("selectizeCount") - 1); - // If counter is 0, hide the row (no filter given to show the row anymore) - if ($(this).data("selectizeCount") === 0) { - $(this).closest("tr").hide(); - } - }); + $body.find("tr").hide(); + var str = 'tr.roleid-' + selected.join('.roleid-'); + $body.find(str).show(); } - }); + }; + + selectize.on("item_add", filterFunc); + + selectize.on("item_remove",filterFunc); } $("tr").on("click", function(e) { @@ -47,8 +32,4 @@ document.addEventListener("DOMContentLoaded", function() { $(this).find("input[type=checkbox]").trigger("click"); } }); - - $("form input").keydown(function(e) { - if (e.keyCode === 13) e.preventDefault(); - }); });
\ No newline at end of file diff --git a/modules-available/permissionmanager/config.json b/modules-available/permissionmanager/config.json index c92e917a..25b61de3 100644 --- a/modules-available/permissionmanager/config.json +++ b/modules-available/permissionmanager/config.json @@ -1,4 +1,8 @@ { - "category":"main.content", - "dependencies": [ "locations", "js_stupidtable", "bootstrap_switch", "js_selectize" ] -} + "category": "main.content", + "dependencies": [ + "locations", + "js_stupidtable", + "js_selectize" + ] +}
\ No newline at end of file diff --git a/modules-available/permissionmanager/hooks/translation-global.inc.php b/modules-available/permissionmanager/hooks/translation-global.inc.php new file mode 100644 index 00000000..4810a719 --- /dev/null +++ b/modules-available/permissionmanager/hooks/translation-global.inc.php @@ -0,0 +1,38 @@ +<?php + +$HANDLER = array(); + +if (file_exists('modules/' . $moduleName . '/permissions/permissions.json')) { + + /** + * List of valid subsections + */ + $HANDLER['subsections'] = array( + 'permissions' + ); + + /* + * Handlers for the subsections that will return an array of expected tags. + * This is optional, if you don't want to define expected tags, don't create a function. + */ + + /** + * Configuration categories. + * + * @param \Module $module + * @return array + */ + $HANDLER['grep_permissions'] = function ($module) { + $file = 'modules/' . $module->getIdentifier() . '/permissions/permissions.json'; + if (!file_exists($file)) + return []; + $array = json_decode(file_get_contents($file), true); + if (!is_array($array)) + return []; + foreach ($array as &$entry) { + $entry = true; + } + return $array; + }; + +} diff --git a/modules-available/permissionmanager/inc/getpermissiondata.inc.php b/modules-available/permissionmanager/inc/getpermissiondata.inc.php index 982fa0b7..660c94ae 100644 --- a/modules-available/permissionmanager/inc/getpermissiondata.inc.php +++ b/modules-available/permissionmanager/inc/getpermissiondata.inc.php @@ -1,27 +1,32 @@ <?php -class GetPermissionData { +class GetPermissionData +{ + + const WITH_USER_COUNT = 1; + const WITH_LOCATION_COUNT = 2; /** * Get data for all users. * * @return array array of users (each with userid, username and roles (each with roleid and rolename)) */ - public static function getUserData() { + public static function getUserData() + { $res = Database::simpleQuery("SELECT user.userid AS userid, user.login AS login, role.rolename AS rolename, role.roleid AS roleid FROM user - LEFT JOIN user_x_role ON user.userid = user_x_role.userid - LEFT JOIN role ON user_x_role.roleid = role.roleid + LEFT JOIN role_x_user ON user.userid = role_x_user.userid + LEFT JOIN role ON role_x_user.roleid = role.roleid "); - $userdata= array(); + $userdata = array(); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $userdata[$row['userid'].' '.$row['login']][] = array( + $userdata[$row['userid'] . ' ' . $row['login']][] = array( 'roleid' => $row['roleid'], 'rolename' => $row['rolename'] ); } $data = array(); - foreach($userdata AS $user => $roles) { + foreach ($userdata AS $user => $roles) { $user = explode(" ", $user, 2); $data[] = array( 'userid' => $user[0], @@ -37,8 +42,9 @@ class GetPermissionData { * * @return array array of locations (each including the roles that have permissions for them) */ - public static function getLocationData() { - $res = Database::simpleQuery("SELECT role.roleid as roleid, rolename, GROUP_CONCAT(COALESCE(locationid, 0)) AS locationids FROM role + public static function getLocationData() + { + $res = Database::simpleQuery("SELECT role.roleid AS roleid, rolename, GROUP_CONCAT(COALESCE(locationid, 0)) AS locationids FROM role INNER JOIN role_x_location ON role.roleid = role_x_location.roleid GROUP BY roleid ORDER BY rolename ASC"); $locations = Location::getLocations(0, 0, false, true); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { @@ -61,18 +67,26 @@ class GetPermissionData { /** * Get all roles. * + * @param int $flags Bitmask specifying additional data to fetch (WITH_* constants of this class) * @return array array roles (each with roleid and rolename) */ - public static function getRoles() { - $res = Database::simpleQuery("SELECT roleid, rolename FROM role ORDER BY rolename ASC"); - $data = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $data[] = array( - 'roleid' => $row['roleid'], - 'rolename' => $row['rolename'] - ); + public static function getRoles($flags = 0) + { + $cols = $joins = ''; + if ($flags & self::WITH_USER_COUNT) { + $cols .= ', Count(DISTINCT rxu.userid) AS users'; + $joins .= ' LEFT JOIN role_x_user rxu ON (r.roleid = rxu.roleid)'; } - return $data; + if ($flags & self::WITH_LOCATION_COUNT) { + $cols .= ', Count(DISTINCT rxl.locationid) AS locations'; + $joins .= ' LEFT JOIN role_x_location rxl ON (r.roleid = rxl.roleid)'; + } + if (!empty($joins)) { + $joins .= ' GROUP BY r.roleid'; + } + return Database::queryAll("SELECT r.roleid, r.rolename, r.roledescription $cols FROM role r + $joins + ORDER BY rolename ASC"); } /** @@ -81,8 +95,9 @@ class GetPermissionData { * @param string $roleid id of the role * @return array array containing an array of permissions and an array of locations */ - public static function getRoleData($roleid) { - $query = "SELECT roleid, rolename FROM role WHERE roleid = :roleid"; + public static function getRoleData($roleid) + { + $query = "SELECT roleid, rolename, roledescription FROM role WHERE roleid = :roleid"; $data = Database::queryFirst($query, array("roleid" => $roleid)); $query = "SELECT roleid, locationid FROM role_x_location WHERE roleid = :roleid"; $res = Database::simpleQuery($query, array("roleid" => $roleid)); diff --git a/modules-available/permissionmanager/inc/permissiondbupdate.inc.php b/modules-available/permissionmanager/inc/permissiondbupdate.inc.php index ffe5fac0..0cd89b3a 100644 --- a/modules-available/permissionmanager/inc/permissiondbupdate.inc.php +++ b/modules-available/permissionmanager/inc/permissiondbupdate.inc.php @@ -1,67 +1,107 @@ <?php -class PermissionDbUpdate { +class PermissionDbUpdate +{ /** - * Insert all user/role combinations into the user_x_role table. + * Insert all user/role combinations into the role_x_user table. * - * @param array $users userids - * @param array $roles roleids + * @param int[] $users userids + * @param int[] $roles roleids */ - public static function addRoleToUser($users, $roles) { - $query = "INSERT IGNORE INTO user_x_role (userid, roleid) VALUES (:userid, :roleid)"; - foreach($users AS $userid) { + public static function addRoleToUser($users, $roles) + { + if (empty($users) || empty($roles)) + return 0; + $arg = array(); + foreach ($users AS $userid) { foreach ($roles AS $roleid) { - Database::exec($query, array("userid" => $userid, "roleid" => $roleid)); + $arg[] = compact('userid', 'roleid'); } } + return Database::exec("INSERT IGNORE INTO role_x_user (userid, roleid) VALUES :arg", + ['arg' => $arg]); } /** - * Remove all user/role combinations from the user_x_role table. + * Remove all user/role combinations from the role_x_user table. * - * @param array $users userids - * @param array $roles roleids + * @param int[] $users userids + * @param int[] $roles roleids */ - public static function removeRoleFromUser($users, $roles) { - $query = "DELETE FROM user_x_role WHERE userid IN (:users) AND roleid IN (:roles)"; - Database::exec($query, array("users" => $users, "roles" => $roles)); + public static function removeRoleFromUser($users, $roles) + { + if (empty($users) || empty($roles)) + return 0; + $query = "DELETE FROM role_x_user WHERE userid IN (:users) AND roleid IN (:roles)"; + return Database::exec($query, array("users" => $users, "roles" => $roles)); + } + + /** + * Assign the specified roles to given users, removing any roles from the users + * that are not in the given set. + * + * @param int[] $users list of user ids + * @param int[] $roles list of role ids + */ + public static function setRolesForUser($users, $roles) + { + $count = Database::exec("DELETE FROM role_x_user WHERE userid in (:users) AND roleid NOT IN (:roles)", + compact('users', 'roles')); + return $count + self::addRoleToUser($users, $roles); } /** * Delete role from the role table. * - * @param string $roleid roleid + * @param int $roleid roleid */ - public static function deleteRole($roleid) { - Database::exec("DELETE FROM role WHERE roleid = :roleid", array("roleid" => $roleid)); + public static function deleteRole($roleid) + { + return Database::exec("DELETE FROM role WHERE roleid = :roleid", array("roleid" => $roleid)); } /** * Save changes to a role or create a new one. * - * @param string $rolename rolename - * @param array $locations array of locations - * @param array $permissions array of permissions - * @param string|null $roleid roleid or null if the role does not exist yet + * @param string $roleName rolename + * @param int[] $locations array of locations + * @param string[] $permissions array of permissions + * @param int|null $roleId roleid or null if the role does not exist yet */ - public static function saveRole($rolename, $locations, $permissions, $roleid = NULL) { - if ($roleid) { - Database::exec("UPDATE role SET rolename = :rolename WHERE roleid = :roleid", - array("rolename" => $rolename, "roleid" => $roleid)); - Database::exec("DELETE FROM role_x_location WHERE roleid = :roleid", array("roleid" => $roleid)); - Database::exec("DELETE FROM role_x_permission WHERE roleid = :roleid", array("roleid" => $roleid)); + public static function saveRole($roleName, $roleDescription, $locations, $permissions, $roleId = null) + { + foreach ($permissions as &$permission) { + $permission = strtolower($permission); + } + unset($permission); + if ($roleId) { + Database::exec("UPDATE role SET rolename = :rolename, roledescription = :roledescription WHERE roleid = :roleid", + array("rolename" => $roleName, "roledescription" => $roleDescription, "roleid" => $roleId)); + Database::exec("DELETE FROM role_x_location + WHERE roleid = :roleid AND (locationid NOT IN (:locations) OR locationid IS NULL)", + array("roleid" => $roleId, 'locations' => $locations)); + Database::exec("DELETE FROM role_x_permission + WHERE roleid = :roleid AND permissionid NOT IN (:permissions)", + array("roleid" => $roleId, 'permissions' => $permissions)); } else { - Database::exec("INSERT INTO role (rolename) VALUES (:rolename)", array("rolename" => $rolename)); - $roleid = Database::lastInsertId(); + Database::exec("INSERT INTO role (rolename, roledescription) VALUES (:rolename, :roledescription)", + array("rolename" => $roleName, "roledescription" => $roleDescription)); + $roleId = Database::lastInsertId(); } - foreach ($locations as $locationid) { - Database::exec("INSERT INTO role_x_location (roleid, locationid) VALUES (:roleid, :locationid)", - array("roleid" => $roleid, "locationid" => $locationid)); + + if (!empty($locations)) { + $arg = array_map(function ($loc) use ($roleId) { + return compact('roleId', 'loc'); + }, $locations); + Database::exec("INSERT IGNORE INTO role_x_location (roleid, locationid) VALUES :arg", ['arg' => $arg]); } - foreach ($permissions as $permissionid) { - Database::exec("INSERT INTO role_x_permission (roleid, permissionid) VALUES (:roleid, :permissionid)", - array("roleid" => $roleid, "permissionid" => $permissionid)); + + if (!empty($permissions)) { + $arg = array_map(function ($perm) use ($roleId) { + return compact('roleId', 'perm'); + }, $permissions); + Database::exec("INSERT IGNORE INTO role_x_permission (roleid, permissionid) VALUES :arg", ['arg' => $arg]); } } diff --git a/modules-available/permissionmanager/inc/permissionutil.inc.php b/modules-available/permissionmanager/inc/permissionutil.inc.php index 5ff41046..a3a2b610 100644 --- a/modules-available/permissionmanager/inc/permissionutil.inc.php +++ b/modules-available/permissionmanager/inc/permissionutil.inc.php @@ -2,6 +2,44 @@ class PermissionUtil { + + /** + * Generate all possible variants to match against, eg. $permissionid = a.b.c then we get: + * [ *, a.*, a.b.*, a.b.c ] + * In case $permissionid ends with an asterisk, also set $wildcard and $wclen, e.g. + * $permissionid = a.b.* --> $wildcard = a.b. and $wclen = 4 + * + * @param $permission string|string[] permission to mangle + * @param string[] $compare all the generated variants + * @param string|false $wildcard if $permission is a wildcard string this returns the matching variant + * @param int|false $wclen if $permission is a wildcard string, this is the length of the matching variant + */ + private static function makeComparisonVariants($permission, &$compare, &$wildcard, &$wclen) + { + if (!is_array($permission)) { + $permission = explode('.', $permission); + } + $partCount = count($permission); + $compare = []; + for ($i = 0; $i < $partCount; ++$i) { + $compare[] = $permission[0]; + } + for ($i = 1; $i < $partCount; ++$i) { + $compare[$i - 1] .= '.*'; + for ($j = $i; $j < $partCount; ++$j) { + $compare[$j] .= '.' . $permission[$i]; + } + } + $compare[] = '*'; + + if ($permission[$partCount - 1] === '*') { + $wildcard = substr($compare[$partCount - 1], 0, -1); + $wclen = strlen($wildcard); + } else { + $wclen = $wildcard = false; + } + } + /** * Check if the user has the given permission (for the given location). * @@ -10,26 +48,48 @@ class PermissionUtil * @param int|null $locationid locationid to check or null if the location should be disregarded * @return bool true if user has permission, false if not */ - public static function userHasPermission($userid, $permissionid, $locationid) { - $locations = array(); - if (!is_null($locationid)) { - $locations = Location::getLocationRootChain($locationid); - if (count($locations) == 0) return false; - else $locations[] = 0; + public static function userHasPermission($userid, $permissionid, $locationid) + { + $permissionid = strtolower($permissionid); + self::validatePermission($permissionid); + $parts = explode('.', $permissionid); + // Special case: To prevent lockout, userid === 1 always has permissionmanager.* + if ($parts[0] === 'permissionmanager' && User::getId() === 1) + return true; + // Limit query to first part of permissionid, which is always the module id + $prefix = $parts[0] . '.%'; + if (is_null($locationid)) { + $res = Database::simpleQuery("SELECT permissionid FROM role_x_permission + INNER JOIN role_x_user USING (roleid) + WHERE role_x_user.userid = :userid AND (permissionid LIKE :prefix OR permissionid LIKE '*')", + compact('userid', 'prefix')); + } else { + if ($locationid === 0) { + $locations = [0]; + } else { + $locations = Location::getLocationRootChain($locationid); + if (empty($locations)) { // Non-existent location, still continue as user might have global perms + $locations = [0]; + } + } + $res = Database::simpleQuery("SELECT permissionid FROM role_x_permission + INNER JOIN role_x_user USING (roleid) + INNER JOIN role_x_location USING (roleid) + WHERE role_x_user.userid = :userid AND (permissionid LIKE :prefix OR permissionid LIKE '*') + AND (locationid IN (:locations) OR locationid IS NULL)", + compact('userid', 'prefix', 'locations')); } + // Quick bailout - no results + if ($res->rowCount() === 0) + return false; - $res = Database::simpleQuery("SELECT permissionid, locationid FROM user_x_role - INNER JOIN role_x_permission ON user_x_role.roleid = role_x_permission.roleid - LEFT JOIN (SELECT roleid, COALESCE(locationid, 0) AS locationid FROM role_x_location) t1 - ON role_x_permission.roleid = t1.roleid - WHERE user_x_role.userid = :userid", array("userid" => $userid)); - + // Compare to database result + self::makeComparisonVariants($parts, $compare, $wildcard, $wclen); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $userPermission = rtrim($row["permissionid"], ".*")."."; - if ((is_null($locationid) || (!is_null($row["locationid"]) && in_array($row["locationid"], $locations))) && - (substr($permissionid.".", 0, strlen($userPermission)) === $userPermission || $userPermission === ".")) { + if (in_array($row['permissionid'], $compare, true)) + return true; + if ($wildcard !== false && strncmp($row['permissionid'], $wildcard, $wclen) === 0) return true; - } } return false; } @@ -41,26 +101,40 @@ class PermissionUtil * @param string $permissionid permissionid to check * @return array array of locationids where the user has the given permission */ - public static function getAllowedLocations($userid, $permissionid) { - - $res = Database::simpleQuery("SELECT permissionid, COALESCE(locationid, 0) AS locationid FROM user_x_role - INNER JOIN role_x_permission ON user_x_role.roleid = role_x_permission.roleid - INNER JOIN role_x_location ON role_x_permission.roleid = role_x_location.roleid - WHERE user_x_role.userid = :userid", array("userid" => $userid)); + public static function getAllowedLocations($userid, $permissionid) + { + $permissionid = strtolower($permissionid); + self::validatePermission($permissionid); + $parts = explode('.', $permissionid); + // Special case: To prevent lockout, userid === 1 always has permissionmanager.* + if ($parts[0] === 'permissionmanager' && User::getId() === 1) { + $allowedLocations = [true]; + } else { + // Limit query to first part of permissionid, which is always the module id + $prefix = $parts[0] . '.%'; + $res = Database::simpleQuery("SELECT permissionid, locationid FROM role_x_permission + INNER JOIN role_x_user USING (roleid) + INNER JOIN role_x_location USING (roleid) + WHERE role_x_user.userid = :userid AND (permissionid LIKE :prefix OR permissionid LIKE '*')", + compact('userid', 'prefix')); - $allowedLocations = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $userPermission = rtrim($row["permissionid"], ".*")."."; - if (substr($permissionid.".", 0, strlen($userPermission)) === $userPermission || $userPermission === ".") { - $allowedLocations[$row["locationid"]] = 1; + // Gather locationid from relevant rows + self::makeComparisonVariants($parts, $compare, $wildcard, $wclen); + $allowedLocations = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + if (in_array($row['permissionid'], $compare, true) + || ($wildcard !== false && strncmp($row['permissionid'], $wildcard, $wclen) === 0)) { + $allowedLocations[(int)$row['locationid']] = true; + } } } - $allowedLocations = array_keys($allowedLocations); $locations = Location::getTree(); - if (in_array("0", $allowedLocations)) { - $allowedLocations = array_map("intval", Location::extractIds($locations)); - $allowedLocations[] = 0; + if (isset($allowedLocations[0])) { + // Trivial case - have permission for all locations, so populate list with all valid locationds + $allowedLocations = Location::extractIds($locations); + $allowedLocations[] = 0; // .. plus 0 to show that we have global perms } else { + // We have a specific list of locationds - add any sublocations to list $allowedLocations = self::getSublocations($locations, $allowedLocations); } return $allowedLocations; @@ -70,17 +144,18 @@ class PermissionUtil * Extend an array of locations by adding all sublocations. * * @param array $tree tree of all locations (structured like Location::getTree()) - * @param array $locations the array of locationids to extend + * @param array $allowedLocations the array of locationids to extend * @return array extended array of locationids */ - public static function getSublocations($tree, $locations) { - $result = array_flip($locations); + public static function getSublocations($tree, $allowedLocations) + { + $result = $allowedLocations; foreach ($tree as $location) { if (array_key_exists("children", $location)) { - if (in_array($location["locationid"], $locations)) { + if (isset($allowedLocations[$location["locationid"]])) { $result += array_flip(Location::extractIds($location["children"])); } else { - $result += array_flip(self::getSublocations($location["children"], $locations)); + $result += array_flip(self::getSublocations($location["children"], $allowedLocations)); } } } @@ -88,6 +163,37 @@ class PermissionUtil } /** + * If in debug mode, validate that the checked permission is actually defined + * in the according permissions.json and complain if that's not the case. + * This is supposed to catch misspelled permission checks. + * + * @param string $permissionId permission to check + */ + private static function validatePermission($permissionId) + { + if (!CONFIG_DEBUG || $permissionId === '*') + return; + $split = explode('.', $permissionId, 2); + if (count($split) !== 2) { + trigger_error('[skip:3]Cannot check malformed permission "' . $permissionId . '"', E_USER_WARNING); + return; + } + if ($split[1] === '*') + return; + $data = json_decode(file_get_contents('modules/' . $split[0] . '/permissions/permissions.json'), true); + if (substr($split[1], -2) === '.*') { + $len = strlen($split[1]) - 1; + foreach ($data as $perm => $v) { + if (strncmp($split[1], $perm, $len) === 0) + return; + } + trigger_error('[skip:3]Permission "' . $permissionId . '" does not match anything defined for module', E_USER_WARNING); + } elseif (!is_array($data) || !array_key_exists($split[1], $data)) { + trigger_error('[skip:3]Permission "' . $permissionId . '" not defined for module', E_USER_WARNING); + } + } + + /** * Get all permissions of all active modules that have permissions in their permissions/permissions.json file. * * @return array permission tree as a multidimensional array @@ -100,30 +206,62 @@ class PermissionUtil if (!is_array($data)) continue; preg_match('#^modules/([^/]+)/#', $file, $out); - foreach( $data as $p ) { - $description = Dictionary::translateFileModule($out[1], "permissions", $p); - self::putInPermissionTree($out[1].".".$p, $description, $permissions); + $moduleId = $out[1]; + if (Module::get($moduleId) === false) + continue; + foreach ($data as $perm => $permissionFlags) { + $description = Dictionary::translateFileModule($moduleId, "permissions", $perm); + self::putInPermissionTree($moduleId . "." . $perm, $permissionFlags['location-aware'], $description, $permissions); } } ksort($permissions); global $MENU_CAT_OVERRIDE; $sortingOrder = $MENU_CAT_OVERRIDE; - foreach ($permissions as $module => $v) $sortingOrder[Module::get($module)->getCategory()][] = $module; + foreach ($permissions as $module => $v) { + $sortingOrder[Module::get($module)->getCategory()][] = $module; + } $permissions = array_replace(array_flip(call_user_func_array('array_merge', $sortingOrder)), $permissions); - foreach ($permissions as $module => $v) if (is_int($v)) unset($permissions[$module]); + foreach ($permissions as $module => $v) { + if (is_int($v)) { + unset($permissions[$module]); + } + } return $permissions; } /** + * Get all existing roles. + * + * @param int|false $userid Which user to consider, false = none + * @param bool $onlyMatching true = filter roles the user doesn't have + * @return array list of roles + */ + public static function getRoles($userid = false, $onlyMatching = true) + { + if ($userid === false) { + return Database::queryAll('SELECT roleid, rolename FROM role ORDER BY rolename ASC'); + } + $ret = Database::queryAll('SELECT r.roleid, r.rolename, u.userid AS hasRole FROM role r + LEFT JOIN role_x_user u ON (r.roleid = u.roleid AND u.userid = :userid) + GROUP BY r.roleid + ORDER BY rolename ASC', ['userid' => $userid]); + foreach ($ret as &$role) { + settype($role['hasRole'], 'bool'); + } + return $ret; + } + + /** * Place a permission into the given permission tree. * * @param string $permission the permission to place in the tree + * @param bool $locationAware whether this permissions can be restricted to specific locations only * @param string $description the description of the permission * @param array $tree the permission tree to modify */ - private static function putInPermissionTree($permission, $description, &$tree) + private static function putInPermissionTree($permission, $locationAware, $description, &$tree) { $subPermissions = explode('.', $permission); foreach ($subPermissions as $subPermission) { @@ -134,6 +272,7 @@ class PermissionUtil $tree =& $tree[$subPermission]; } } - $tree = $description; + $tree = array('description' => $description, 'location-aware' => $locationAware, 'isLeaf' => true); } + }
\ No newline at end of file diff --git a/modules-available/permissionmanager/install.inc.php b/modules-available/permissionmanager/install.inc.php index 71ee7a1e..7f9c80ef 100644 --- a/modules-available/permissionmanager/install.inc.php +++ b/modules-available/permissionmanager/install.inc.php @@ -5,20 +5,27 @@ $res = array(); $res[] = tableCreate('role', " roleid int(10) unsigned NOT NULL AUTO_INCREMENT, rolename varchar(200) NOT NULL, + roledescription TEXT, PRIMARY KEY (roleid) "); -$res[] = tableCreate('user_x_role', " +if (tableExists('user_x_role')) { + if (tableExists('role_x_user')) { + Database::exec('DROP TABLE user_x_role'); + } else { + $res[] = tableRename('user_x_role', 'role_x_user'); + } +} +$res[] = tableCreate('role_x_user', " userid int(10) unsigned NOT NULL, roleid int(10) unsigned NOT NULL, PRIMARY KEY (userid, roleid) "); $res[] = tableCreate('role_x_location', " - id int(10) unsigned NOT NULL AUTO_INCREMENT, roleid int(10) unsigned NOT NULL, locationid int(11), - PRIMARY KEY (id) + CONSTRAINT role_loc UNIQUE (roleid, locationid) "); $res[] = tableCreate('role_x_permission', " @@ -27,24 +34,38 @@ $res[] = tableCreate('role_x_permission', " PRIMARY KEY (roleid, permissionid) "); +if (tableHasColumn('role_x_location', 'id')) { + $cnt = Database::exec('DELETE a FROM role_x_location a, role_x_location b + WHERE a.roleid = b.roleid AND (a.locationid = b.locationid OR (a.locationid IS NULL AND b.locationid IS NULL)) + AND a.id > b.id'); + $ret = Database::exec('ALTER TABLE role_x_location DROP COLUMN id, + ADD CONSTRAINT role_loc UNIQUE (roleid, locationid)'); + if ($ret === false) { + $res[] = UPDATE_NOOP; + } else { + $res[] = UPDATE_DONE; + } + +} + if (!tableExists('user') || !tableExists('location')) { finalResponse(UPDATE_RETRY, 'Cannot add constraint yet. Please retry.'); } else { - $c = tableGetContraints('user_x_role', 'userid', 'user', 'userid'); + $c = tableGetContraints('role_x_user', 'userid', 'user', 'userid'); if ($c === false) finalResponse(UPDATE_FAILED, 'Cannot get constraints of user table: ' . Database::lastError()); if (empty($c)) { - $alter = Database::exec('ALTER TABLE user_x_role ADD FOREIGN KEY (userid) REFERENCES user (userid) ON DELETE CASCADE ON UPDATE CASCADE'); + $alter = Database::exec('ALTER TABLE role_x_user ADD FOREIGN KEY (userid) REFERENCES user (userid) ON DELETE CASCADE ON UPDATE CASCADE'); if ($alter === false) finalResponse(UPDATE_FAILED, 'Cannot add userid constraint referencing user table: ' . Database::lastError()); $res[] = UPDATE_DONE; } - $c = tableGetContraints('user_x_role', 'roleid', 'role', 'roleid'); + $c = tableGetContraints('role_x_user', 'roleid', 'role', 'roleid'); if ($c === false) finalResponse(UPDATE_FAILED, 'Cannot get constraints of role table: ' . Database::lastError()); if (empty($c)) { - $alter = Database::exec('ALTER TABLE user_x_role ADD FOREIGN KEY (roleid) REFERENCES role (roleid) ON DELETE CASCADE ON UPDATE CASCADE'); + $alter = Database::exec('ALTER TABLE role_x_user ADD FOREIGN KEY (roleid) REFERENCES role (roleid) ON DELETE CASCADE ON UPDATE CASCADE'); if ($alter === false) finalResponse(UPDATE_FAILED, 'Cannot add roleid constraint referencing role table: ' . Database::lastError()); $res[] = UPDATE_DONE; @@ -80,6 +101,108 @@ if (!tableExists('user') || !tableExists('location')) { $res[] = UPDATE_DONE; } } + +// 2018-04-13 role description field; add a couple default roles +if (!tableHasColumn('role', 'roledescription')) { + $alter = Database::exec("ALTER TABLE role ADD roledescription TEXT"); + if ($alter === false) + finalResponse(UPDATE_FAILED, 'Cannot add roledescription field to table role: ' . Database::lastError()); + $res[] = UPDATE_DONE; +} + +if (!tableHasColumn('role', 'roledescription')) { + finalResponse(UPDATE_RETRY, 'Try again later'); +} + +if (Database::exec("INSERT INTO `role` VALUES + (1,'Super-Admin', 'Hat keinerlei Zugriffsbeschränkungen'), + (2,'Admin', 'Alles bis auf Rechte-/Nutzerverwaltung'), + (3,'Prüfungsadmin', 'Kann E-Prüfungen verwalten, Prüfungsmodus einschalten, etc.'), + (4,'Lesezugriff', 'Kann auf die meisten Seiten zugreifen, jedoch keine Änderungen vornehmen')") !== false) { + // Success, there probably were no roles before, keep going + // Assign roles to location (all) + Database::exec("INSERT INTO `role_x_location` VALUES (1,NULL),(2,NULL),(3,NULL),(4,NULL)"); + // Assign permissions to roles + Database::exec("INSERT INTO `role_x_permission` VALUES + (3,'exams.exams.*'), + (3,'rebootcontrol.action.*'), + (3,'statistics.hardware.projectors.view'), + (3,'statistics.machine.note.*'), + (3,'statistics.machine.view-details'), + (3,'statistics.view.*'), + (3,'syslog.view'), + + (1,'*'), + + (4,'adduser.user.view-list'), + (4,'backup.create'), + (4,'baseconfig.view'), + (4,'dnbd3.access-page'), + (4,'dnbd3.refresh'), + (4,'dnbd3.view.details'), + (4,'dozmod.actionlog.view'), + (4,'dozmod.users.view'), + (4,'eventlog.view'), + (4,'exams.exams.view'), + (4,'locationinfo.backend.check'), + (4,'locationinfo.panel.list'), + (4,'locations.location.view'), + (4,'minilinux.view'), + (4,'news.*'), + (4,'permissionmanager.locations.view'), + (4,'permissionmanager.roles.view'), + (4,'permissionmanager.users.view'), + (4,'runmode.list-all'), + (4,'serversetup.access-page'), + (4,'serversetup.download'), + (4,'statistics.hardware.projectors.view'), + (4,'statistics.machine.note.view'), + (4,'statistics.machine.view-details'), + (4,'statistics.view.*'), + (4,'statistics_reporting.reporting.download'), + (4,'statistics_reporting.table.export'), + (4,'statistics_reporting.table.view.*'), + (4,'sysconfig.config.view-list'), + (4,'sysconfig.module.download'), + (4,'sysconfig.module.view-list'), + (4,'syslog.view'), + (4,'systemstatus.show.overview.*'), + (4,'systemstatus.tab.*'), + (4,'webinterface.access-page'), + + (2,'adduser.user.view-list'), + (2,'backup.*'), + (2,'baseconfig.*'), + (2,'dnbd3.*'), + (2,'dozmod.*'), + (2,'eventlog.view'), + (2,'exams.exams.*'), + (2,'locationinfo.*'), + (2,'locations.*'), + (2,'minilinux.*'), + (2,'news.*'), + (2,'permissionmanager.locations.view'), + (2,'permissionmanager.roles.view'), + (2,'permissionmanager.users.view'), + (2,'rebootcontrol.*'), + (2,'roomplanner.edit'), + (2,'runmode.list-all'), + (2,'serversetup.*'), + (2,'statistics.*'), + (2,'statistics_reporting.*'), + (2,'sysconfig.*'), + (2,'syslog.*'), + (2,'systemstatus.*'), + (2,'vmstore.edit'), + (2,'webinterface.*')"); + // Asign the first user to the superadmin role (if one exists) + Database::exec("INSERT INTO `role_x_user` VALUES (1,1)"); + $res[] = UPDATE_DONE; +} + +// +// + if (in_array(UPDATE_DONE, $res)) { finalResponse(UPDATE_DONE, 'Tables created successfully'); } diff --git a/modules-available/permissionmanager/lang/de/permissions.json b/modules-available/permissionmanager/lang/de/permissions.json new file mode 100644 index 00000000..444c1e8c --- /dev/null +++ b/modules-available/permissionmanager/lang/de/permissions.json @@ -0,0 +1,7 @@ +{ + "locations.view": "Orte mit zugewiesenen Rollen sehen.", + "roles.edit": "Rollen bearbeiten.", + "roles.view": "Rollen sehen.", + "users.edit-roles": "Benutzern Rollen zuweisen oder entziehen.", + "users.view": "Benutzer mit zugewiesenen Rolen sehen." +}
\ No newline at end of file diff --git a/modules-available/permissionmanager/lang/de/template-tags.json b/modules-available/permissionmanager/lang/de/template-tags.json index 71bd4075..504ef6d2 100644 --- a/modules-available/permissionmanager/lang/de/template-tags.json +++ b/modules-available/permissionmanager/lang/de/template-tags.json @@ -1,24 +1,24 @@ { - "lang_roles": "Rollen", - "lang_users": "Nutzer", - "lang_locations": "Räume", "lang_addRole": "Rollen erteilen", - "lang_removeRole": "Rollen entziehen", - "lang_newRole": "Rolle anlegen", - "lang_selected": "Ausgewählt", - "lang_edit": "Bearbeiten", - "lang_delete": "Löschen", - "lang_removeCheck": "Sind Sie sich sicher, dass Sie diese Rolle entfernen wollen?", - "lang_deleteCheck": "Sind Sie sich sicher, dass Sie diese Rolle löschen wollen?", - "lang_emptyNameWarning": "Der Name der Rolle darf nicht leer sein!", + "lang_addRoleHeading": "Neue Rolle hinzuf\u00fcgen", + "lang_description": "Beschreibung", + "lang_editRoleHeading": "Rolle bearbeiten", + "lang_locationAwareDesc": "Berechtigungen mit diesem Symbol k\u00f6nnen auf bestimmte R\u00e4ume\/Orte beschr\u00e4nkt werden. Alle anderen Berechtigungen sind unabh\u00e4ngig von den f\u00fcr diese Rolle ausgew\u00e4hlten Orten.", + "lang_locations": "R\u00e4ume", + "lang_moduleName": "Rechtemanager", "lang_name": "Name", - "lang_cancel": "Abbrechen", - "lang_save": "Speichern", - "lang_all": "alle", - "lang_selected": "ausgewählte", + "lang_newRole": "Rolle anlegen", + "lang_numAssignedUsers": "Benutzer mit dieser Rolle", + "lang_permission": "Berechtigung", + "lang_permissionDeniedBody": "Ihnen fehlt eine oder mehrere Berechtigungen, um auf diese Seite oder Funktion zuzugreifen.", + "lang_permissionDeniedHeader": "Zugriff verweigert", "lang_permissions": "Rechte", - "lang_selectizePlaceholder": "Nach Rollen filtern...", + "lang_removeRole": "Rollen entziehen", + "lang_roleDeleteConfirm": "Sind Sie sich sicher, dass Sie diese Rolle l\u00f6schen m\u00f6chten? Benutzer, denen diese Rolle zugewiesen ist, werden die entsprechenden Berechtigungen verlieren.", + "lang_roles": "Rollen", "lang_searchPlaceholder": "Nach Rollen suchen...", - "lang_moduleName": "Rechtemanager", - "lang_roleEditor": "Rollen Editor" + "lang_selected": "ausgew\u00e4hlte", + "lang_selectizePlaceholder": "Nach Rollen filtern...", + "lang_users": "Nutzer", + "lang_view": "Anzeigen" }
\ No newline at end of file diff --git a/modules-available/permissionmanager/lang/en/permissions.json b/modules-available/permissionmanager/lang/en/permissions.json new file mode 100644 index 00000000..9f7263db --- /dev/null +++ b/modules-available/permissionmanager/lang/en/permissions.json @@ -0,0 +1,7 @@ +{ + "locations.view": "See locations with assigned roles.", + "roles.edit": "Edit roles.", + "roles.view": "Show roles.", + "users.edit-roles": "Assign or remove roles from users.", + "users.view": "See users with assigned roles." +}
\ No newline at end of file diff --git a/modules-available/permissionmanager/lang/en/template-tags.json b/modules-available/permissionmanager/lang/en/template-tags.json index 2d31b294..6f1fa614 100644 --- a/modules-available/permissionmanager/lang/en/template-tags.json +++ b/modules-available/permissionmanager/lang/en/template-tags.json @@ -1,24 +1,24 @@ { - "lang_roles": "Roles", - "lang_users": "Users", - "lang_locations": "Locations", "lang_addRole": "Grant Roles", - "lang_removeRole": "Revoke Roles", - "lang_newRole": "New Role", - "lang_selected": "Selected", - "lang_edit": "Edit", - "lang_delete": "Delete", - "lang_removeCheck": "Are you sure you want to remove this role?", - "lang_deleteCheck": "Are you sure you want to delete this role?", - "lang_emptyNameWarning": "Role name can not be empty!", + "lang_addRoleHeading": "Add new role", + "lang_description": "Description", + "lang_editRoleHeading": "Edit role", + "lang_locationAwareDesc": "Permissions with this symbol can be restricted to certain locations. All other permissions are independent of the locations selected for this role.", + "lang_locations": "Locations", + "lang_moduleName": "Permission Manager", "lang_name": "Name", - "lang_cancel": "Cancel", - "lang_save": "Save", - "lang_all": "all", - "lang_selected": "selected", + "lang_newRole": "New Role", + "lang_numAssignedUsers": "Users with this role", + "lang_permission": "Permission", + "lang_permissionDeniedBody": "You are missing one or more permissions to access this page or functionality.", + "lang_permissionDeniedHeader": "Access denied", "lang_permissions": "Permissions", - "lang_selectizePlaceholder": "Filter for roles...", + "lang_removeRole": "Revoke Roles", + "lang_roleDeleteConfirm": "Are you sure you want to delete this role? Users currently assigned to this role will lose the according permissions.", + "lang_roles": "Roles", "lang_searchPlaceholder": "Search for roles...", - "lang_moduleName": "Permission Manager", - "lang_roleEditor": "Role Editor" + "lang_selected": "selected", + "lang_selectizePlaceholder": "Filter for roles...", + "lang_users": "Users", + "lang_view": "View" }
\ No newline at end of file diff --git a/modules-available/permissionmanager/page.inc.php b/modules-available/permissionmanager/page.inc.php index 13d81c6a..462d3163 100644 --- a/modules-available/permissionmanager/page.inc.php +++ b/modules-available/permissionmanager/page.inc.php @@ -17,22 +17,38 @@ class Page_PermissionManager extends Page $action = Request::any('action', 'show', 'string'); if ($action === 'addRoleToUser') { + User::assertPermission('users.edit-roles'); $users = Request::post('users', ''); $roles = Request::post('roles', ''); PermissionDbUpdate::addRoleToUser($users, $roles); } elseif ($action === 'removeRoleFromUser') { + User::assertPermission('users.edit-roles'); $users = Request::post('users', ''); $roles = Request::post('roles', ''); PermissionDbUpdate::removeRoleFromUser($users, $roles); } elseif ($action === 'deleteRole') { - $id = Request::post('deleteId', false, 'string'); + User::assertPermission('roles.edit'); + $id = Request::post('deleteId', false, 'int'); PermissionDbUpdate::deleteRole($id); } elseif ($action === 'saveRole') { - $roleID = Request::post("roleid", false); - $rolename = Request::post("rolename"); - $locations = self::processLocations(Request::post("locations")); + User::assertPermission('roles.edit'); + $roleID = Request::post("roleid", false, 'int'); + if ($roleID === false) { + Message::addError('main.parameter-missing', 'roleid'); + Util::redirect('?do=permissionmanager'); + } + $roleName = Request::post("rolename", '', 'string'); + if (empty($roleName)) { + Message::addError('main.parameter-empty', 'rolename'); + Util::redirect('?do=permissionmanager'); + } + $roleDescription = Request::post('roledescription', '', 'string'); + $locations = self::processLocations(Request::post("locations", [], 'array')); $permissions = self::processPermissions(Request::post("permissions")); - PermissionDbUpdate::saveRole($rolename, $locations, $permissions, $roleID); + PermissionDbUpdate::saveRole($roleName, $roleDescription, $locations, $permissions, $roleID); + } + if (Request::isPost()) { + Util::redirect('?do=permissionmanager&show=' . Request::get("show", "roles")); } } @@ -41,47 +57,76 @@ class Page_PermissionManager extends Page */ protected function doRender() { - $show = Request::get("show", "roles"); + $show = Request::get("show", false, 'string'); + + // "Public" page -- nice "permission denied" message + if ($show === 'denied') { + Render::addTemplate('page-permission-denied', [ + 'name' => User::getName(), + 'permission' => Request::get('permission', false, 'string'), + ]); + return; + } + + if ($show === false) { + foreach (['roles', 'users', 'locations'] as $show) { + if (User::hasPermission($show . '.*')) + break; + } + } // switch between tables, but always show menu to switch tables - if ( $show === 'roles' || $show === 'users' || $show === 'locations' ) { - // get menu button colors - $buttonColors = array(); - $buttonColors['rolesButtonClass'] = $show === 'roles' ? 'active' : ''; - $buttonColors['usersButtonClass'] = $show === 'users' ? 'active' : ''; - $buttonColors['locationsButtonClass'] = $show === 'locations' ? 'active' : ''; - - Render::addtemplate('_page', $buttonColors); - - if ($show === "roles") { - $data = array("roles" => GetPermissionData::getRoles()); - Render::addTemplate('rolestable', $data); - } elseif ($show === "users") { - $data = array("user" => GetPermissionData::getUserData(), "roles" => GetPermissionData::getRoles()); - Render::addTemplate('userstable', $data); - } elseif ($show === "locations") { - $data = array("location" => GetPermissionData::getLocationData(), "allroles" => GetPermissionData::getRoles()); - Render::addTemplate('locationstable', $data); + // get menu button colors + $data = array(); + if ($show === "roleEditor") { + $data['groupClass'] = 'btn-group-muted'; + $data['rolesButtonClass'] = 'active'; + } else { + $data[$show . 'ButtonClass'] = 'active'; + } + Permission::addGlobalTags($data['perms'], null, ['roles.*', 'users.*', 'locations.*']); + + Render::addtemplate('header-menu', $data); + + if ($show === "roles") { + User::assertPermission('roles.*'); + $data = array("roles" => GetPermissionData::getRoles(GetPermissionData::WITH_USER_COUNT)); + Permission::addGlobalTags($data['perms'], null, ['roles.edit']); + Render::addTemplate('rolestable', $data); + } elseif ($show === "users") { + User::assertPermission('users.*'); + $data = array("user" => GetPermissionData::getUserData()); + if (User::hasPermission('users.edit-roles')) { + $data['allroles'] = GetPermissionData::getRoles(); } + Permission::addGlobalTags($data['perms'], null, ['users.edit-roles']); + Render::addTemplate('role-filter-selectize', $data); + Render::addTemplate('userstable', $data); + } elseif ($show === "locations") { + User::assertPermission('locations.*'); + $data = array("location" => GetPermissionData::getLocationData(), "allroles" => GetPermissionData::getRoles()); + Render::addTemplate('role-filter-selectize', $data); + Render::addTemplate('locationstable', $data); } elseif ($show === "roleEditor") { - $data = array("cancelShow" => Request::get("cancel", "roles")); + User::assertPermission('roles.*'); + $data = array("cancelShow" => Request::get("cancel", "roles", 'string')); + Permission::addGlobalTags($data['perms'], null, ['roles.edit']); $selectedPermissions = array(); $selectedLocations = array(); - $roleid = Request::get("roleid", false); - if ($roleid) { - $roleData = GetPermissionData::getRoleData($roleid); - $data["roleid"] = $roleid; - $data["rolename"] = $roleData["rolename"]; - $selectedPermissions = $roleData["permissions"]; - $selectedLocations = $roleData["locations"]; + $roleid = Request::get("roleid", false, 'int'); + if ($roleid !== false) { + $data += GetPermissionData::getRoleData($roleid); + $selectedPermissions = $data["permissions"]; + $selectedLocations = $data["locations"]; } - $data["permissionHTML"] = self::generatePermissionHTML(PermissionUtil::getPermissions(), $selectedPermissions); - $data["locationHTML"] = self::generateLocationHTML(Location::getTree(), $selectedLocations); + $data["permissionHTML"] = self::generatePermissionHTML(PermissionUtil::getPermissions(), $selectedPermissions, + false, '', ['perms' => $data['perms']]); + $data["locationHTML"] = self::generateLocationHTML(Location::getTree(), $selectedLocations, + $roleid === false, true, ['perms' => $data['perms']]); Render::addTemplate('roleeditor', $data); - } } @@ -90,36 +135,57 @@ class Page_PermissionManager extends Page * * @param array $permissions the permission tree * @param array $selectedPermissions permissions that should be preselected - * @param array $selectAll true if all pemrissions should be preselected, false if only those in $selectedPermissions - * @param array $permString the prefix permission string with which all permissions in the permission tree should start + * @param bool $selectAll true if all permissions should be preselected, false if only those in $selectedPermissions + * @param string $permString the prefix permission string with which all permissions in the permission tree should start * @return string generated html code */ - private static function generatePermissionHTML($permissions, $selectedPermissions = array(), $selectAll = false, $permString = "") + private static function generatePermissionHTML($permissions, $selectedPermissions = array(), $selectAll = false, $permString = "", $tags = []) { $res = ""; $toplevel = $permString == ""; - if ($toplevel && in_array("*", $selectedPermissions)) $selectAll = true; + if ($toplevel && in_array("*", $selectedPermissions)) { + $selectAll = true; + } foreach ($permissions as $k => $v) { - $leaf = !is_array($v); - $nextPermString = $permString ? $permString.".".$k : $k; - $id = $leaf ? $nextPermString : $nextPermString.".*"; - $selected = $selectAll || in_array($id, $selectedPermissions); - $res .= Render::parse("treenode", - array("id" => $id, - "name" => $toplevel ? Module::get($k)->getDisplayName() : $k, - "toplevel" => $toplevel, - "checkboxname" => "permissions", - "selected" => $selected, - "HTML" => $leaf ? "" : self::generatePermissionHTML($v, $selectedPermissions, $selected, $nextPermString), - "description" => $leaf ? $v : "")); + $selected = $selectAll; + $nextPermString = $permString ? $permString . "." . $k : $k; + if ($toplevel) { + $displayName = Module::get($k)->getDisplayName(); + } else { + $displayName = $k; + } + do { + $leaf = isset($v['isLeaf']) && $v['isLeaf']; + $id = $leaf ? $nextPermString : $nextPermString . ".*"; + $selected = $selected || in_array($id, $selectedPermissions); + if ($leaf || count($v) !== 1) + break; + reset($v); + $k = key($v); + $v = $v[$k]; + $nextPermString .= '.' . $k; + $displayName .= '.' . $k; + } while (true); + $data = array( + "id" => $id, + "name" => $displayName, + "toplevel" => $toplevel, + "checkboxname" => "permissions", + "selected" => $selected, + "HTML" => $leaf ? "" : self::generatePermissionHTML($v, $selectedPermissions, $selected, $nextPermString, $tags), + ); + if ($leaf) { + $data += $v; + } + $res .= Render::parse("treenode", $data + $tags); } if ($toplevel) { $res = Render::parse("treepanel", array("id" => "*", - "name" => Dictionary::translateFile("template-tags", "lang_permissions"), - "checkboxname" => "permissions", - "selected" => $selectAll, - "HTML" => $res)); + "name" => Dictionary::translateFile("template-tags", "lang_permissions"), + "checkboxname" => "permissions", + "selected" => $selectAll, + "HTML" => $res) + $tags); } return $res; } @@ -133,28 +199,31 @@ class Page_PermissionManager extends Page * @param array $toplevel true if the location tree are the children of the root location, false if not * @return string generated html code */ - private static function generateLocationHTML($locations, $selectedLocations = array(), $selectAll = false, $toplevel = true) + private static function generateLocationHTML($locations, $selectedLocations = array(), $selectAll = false, $toplevel = true, $tags = []) { $res = ""; - if ($toplevel && in_array(0, $selectedLocations)) $selectAll = true; + if ($toplevel && in_array(0, $selectedLocations)) { + $selectAll = true; + } foreach ($locations as $location) { $selected = $selectAll || in_array($location["locationid"], $selectedLocations); $res .= Render::parse("treenode", - array("id" => $location["locationid"], - "name" => $location["locationname"], - "toplevel" => $toplevel, - "checkboxname" => "locations", - "selected" => $selected, - "HTML" => array_key_exists("children", $location) ? - self::generateLocationHTML($location["children"], $selectedLocations, $selected, false) : "")); + array("id" => $location["locationid"], + "name" => $location["locationname"], + "toplevel" => $toplevel, + "checkboxname" => "locations", + "selected" => $selected, + "HTML" => array_key_exists("children", $location) ? + self::generateLocationHTML($location["children"], $selectedLocations, $selected, false, $tags) : "") + + $tags); } if ($toplevel) { $res = Render::parse("treepanel", array("id" => 0, - "name" => Dictionary::translateFile("template-tags", "lang_locations"), - "checkboxname" => "locations", - "selected" => $selectAll, - "HTML" => $res)); + "name" => Dictionary::translateFile("template-tags", "lang_locations"), + "checkboxname" => "locations", + "selected" => $selectAll, + "HTML" => $res) + $tags); } return $res; } @@ -167,12 +236,14 @@ class Page_PermissionManager extends Page */ private static function processLocations($locations) { - if (in_array(0, $locations)) return array(NULL); + if (in_array(0, $locations)) + return array(null); $result = array(); foreach ($locations as $location) { $rootchain = array_reverse(Location::getLocationRootChain($location)); foreach ($rootchain as $l) { - if (in_array($l, $result)) break; + if (in_array($l, $result)) + break; if (in_array($l, $locations)) { $result[] = $l; break; @@ -190,7 +261,8 @@ class Page_PermissionManager extends Page */ private static function processPermissions($permissions) { - if (in_array("*", $permissions)) return array("*"); + if (in_array("*", $permissions)) + return array("*"); $result = array(); foreach ($permissions as $permission) { $x =& $result; @@ -213,10 +285,10 @@ class Page_PermissionManager extends Page foreach ($permissions as $permission => $a) { if (is_array($a)) { if (array_key_exists("*", $a)) { - $result[] = $permission.".*"; + $result[] = $permission . ".*"; } else { foreach (self::extractPermissions($a) as $subPermission) { - $result[] = $permission.".".$subPermission; + $result[] = $permission . "." . $subPermission; } } } else { diff --git a/modules-available/permissionmanager/permissions/permissions.json b/modules-available/permissionmanager/permissions/permissions.json new file mode 100644 index 00000000..3981a2c3 --- /dev/null +++ b/modules-available/permissionmanager/permissions/permissions.json @@ -0,0 +1,17 @@ +{ + "roles.view": { + "location-aware": false + }, + "roles.edit": { + "location-aware": false + }, + "users.view": { + "location-aware": false + }, + "users.edit-roles": { + "location-aware": false + }, + "locations.view": { + "location-aware": false + } +}
\ No newline at end of file diff --git a/modules-available/permissionmanager/style.css b/modules-available/permissionmanager/style.css index 49d631a8..dca38eeb 100644 --- a/modules-available/permissionmanager/style.css +++ b/modules-available/permissionmanager/style.css @@ -1,82 +1,46 @@ -#switchForm { - text-align: center; - margin-bottom: 50px; -} - -#saveButton { - margin-left: 10px; -} - -#rolename { - width: 200px; - display: inline-block; - margin-left: 10px; -} - -.missingInput { - border-color: rgba(255, 0, 0, 0.8); - box-shadow: 0 1px 1px rgba(255, 0, 0, 0.075) inset, 0 0 8px rgba(255, 0, 0, 0.6); -} - .table { margin-top: 20px; } -.table > tbody > tr > td { - vertical-align: middle; - height: 50px; -} - .scrollingTable { height: 500px; overflow: auto; } -.customSpanMargin { +/* vcenter .label in table cell */ +td > .label { display: inline-block; - margin-top: 2px; - margin-bottom: 2px; + margin: 2px 0; } -.panel-primary > .panel-heading { - background-image: none; +/* lists in tree view: hide bullet points, first entry bold, ... */ +.tree-container ul { + list-style-type: none; } -.panel{ - margin-bottom: 20px; +.tree-container > ul { + display: inline-block; + width: 100%; + padding: 0; } -.selectize-input { - overflow: visible; -} - - -.tree-container .selected { - background-color: rgba(0, 182, 41, 0.23); +.tree-container > ul > li > div > label { + font-weight: bold; } +/* number of columns in tree view depending on screen size */ .tree-container { -moz-column-gap: 20px; -webkit-column-gap: 20px; column-gap: 20px; + -moz-column-count: 1; + -webkit-column-count: 1; + column-count: 1; + padding-left: 20px; + padding-right: 20px; } - -.tree-container > ul { - display: inline-block; - width: 100%; - padding: 0; -} - -@media (max-width: 767px) { - .tree-container { - -moz-column-count: 1; - -webkit-column-count: 1; - column-count: 1; - } -} - -@media (min-width: 768px) and (max-width: 991px) { +@media (min-width: 768px) { .tree-container { -moz-column-count: 2; -webkit-column-count: 2; @@ -92,6 +56,11 @@ } } -ul { - list-style-type: none; -}
\ No newline at end of file +.btn-group-muted > button { + color: #aaa; +} + +h1 span.glyphicon { + top: 9px; +} + diff --git a/modules-available/permissionmanager/templates/_page.html b/modules-available/permissionmanager/templates/_page.html deleted file mode 100644 index 4140ce78..00000000 --- a/modules-available/permissionmanager/templates/_page.html +++ /dev/null @@ -1,29 +0,0 @@ -<div class="row"> - <div class="col-md-12" style="margin-bottom: 0;"> - <div class='page-header'> - <div class='pull-right'> - <form id="switchForm" method="GET" action="?do=permissionmanager"> - <input type="hidden" name="do" value="permissionmanager"> - - <div class="btn-group"> - <button class="btn btn-default {{rolesButtonClass}}" type="submit" name="show" value="roles"> - <span class="glyphicon glyphicon-education"></span> - {{lang_roles}} - </button> - - <button class="btn btn-default {{usersButtonClass}}" type="submit" name="show" value="users"> - <span class="glyphicon glyphicon-user"></span> - {{lang_users}} - </button> - - <button class="btn btn-default {{locationsButtonClass}}" type="submit" name="show" value="locations"> - <span class="glyphicon glyphicon-home"></span> - {{lang_locations}} - </button> - </div> - </form> - </div> - <h1>{{lang_moduleName}}</h1> - </div> - </div> -</div>
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/header-menu.html b/modules-available/permissionmanager/templates/header-menu.html new file mode 100644 index 00000000..91bfa3af --- /dev/null +++ b/modules-available/permissionmanager/templates/header-menu.html @@ -0,0 +1,25 @@ +<div class='page-header'> + <div class='pull-right'> + <form method="GET"> + <input type="hidden" name="do" value="permissionmanager"> + + <div class="btn-group {{groupClass}}"> + <button class="btn btn-default {{rolesButtonClass}}" type="submit" name="show" value="roles" {{perms.roles.disabled}}> + <span class="glyphicon glyphicon-education"></span> + {{lang_roles}} + </button> + + <button class="btn btn-default {{usersButtonClass}}" type="submit" name="show" value="users" {{perms.users.disabled}}> + <span class="glyphicon glyphicon-user"></span> + {{lang_users}} + </button> + + <button class="btn btn-default {{locationsButtonClass}}" type="submit" name="show" value="locations" {{perms.locations.disabled}}> + <span class="glyphicon glyphicon-home"></span> + {{lang_locations}} + </button> + </div> + </form> + </div> + <h1>{{lang_moduleName}}</h1> +</div>
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/locationstable.html b/modules-available/permissionmanager/templates/locationstable.html index 153258fe..35058387 100644 --- a/modules-available/permissionmanager/templates/locationstable.html +++ b/modules-available/permissionmanager/templates/locationstable.html @@ -1,37 +1,21 @@ -<div class="row"> - <div class="col-md-4"></div> - <div class="col-md-4"> - <select multiple name="roles[]" id="select-role"> - <option value>{{lang_selectizePlaceholder}}</option> - {{#allroles}} - <option value="{{roleid}}">{{rolename}}</option> - {{/allroles}} - </select> - </div> -</div> +<table id="locationsTable" class="table table-condensed table-hover dataTable"> + <thead> + <tr> + <th>{{lang_locations}}</th> + <th class="slx-smallcol">{{lang_roles}}</th> + </tr> + </thead> -<div class="row"> - <div class="col-md-12"> - <table id="locationsTable" class="table table-condensed table-hover stupidtable dataTable"> - <thead> - <tr> - <th data-sort="string">{{lang_locations}}</th> - <th>{{lang_roles}}</th> - </tr> - </thead> - - <tbody> - {{#location}} - <tr data-selectizeCount='0'> - <td>{{locationpad}} {{locationname}}</td> - <td> - {{#roles}} - <a href="?do=permissionmanager&show=roleEditor&cancel=locations&roleid={{roleid}}" class="label label-default customSpanMargin roleid-{{roleid}}">{{rolename}}</a> - {{/roles}} - </td> - </tr> - {{/location}} - </tbody> - </table> - </div> -</div>
\ No newline at end of file + <tbody> + {{#location}} + <tr class="{{#roles}}roleid-{{roleid}} {{/roles}}"> + <td>{{locationpad}} {{locationname}}</td> + <td class="slx-smallcol"> + {{#roles}} + <a href="?do=permissionmanager&show=roleEditor&cancel=locations&roleid={{roleid}}" class="label label-default customSpanMargin">{{rolename}}</a> + {{/roles}} + </td> + </tr> + {{/location}} + </tbody> +</table>
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/page-permission-denied.html b/modules-available/permissionmanager/templates/page-permission-denied.html new file mode 100644 index 00000000..cc357a0b --- /dev/null +++ b/modules-available/permissionmanager/templates/page-permission-denied.html @@ -0,0 +1,21 @@ +<br><br> +<div class="jumbotron"> + <h1> + <span class="text-danger"> + <span class="glyphicon glyphicon-ban-circle"></span> + {{lang_permissionDeniedHeader}} + </span> + </h1> + <br><br> + <p> + {{lang_permissionDeniedBody}} + </p> + {{#permission}} + <div> + {{lang_permission}}: <b>{{permission}}</b> + </div> + {{/permission}} + <div> + {{lang_user}}: <b>{{name}}</b> + </div> +</div> diff --git a/modules-available/permissionmanager/templates/role-filter-selectize.html b/modules-available/permissionmanager/templates/role-filter-selectize.html new file mode 100644 index 00000000..ceadec75 --- /dev/null +++ b/modules-available/permissionmanager/templates/role-filter-selectize.html @@ -0,0 +1,6 @@ +<select multiple id="select-role"> + <option value>{{lang_selectizePlaceholder}}</option> + {{#allroles}} + <option value="{{roleid}}">{{rolename}}</option> + {{/allroles}} +</select>
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/roleeditor.html b/modules-available/permissionmanager/templates/roleeditor.html index 871fd0cc..c464c1fc 100644 --- a/modules-available/permissionmanager/templates/roleeditor.html +++ b/modules-available/permissionmanager/templates/roleeditor.html @@ -1,36 +1,55 @@ -<h1>{{lang_roleEditor}}</h1> +<h2> + {{#roleid}} + {{lang_editRoleHeading}} + {{/roleid}} + {{^roleid}} + {{lang_addRoleHeading}} + {{/roleid}} +</h2> + <form method="post" action="?do=permissionmanager"> <input type="hidden" name="action" value="saveRole"> <input type="hidden" name="token" value="{{token}}"> <input type="hidden" name="roleid" value="{{roleid}}"> - <div class="row"> - <div class="col-md-12" style="margin-bottom: 20px;"> - <ul class="nav nav-tabs text-center" role="tablist"> - <li role="presentation" class="active"><a href="#permissions" role="tab" data-toggle="tab">{{lang_permissions}}</a></li> - <li role="presentation"><a href="#locations" role="tab" data-toggle="tab">{{lang_locations}}</a></li> - <li style="float: none; display: inline-block"> - <label for="rolename">{{lang_name}}:</label> - <input id="rolename" name="rolename" value="{{rolename}}" type="text" class="form-control"> - </li> - <li style="float: right;"> - <span><a href="?do=permissionmanager&show={{cancelShow}}" id="cancelButton" class="btn btn-default">{{lang_cancel}}</a></span> - <button type="submit" id="saveButton" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button> - </li> - </ul> - </div> + <div class="input-group"> + <span class="input-group-addon slx-ga"> + <label for="rolename">{{lang_name}}</label> + </span> + <input id="rolename" name="rolename" value="{{rolename}}" type="text" class="form-control" required> </div> - <div class="row" style="margin-bottom: 20px;"> - <div class="col-md-12"> - <div class="tab-content"> - <div role="tabpanel" class="tab-pane active" id="permissions"> - {{{permissionHTML}}} - </div> - <div role="tabpanel" class="tab-pane" id="locations"> - {{{locationHTML}}} + <div class="input-group"> + <span class="input-group-addon slx-ga"> + <label for="roledescription">{{lang_description}}</label> + </span> + <input id="roledescription" name="roledescription" value="{{roledescription}}" type="text" class="form-control"> + </div> + <br> + + <div class="pull-right"> + <a href="?do=permissionmanager&show={{cancelShow}}" class="btn btn-default">{{lang_cancel}}</a> + <button type="submit" class="btn btn-primary" {{perms.roles.edit.disabled}}> + <span class="glyphicon glyphicon-floppy-disk"></span> + {{lang_save}} + </button> + </div> + <ul class="nav nav-tabs text-center" role="tablist"> + <li role="presentation" class="active"><a href="#permissions" role="tab" data-toggle="tab">{{lang_permissions}}</a></li> + <li role="presentation"><a href="#locations" role="tab" data-toggle="tab">{{lang_locations}}</a></li> + </ul> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="permissions"> + {{{permissionHTML}}} + <div class="panel panel-default"> + <div class="panel-body"> + <span class="glyphicon glyphicon-home text-muted"></span>  + {{lang_locationAwareDesc}} </div> </div> </div> + <div role="tabpanel" class="tab-pane" id="locations"> + {{{locationHTML}}} + </div> </div> </form> @@ -39,16 +58,14 @@ document.addEventListener("DOMContentLoaded", function () { - $(".tree-panel input[type=checkbox]").change(function () { - var checked = $(this).prop("checked"); - var parent = $(this).parent().parent(); - if (parent.hasClass("panel-heading")) parent = parent.parent(); + $(".tree-container input[type=checkbox]").change(function () { + // (Un)Mark all sub-elements when changing a checkbox in the panel body + var $this = $(this); + var checked = $this.prop("checked"); + $this.closest('li').find("input[type=checkbox]").prop("checked", checked); - var checkboxes = parent.find("input[type=checkbox]"); - if (checked) { - checkboxes.prop("checked", true); - } else { - checkboxes.prop("checked", false); + if (!checked) { + var parent = $(this).parent().parent(); while (!parent.hasClass("tree-panel")) { parent = parent.parent().parent(); if (parent.hasClass("tree-container")) parent = parent.parent().parent(); @@ -56,14 +73,11 @@ } } }); - - $('form').submit(function () { - var input = $("#rolename"); - var name = $.trim(input.val()); - if (!name) { - input.addClass("missingInput"); - return false; - } + $("input.master-checkbox").change(function () { + // (Un)Mark everything within the panel when the master checkbox on top is clicked + var $this = $(this); + var checked = $this.prop("checked"); + $this.closest('.tree-panel').find("input[type=checkbox]").prop("checked", checked); }); $('[data-toggle="tooltip"]').tooltip({ diff --git a/modules-available/permissionmanager/templates/rolestable.html b/modules-available/permissionmanager/templates/rolestable.html index b121a9e0..d520db33 100644 --- a/modules-available/permissionmanager/templates/rolestable.html +++ b/modules-available/permissionmanager/templates/rolestable.html @@ -1,15 +1,8 @@ <form method="post" action="?do=permissionmanager"> <input type="hidden" name="token" value="{{token}}"> - <div class="row"> - <div class="col-md-4"> - </div> - <div class="col-md-4"> - <input type="text" class="form-control" id="roleNameSearchField" onkeyup="searchFieldFunction()" placeholder="{{lang_searchPlaceholder}}"> - </div> - <div class="col-md-4 text-right"> - <a href="?do=permissionmanager&show=roleEditor" class="btn btn-success"><span class="glyphicon glyphicon-plus"></span> {{lang_newRole}}</a> - </div> + <div> + <input type="text" class="form-control" id="roleNameSearchField" onkeyup="searchFieldFunction()" placeholder="{{lang_searchPlaceholder}}"> </div> <div class="row"> @@ -18,8 +11,16 @@ <thead> <tr> <th data-sort="string">{{lang_roles}}</th> - <th class="text-center">{{lang_edit}}</th> - <th class="text-center">{{lang_delete}}</th> + <th data-sort="string">{{lang_description}}</th> + <th class="text-center slx-smallcol"> + {{#perms.roles.edit.disabled}} + {{lang_view}} + {{/perms.roles.edit.disabled}} + {{^perms.roles.edit.disabled}} + {{lang_edit}} + {{/perms.roles.edit.disabled}} + </th> + <th class="text-center slx-smallcol">{{lang_delete}}</th> </tr> </thead> @@ -27,11 +28,14 @@ {{#roles}} <tr> <td class="rolename">{{rolename}}</td> + <td class="text-muted"><table class="slx-ellipsis"><tr><td>{{roledescription}}</td></tr></table></td> <td class="text-center"> - <a class="btn btn-xs btn-primary" href="?do=permissionmanager&show=roleEditor&roleid={{roleid}}"><span class="glyphicon glyphicon-edit"></span></a> + <a class="btn btn-xs btn-primary" href="?do=permissionmanager&show=roleEditor&roleid={{roleid}}"><span class="glyphicon glyphicon-edit"></span></a> </td> <td class="text-center"> - <a class="btn btn-xs btn-danger" href="#deleteModal" data-toggle="modal" data-target="#deleteModal" onclick="deleteRole('{{roleid}}')"><span class="glyphicon glyphicon-trash"></span></a> + <button type="button" class="btn btn-xs btn-danger" data-toggle="modal" data-target="#deleteModal" onclick="deleteRole('{{roleid}}', '{{users}}')" {{perms.roles.edit.disabled}}> + <span class="glyphicon glyphicon-trash"></span> + </button> </td> </tr> {{/roles}} @@ -40,7 +44,6 @@ </div> </div> - <!-- Modals --> <div class ="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> @@ -50,10 +53,11 @@ <h4 class="modal-title" id="myModalLabel">{{lang_delete}}</h4> </div> <div class="modal-body"> - {{lang_deleteCheck}} + <p>{{lang_roleDeleteConfirm}}</p> + {{lang_numAssignedUsers}}: <span id="delete-role-users"></span> </div> <div class="modal-footer"> - <input type="hidden" id="deleteId" name="deleteId" value=""/> + <input type="hidden" id="delete-role-id" name="deleteId" value=""> <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> <button type="submit" name="action" value="deleteRole" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> {{lang_delete}}</button> </div> @@ -63,9 +67,14 @@ </form> +<div class="text-right"> + <a href="?do=permissionmanager&show=roleEditor" class="btn btn-success {{perms.roles.edit.disabled}}"><span class="glyphicon glyphicon-plus"></span> {{lang_newRole}}</a> +</div> + <script> - function deleteRole($roleid) { - $(".modal-footer #deleteId").val($roleid); + function deleteRole(roleid, users) { + $("#delete-role-id").val(roleid); + $("#delete-role-users").text(users); } function searchFieldFunction() { diff --git a/modules-available/permissionmanager/templates/treenode.html b/modules-available/permissionmanager/templates/treenode.html index ced973ca..f8ee3df5 100644 --- a/modules-available/permissionmanager/templates/treenode.html +++ b/modules-available/permissionmanager/templates/treenode.html @@ -1,11 +1,14 @@ {{#toplevel}}<ul>{{/toplevel}} - <li title="{{description}}" data-toggle="tooltip" data-placement="left"> - <div class='checkbox'> - <input id="{{id}}" name="{{checkboxname}}[]" value="{{id}}" type="checkbox" class="form-control" {{#selected}}checked{{/selected}}> - <label for="{{id}}">{{#toplevel}}<b>{{/toplevel}}{{name}}{{#toplevel}}</b>{{/toplevel}}</label> - </div> - <ul> - {{{HTML}}} - </ul> - </li> -{{#toplevel}}</ul>{{/toplevel}} +<li {{#description}}title="{{description}}" data-toggle="tooltip" data-placement="left"{{/description}}> + <div class='checkbox'> + <input id="{{id}}" name="{{checkboxname}}[]" value="{{id}}" type="checkbox" {{#selected}}checked{{/selected}} {{edit_disabled}} {{perms.roles.edit.disabled}}> + <label for="{{id}}"> + {{name}} + {{#location-aware}}<span class="glyphicon glyphicon-home text-muted"></span>{{/location-aware}} + </label> + </div> + <ul> + {{{HTML}}} + </ul> +</li> +{{#toplevel}}</ul>{{/toplevel}}
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/treepanel.html b/modules-available/permissionmanager/templates/treepanel.html index 6f358825..eccecb58 100644 --- a/modules-available/permissionmanager/templates/treepanel.html +++ b/modules-available/permissionmanager/templates/treepanel.html @@ -1,12 +1,12 @@ <div class="panel panel-primary tree-panel"> <div class="panel-heading"> <div class="checkbox"> - <input id="{{id}}" name="{{checkboxname}}[]" value="{{id}}" type="checkbox" class="form-control" {{#selected}}checked{{/selected}}> + <input id="{{id}}" name="{{checkboxname}}[]" value="{{id}}" type="checkbox" class="master-checkbox" {{#selected}}checked{{/selected}} {{perms.roles.edit.disabled}}> <label for="{{id}}">{{name}}</label> </div> </div> <div class="panel-body"> - <div class="tree-container" style="padding-left: 20px; padding-right: 20px;"> + <div class="tree-container"> {{{HTML}}} </div> </div> diff --git a/modules-available/permissionmanager/templates/userstable.html b/modules-available/permissionmanager/templates/userstable.html index bb0e228e..4cda2b1b 100644 --- a/modules-available/permissionmanager/templates/userstable.html +++ b/modules-available/permissionmanager/templates/userstable.html @@ -2,40 +2,23 @@ <input type="hidden" name="token" value="{{token}}"> <div class="row"> - <div class="col-md-4"> - </div> - <div class="col-md-4"> - <select multiple name="roles[]" id="select-role"> - <option value>{{lang_selectizePlaceholder}}</option> - {{#roles}} - <option value="{{roleid}}">{{rolename}}</option> - {{/roles}} - </select> - </div> - <div class="col-md-4 text-right"> - <button class="roleButtons btn btn-success" type="button" data-toggle="modal" data-target="#addRoleToUserModal" disabled><span class="glyphicon glyphicon-share-alt"></span> {{lang_addRole}}</button> - <button class="roleButtons btn btn-danger" type="button" data-toggle="modal" data-target="#removeRoleFromUserModal" disabled><span class="glyphicon glyphicon-remove-circle"></span> {{lang_removeRole}}</button> - </div> - </div> - - <div class="row"> <div class="col-md-12"> <table id="usersTable" class="table table-condensed table-hover stupidtable dataTable"> <thead> <tr> <th data-sort="string">{{lang_users}}</th> - <th>{{lang_roles}}</th> - <th data-sort="int" data-sort-default="desc">{{lang_selected}}</th> + <th class="slx-smallcol">{{lang_roles}}</th> + <th class="slx-smallcol" data-sort="int" data-sort-default="desc">{{lang_selected}}</th> </tr> </thead> <tbody> {{#user}} - <tr data-selectizeCount='0'> + <tr class="{{#roles}}roleid-{{roleid}} {{/roles}}"> <td>{{username}}</td> - <td> + <td class="slx-smallcol"> {{#roles}} - <a href="?do=permissionmanager&show=roleEditor&cancel=users&roleid={{roleid}}" class="label label-default customSpanMargin roleid-{{roleid}}">{{rolename}}</a> + <a href="?do=permissionmanager&show=roleEditor&cancel=users&roleid={{roleid}}" class="label label-default customSpanMargin">{{rolename}}</a> {{/roles}} </td> <td data-sort-value="0"> @@ -71,7 +54,7 @@ </thead> <tbody> - {{#roles}} + {{#allroles}} <tr> <td>{{rolename}}</td> <td data-sort-value="0"> @@ -81,7 +64,7 @@ </div> </td> </tr> - {{/roles}} + {{/allroles}} </tbody> </table> </div> @@ -114,7 +97,7 @@ </thead> <tbody> - {{#roles}} + {{#allroles}} <tr> <td>{{rolename}}</td> <td data-sort-value="0"> @@ -124,7 +107,7 @@ </div> </td> </tr> - {{/roles}} + {{/allroles}} </tbody> </table> </div> @@ -139,6 +122,11 @@ </div> </form> +<div class="text-right"> + <button class="roleButtons btn btn-success" type="button" data-toggle="modal" data-target="#addRoleToUserModal" disabled><span class="glyphicon glyphicon-share-alt"></span> {{lang_addRole}}</button> + <button class="roleButtons btn btn-danger" type="button" data-toggle="modal" data-target="#removeRoleFromUserModal" disabled><span class="glyphicon glyphicon-remove-circle"></span> {{lang_removeRole}}</button> +</div> + <script> selectedUsersCounter = 0; selectedAddRolesCounter = 0; |