diff options
13 files changed, 492 insertions, 11 deletions
diff --git a/modules-available/permissionmanager/clientscript.js b/modules-available/permissionmanager/clientscript.js new file mode 100644 index 00000000..da825984 --- /dev/null +++ b/modules-available/permissionmanager/clientscript.js @@ -0,0 +1,12 @@ +document.addEventListener("DOMContentLoaded", function() { + var table = $("table").stupidtable(); + + // to show the sort-arrow next to the table header + table.on("aftertablesort", function (event, data) { + var th = $(this).find("th"); + th.find(".arrow").remove(); + var dir = $.fn.stupidtable.dir; + var arrow = data.direction === dir.ASC ? "down" : "up"; + th.eq(data.column).append(' <span class="arrow glyphicon glyphicon-chevron-'+arrow+'"></span>'); + }); +});
\ No newline at end of file diff --git a/modules-available/permissionmanager/config.json b/modules-available/permissionmanager/config.json index 706412d0..3aeab3e5 100644 --- a/modules-available/permissionmanager/config.json +++ b/modules-available/permissionmanager/config.json @@ -1,3 +1,4 @@ { - "category":"main.content" + "category":"main.content", + "dependencies": [ "js_stupidtable"] } diff --git a/modules-available/permissionmanager/inc/dbupdate.inc.php b/modules-available/permissionmanager/inc/dbupdate.inc.php new file mode 100644 index 00000000..20ff746a --- /dev/null +++ b/modules-available/permissionmanager/inc/dbupdate.inc.php @@ -0,0 +1,37 @@ +<?php + +class DbUpdate { + + // insert new userXrole to database. "ignore" to ignore duplicate entry try + public static function addRoleToUser($users, $roles) { + foreach($users AS $user) { + foreach ($roles AS $role) { + $query = "INSERT IGNORE INTO userXrole (userid, roleid) VALUES ($user, $role)"; + Database::exec($query); + } + } + } + + // remove userXrole entry from database + public static function removeRoleFromUser($users, $roles) { + foreach($users AS $user) { + foreach ($roles AS $role) { + $query = "DELETE FROM userXrole WHERE userid = $user AND roleid = $role"; + Database::exec($query); + } + } + } + + // delete role, delete userXrole relationships, delete roleXlocation relationships, delete roleXpermission relationships + public static function deleteRole($id) { + $query = "DELETE FROM role WHERE id = $id"; + Database::exec($query); + $query = "DELETE FROM userXrole WHERE roleid = $id"; + Database::exec($query); + $query = "DELETE FROM roleXlocation WHERE roleid = $id"; + Database::exec($query); + $query = "DELETE FROM roleXpermission WHERE roleid = $id"; + Database::exec($query); + } + +} diff --git a/modules-available/permissionmanager/inc/getdata.inc.php b/modules-available/permissionmanager/inc/getdata.inc.php new file mode 100644 index 00000000..7eac333f --- /dev/null +++ b/modules-available/permissionmanager/inc/getdata.inc.php @@ -0,0 +1,43 @@ +<?php + +class GetData { + + // get UserIDs, User Login Names, User Roles + public static function getUserData() { + $res = self::queryUserData(); + $data = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $data[] = array( + 'userid' => $row['userid'], + 'name' => $row['login'], + 'role' => explode(",",$row['role']) + ); + } + return $data; + } + + // get all roles from database (id and name) + public static function getRoles() { + $res = Database::simpleQuery("SELECT id, name FROM role ORDER BY name"); + $data = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $data[] = array( + 'roleId' => $row['id'], + 'roleName' => $row['name'] + ); + } + return $data; + } + + // UserID, User Login Name, Roles of each User + private static function queryUserData() { + $res = Database::simpleQuery("SELECT user.userid AS userid, user.login AS login, GROUP_CONCAT(role.name) AS role + FROM user + LEFT JOIN userXrole ON user.userid = userXrole.userid + LEFT JOIN role ON userXrole.roleid = role.id + GROUP BY user.userid + "); + return $res; + } + +}
\ No newline at end of file diff --git a/modules-available/permissionmanager/install.inc.php b/modules-available/permissionmanager/install.inc.php new file mode 100644 index 00000000..a873f2c0 --- /dev/null +++ b/modules-available/permissionmanager/install.inc.php @@ -0,0 +1,27 @@ +<?php + +$res = array(); + +$res[] = tableCreate('role', " + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(200) NOT NULL, + PRIMARY KEY (`id`) +"); + +$res[] = tableCreate('userXrole', " + `userid` int(10) unsigned NOT NULL, + `roleid` int(10) unsigned NOT NULL, + PRIMARY KEY (`userid`, `roleid`) +"); + +$res[] = tableCreate('roleXlocation', " + `roleid` int(10) unsigned NOT NULL, + `locid` int(10) unsigned NOT NULL, + PRIMARY KEY (`roleid`, `locid`) +"); + +$res[] = tableCreate('roleXpermission', " + `roleid` int(10) unsigned NOT NULL, + `permissionid`int(10) unsigned NOT NULL, + PRIMARY KEY (`roleid`, `permissionid`) +"); diff --git a/modules-available/permissionmanager/lang/de/template-tags.json b/modules-available/permissionmanager/lang/de/template-tags.json index ce98ce38..bec71103 100644 --- a/modules-available/permissionmanager/lang/de/template-tags.json +++ b/modules-available/permissionmanager/lang/de/template-tags.json @@ -1,3 +1,14 @@ { - "lang_hello": "Hallo" + "lang_Roles": "Rollen", + "lang_Users": "Nutzer", + "lang_Locations": "Räume", + "lang_addRole": "Rolle zuweisen", + "lang_removeRole": "Rolle entfernen", + "lang_newRole": "Rolle anlegen", + "lang_Selected": "Ausgewählt", + "lang_Edit": "Bearbeiten", + "lang_Remove": "Entfernen", + "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?" }
\ 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 c30739e5..e699e102 100644 --- a/modules-available/permissionmanager/lang/en/template-tags.json +++ b/modules-available/permissionmanager/lang/en/template-tags.json @@ -1,3 +1,14 @@ { - "lang_hello": "Hello" + "lang_Roles": "Roles", + "lang_Users": "Users", + "lang_Locations": "Locations", + "lang_addRole": "Add Role", + "lang_removeRole": "Remove Role", + "lang_newRole": "New Role", + "lang_Selected": "Selected", + "lang_Edit": "Edit", + "lang_Remove": "Remove", + "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?" }
\ No newline at end of file diff --git a/modules-available/permissionmanager/page.inc.php b/modules-available/permissionmanager/page.inc.php index 871e7946..faf8b300 100644 --- a/modules-available/permissionmanager/page.inc.php +++ b/modules-available/permissionmanager/page.inc.php @@ -14,6 +14,20 @@ class Page_PermissionManager extends Page Message::addError('main.no-permission'); Util::redirect('?do=Main'); // does not return } + + $action = Request::any('action', 'show', 'string'); + if ($action === 'addRoleToUser') { + $users = Request::post('users', ''); + $roles = Request::post('roles', ''); + DbUpdate::addRoleToUser($users, $roles); + } else if ($action === 'removeRoleFromUser') { + $users = Request::post('users', ''); + $roles = Request::post('roles', ''); + DbUpdate::removeRoleFromUser($users, $roles); + } else if ($action === 'deleteRole') { + $id = Request::post('deleteId', false, 'string'); + DbUpdate::deleteRole($id); + } } /** @@ -21,10 +35,51 @@ class Page_PermissionManager extends Page */ protected function doRender() { - Render::addTemplate('_page', array( - 'foo' => 'bar', - 'now' => date('d.m.Y H:i:s') - )); + $show = Request::get("show", false); + // get menu button colors + $buttonColors = self::setButtonColors($show); + + $data = array(); + + // switch between tables, but always show menu to switch tables + if (!$show || $show === 'roles' || $show === 'users' || $show === 'locations') { + Render::openTag('div', array('class' => 'row')); + Render::addtemplate('_page', $buttonColors); + Render::closeTag('div'); + + if ($show === "roles") { + $data = array("roles" => GetData::getRoles()); + Render::addTemplate('rolesTable', $data); + } else if ($show === "users") { + $data = array("user" => GetData::getUserData(), "roles" => GetData::getRoles()); + Render::addTemplate('usersTable', $data); + } else if ($show === "locations") { + Render::addTemplate('locationsTable', $data); + } + } + } + + // Menu: Selected table is shown in blue (btn-primary) + function setButtonColors($show) { + if ($show === 'roles') { + $buttonColors['rolesButtonClass'] = 'btn-primary'; + $buttonColors['usersButtonClass'] = 'btn-default'; + $buttonColors['locationsButtonClass'] = 'btn-default'; + } else if ($show === 'users') { + $buttonColors['rolesButtonClass'] = 'btn-default'; + $buttonColors['usersButtonClass'] = 'btn-primary'; + $buttonColors['locationsButtonClass'] = 'btn-default'; + } else if ($show === 'locations') { + $buttonColors['rolesButtonClass'] = 'btn-default'; + $buttonColors['usersButtonClass'] = 'btn-default'; + $buttonColors['locationsButtonClass'] = 'btn-primary'; + } else { + $buttonColors['rolesButtonClass'] = 'btn-default'; + $buttonColors['usersButtonClass'] = 'btn-default'; + $buttonColors['locationsButtonClass'] = 'btn-default'; + } + + return $buttonColors; } } diff --git a/modules-available/permissionmanager/style.css b/modules-available/permissionmanager/style.css new file mode 100644 index 00000000..ee81bf47 --- /dev/null +++ b/modules-available/permissionmanager/style.css @@ -0,0 +1,29 @@ +#switchForm { + text-align: center; + margin-bottom: 50px; +} + +.table { + margin-top: 20px; +} + +.table > tbody > tr > td { + vertical-align: middle; + height: 50px; +} + +.checkbox { + margin-top: 0; + margin-bottom: 0; +} + +.scrollingTable { + height: 500px; + overflow: auto; +} + +.customSpanMargin { + display: inline-block; + margin-top: 2px; + margin-bottom: 2px; +}
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/_page.html b/modules-available/permissionmanager/templates/_page.html index dfc941ae..3b436eda 100644 --- a/modules-available/permissionmanager/templates/_page.html +++ b/modules-available/permissionmanager/templates/_page.html @@ -1,4 +1,20 @@ -<div style="border:5px solid red"> - <h1>{{lang_hello}}, {{foo}}</h1> - ** {{now}} ** -</div>
\ No newline at end of file +<form id="switchForm" method="GET" action="?do=permissionmanager"> + <input type="hidden" name="do" value="permissionmanager"> + + <div class="btn-group"> + <button class="btn {{rolesButtonClass}}" type="submit" name="show" value="roles"> + <span class="glyphicon glyphicon-education"></span> + {{lang_Roles}} + </button> + + <button class="btn {{usersButtonClass}}" type="submit" name="show" value="users"> + <span class="glyphicon glyphicon-user"></span> + {{lang_Users}} + </button> + + <button class="btn {{locationsButtonClass}}" type="submit" name="show" value="locations"> + <span class="glyphicon glyphicon-home"></span> + {{lang_Locations}} + </button> + </div> +</form>
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/locationsTable.html b/modules-available/permissionmanager/templates/locationsTable.html new file mode 100644 index 00000000..bd3b7f88 --- /dev/null +++ b/modules-available/permissionmanager/templates/locationsTable.html @@ -0,0 +1,14 @@ +<div class="row"> + <div class="col-md-12"> + <table id="locationsTable" class="table table-condensed table-hover"> + <thead> + + </thead> + + <tbody> + + + </tbody> + </table> + </div> +</div>
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/rolesTable.html b/modules-available/permissionmanager/templates/rolesTable.html new file mode 100644 index 00000000..40cdda96 --- /dev/null +++ b/modules-available/permissionmanager/templates/rolesTable.html @@ -0,0 +1,65 @@ +<form method="post" action="?do=permissionmanager"> + <input type="hidden" name="token" value="{{token}}"> + + <button class="btn btn-success" type="button" onclick="openRoleEditor()"><span class="glyphicon glyphicon-plus"></span> {{lang_newRole}}</button> + + <div class="row"> + <div class="col-md-12"> + <table id="rolesTable" class="table table-condensed table-hover"> + <thead> + <tr> + <th data-sort="string">{{lang_Roles}}</th> + <th>{{lang_Edit}}</th> + <th>{{lang_Delete}}</th> + </tr> + </thead> + + <tbody> + {{#roles}} + <tr> + <td>{{roleName}}</td> + <td> + <a href="?do=permissionmanager&show=roleEditor&roleid={{roleId}}">{{lang_Edit}}</a> + </td> + <td> + <a href="#deleteModal" data-toggle="modal" data-target="#deleteModal" onclick="deleteRole('{{roleId}}')">{{lang_Delete}}</a> + </td> + </tr> + {{/roles}} + </tbody> + </table> + </div> + </div> + + + <!-- Modals --> + <div class ="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="myModalLabel">{{lang_Delete}}</h4> + </div> + <div class="modal-body"> + {{lang_deleteCheck}} + </div> + <div class="modal-footer"> + <input type="hidden" id="deleteId" 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> + </div> + </div> + </div> + +</form> + +<script> + function openRoleEditor() { + window.location.href = "?do=permissionmanager&show=roleEditor" + } + + function deleteRole($roleId) { + $(".modal-footer #deleteId").val($roleId); + } +</script>
\ No newline at end of file diff --git a/modules-available/permissionmanager/templates/usersTable.html b/modules-available/permissionmanager/templates/usersTable.html new file mode 100644 index 00000000..3db1ebdb --- /dev/null +++ b/modules-available/permissionmanager/templates/usersTable.html @@ -0,0 +1,160 @@ +<form method="post" action="?do=permissionmanager"> + <input type="hidden" name="token" value="{{token}}"> + <button class="btn btn-success" type="button" data-toggle="modal" data-target="#addRoleToUserModal"><span class="glyphicon glyphicon-share-alt"></span> {{lang_addRole}}</button> + <button class="btn btn-danger" type="button" data-toggle="modal" data-target="#removeRoleFromUserModal"><span class="glyphicon glyphicon-trash"></span> {{lang_removeRole}}</button> + + <div class="row"> + <div class="col-md-12"> + <table id="usersTable" class="table table-condensed table-hover"> + <thead> + <tr> + <th data-sort="string">{{lang_Users}}</th> + <th>{{lang_Roles}}</th> + <th data-sort="int" data-sort-default="desc">{{lang_Selected}}</th> + </tr> + </thead> + + <tbody> + {{#user}} + <tr> + <td>{{name}}</td> + <td> + {{#role}} + <span class="label label-default customSpanMargin">{{.}}</span> + {{/role}} + </td> + <td data-sort-value="0"> + <div class="checkbox"> + <input id="{{userid}}" type="checkbox" name="users[]" value='{{userid}}'> + <label for="{{userid}}"></label> + </div> + </td> + </tr> + {{/user}} + </tbody> + </table> + </div> + </div> + + <!-- Modals --> + <div class ="modal fade" id="addRoleToUserModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="myModalLabel">{{lang_addRole}}</h4> + </div> + <div class="modal-body"> + <div class="row"> + <div class="col-md-12 scrollingTable"> + <table id="addRoleToUserTable" class="table table-condensed table-hover"> + <thead> + <tr> + <th data-sort="string">{{lang_Roles}}</th> + <th data-sort="int" data-sort-default="desc">{{lang_Selected}}</th> + </tr> + </thead> + + <tbody> + {{#roles}} + <tr> + <td>{{roleName}}</td> + <td data-sort-value="0"> + <div class="checkbox"> + <input id="add{{roleId}}" type="checkbox" name="roles[]" value='{{roleId}}'> + <label for="add{{roleId}}"></label> + </div> + </td> + </tr> + {{/roles}} + </tbody> + </table> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> + <button type="submit" name="action" value="addRoleToUser" class="btn btn-success" onclick="clearRemoveRoleModal()"><span class="glyphicon glyphicon-share-alt"></span> {{lang_addRole}}</button> + </div> + </div> + </div> + </div> + + <div class ="modal fade" id="removeRoleFromUserModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="myModalLabel2">{{lang_Remove}}</h4> + </div> + <div class="modal-body"> + <div class="row"> + <div class="col-md-12 scrollingTable"> + <table id="removeRoleFromUserTable" class="table table-condensed table-hover"> + <thead> + <tr> + <th data-sort="string">{{lang_Roles}}</th> + <th data-sort="int" data-sort-default="desc">{{lang_Selected}}</th> + </tr> + </thead> + + <tbody> + {{#roles}} + <tr> + <td>{{roleName}}</td> + <td data-sort-value="0"> + <div class="checkbox"> + <input id="remove{{roleId}}" type="checkbox" name="roles[]" value='{{roleId}}'> + <label for="remove{{roleId}}"></label> + </div> + </td> + </tr> + {{/roles}} + </tbody> + </table> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> + <button type="submit" name="action" value="removeRoleFromUser" class="btn btn-danger" onclick="clearAddRoleModal()"><span class="glyphicon glyphicon-trash"></span> {{lang_Remove}}</button> + </div> + </div> + </div> + </div> +</form> + +<script> + document.addEventListener("DOMContentLoaded", function() { + // if checked,: mark green, else: unmark + $('input:checkbox').change(function() { + if ($(this).is(':checked')) { + $(this).closest("td").data("sort-value", 1); + $(this).closest("tr").css("background-color", "#f2ffe6"); + } else { + $(this).closest("td").data("sort-value", 0); + $(this).closest("tr").css("background-color", ""); + } + + }); + + }); + + + // if remove-Role button is clicked, uncheck all checkboxes in add-role modal so they aren't submitted too + function clearAddRoleModal () { + $('#addRoleToUserModal') + .find("input[type=checkbox]") + .prop("checked", "") + .end(); + } + + // if add-Role button is clicked, uncheck all checkboxes in remove-role modal so they aren't submitted too + function clearRemoveRoleModal() { + $('#removeRoleFromUserModal') + .find("input[type=checkbox]") + .prop("checked", "") + .end(); + } + +</script>
\ No newline at end of file |