diff --git a/.gitignore b/.gitignore index 9b574d8..dc4fcae 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ stylesheet.json .npmrc radix_os_*.png radix_os_icon.ico -login.hbs \ No newline at end of file +login.hbs +todo.txt diff --git a/dbcreate.sql b/dbcreate.sql index f2e4d9c..977e1f7 100644 --- a/dbcreate.sql +++ b/dbcreate.sql @@ -493,12 +493,25 @@ GO CREATE OR ALTER VIEW dbo.vRoleOverview AS -SELECT r.ID, r.Name, r.Description, r.RoleType, COUNT(gr.Group_ObjectGUID) AS GroupCount, COUNT(vau.ObjectGUID) AS UserCount -FROM dbo.Role AS r LEFT OUTER JOIN - dbo.vAuthenticationRoles AS vau ON vau.Role_ID = r.ID LEFT OUTER JOIN - dbo.GroupRoles AS gr ON gr.Role_ID = r.ID LEFT OUTER JOIN - dbo.AuthenticationGroups AS ag ON ag.Group_ObjectGUID = gr.Group_ObjectGUID -GROUP BY r.ID, r.Name, r.Description, r.RoleType +SELECT + r.ID, + r.Name, + r.Description, + r.RoleType, + + COUNT(DISTINCT gr.Group_ObjectGUID) AS GroupCount, + COUNT(DISTINCT vau.ObjectGUID) AS UserCount + +FROM dbo.Role AS r + +LEFT JOIN dbo.vAuthenticationRoles AS vau + ON vau.Role_ID = r.ID + +LEFT JOIN dbo.GroupRoles AS gr + ON gr.Role_ID = r.ID + +GROUP BY + r.ID, r.Name, r.Description, r.RoleType; GO diff --git a/public/javascript/rbacAPI.js b/public/javascript/rbacAPI.js index c4b66fc..163e168 100644 --- a/public/javascript/rbacAPI.js +++ b/public/javascript/rbacAPI.js @@ -39,7 +39,7 @@ const RBAC = { // 🎭 ROLES loadRoles: () => api('/api/rbac/role/get', 'POST'), - createRole: (name) => api('/api/rbac/role', 'POST', { name }), + createRole: (name) => api('/api/rbac/role/create', 'POST', { name }), deleteRole: (id) => api(`/api/rbac/role/${id}`, 'DELETE'), // 🔗 ASSIGNMENTS @@ -53,15 +53,15 @@ const RBAC = { // 🖱️ DRAG & DROP ////////////////////////////// -function createDragZone(el, data) { +function createDragZone(el, data, type) { el.draggable = true; el.addEventListener('dragstart', (evt) => { - evt.dataTransfer.setData('application/json', JSON.stringify(data)); + evt.dataTransfer.setData('application/json', JSON.stringify( { ...data, type })); }); } function createDropZone(el, type, target) { - const targetValue = target.ObjectGUID || target.Role_ID || target.Permission_ID; + const targetValue = target.ObjectGUID || target.ID || target.Role_ID || target.Permission_ID; let process = { action: null, response: null, failure: false }; el.addEventListener('dragover', e => e.preventDefault()); @@ -72,39 +72,45 @@ function createDropZone(el, type, target) { e.dataTransfer.getData('application/json') ); - if(!targetValue) { + if(!targetValue || !data.type) { sendUserEvent('RBAC', 'Deinem Drop-Ziel wurde kein ID-Attribut zugewiesen. Frag einfach Manuel ', null, 2); return; } + // NOCH NICHT UNTER ADMINROUTES EDITIERT: WENN BENUTZER/GRUPPE BEREITS IN ROLLE ENTHALTEN IST switch (type) { case 'group': - process.action = `Du hast den Benutzer der Gruppe hinzugefügt`; - process.response = await RBAC.addUserToGroup(data.ObjectGUID, targetValue); - loadUsers(); - loadGroups(); + if(data.type === 'user') { + process.action = `Du hast den Benutzer der Gruppe hinzugefügt`; + process.response = await RBAC.addUserToGroup(data.ObjectGUID, targetValue); + } break; case 'role': - process.action = `Du hast den Benutzer der Rolle hinzugefügt`; - process.response = await RBAC.addUserToRole(data.ObjectGUID, targetValue); - break; - - case 'group-to-role': - process.action = `Du hast die Gruppe der Rolle hinzugefügt`; - process.response = await RBAC.addGroupToRole(data.ObjectGUID, targetValue); - break; - + if(data.type === 'user') { + process.action = `Du hast den Benutzer der Rolle hinzugefügt`; + process.response = await RBAC.addUserToRole(data.ObjectGUID, targetValue); + break; + } + if(data.type === 'group') { + process.action = `Du hast die Gruppe der Rolle hinzugefügt`; + process.response = await RBAC.addGroupToRole(data.ObjectGUID, targetValue); + break; + } case 'permission': - process.action = `Du hast den Berechtigung der Rolle hinzugefügt`; + process.action = `Du hast die Berechtigung der Rolle hinzugefügt`; process.response = await RBAC.addPermissionToRole(targetValue, data.ID); break; } - if(process.failure) return; + if(process.failure || !process.action) return; + loadUsers(); + loadGroups(); + loadRoles(); sendUserEvent('RBAC', process.action, null, 0); }); } + ////////////////////////////// // 📋 TABLE (USERS) ////////////////////////////// @@ -127,7 +133,7 @@ const rbacVT = virtualTable({ customRender: (row, tr) => { - createDragZone(tr, row); + createDragZone(tr, row, 'user'); tr.addEventListener('contextmenu', (evt) => { evt.preventDefault(); @@ -209,7 +215,7 @@ async function loadGroups() { }; section.append(removeButton); - + createDragZone(section, group, 'group'); createDropZone(section, 'group', group); fragment.appendChild(section); @@ -243,7 +249,7 @@ async function loadRoles() { const section = document.createElement('section'); const roleName = document.createElement('span'); - roleName.innerHTML = role.Name; + roleName.innerHTML = `[${role.UserCount}][${role.GroupCount}] ${role.Name}`; roleName.dataset.tooltip = role.Name; section.append(roleName); @@ -258,12 +264,7 @@ async function loadRoles() { section.append(removeButton); - // 🔥 DROP ZONES - createDropZone(section, 'role', role); // User → Role - createDropZone(section, 'group-to-role', role); // Group → Role - - // optional: permissions - createDropZone(section, 'permission', role); + createDropZone(section, 'role', role); fragment.appendChild(section); }); @@ -384,336 +385,3 @@ loadUsers(); loadGroups(); loadRoles(); - -// const ctx = new ContextMenu(); -// const vt = virtualTable({ -// tableEl: document.querySelector('#rbacUsersTable'), -// data: [], -// rowHeight: 20, -// buffer: 5, -// groupKey: 'ObjectSourceName', // optional zum Gruppieren -// rowKey: 'ObjectGUID', -// filterConfig: { -// hideCounter: true, -// exceptedColumns: ['', 'Rollen', 'Gruppen'], -// columnModes: { -// Aktiv: 'dropdown', -// Online: 'dropdown' -// } -// }, -// customRender: (row, tr) => { -// tr.draggable = true; -// tr.dataset.guid = row['ObjectGUID']; -// tr.dataset.sAMAccountName = row['sAMAccountName']; - -// tr.ondragstart = (evt) => { -// const data = { -// guid: tr.dataset.guid, -// sAMAccountName: tr.dataset.sAMAccountName -// }; -// evt.dataTransfer.setData('application/json', JSON.stringify(data)); -// }; - - -// tr.oncontextmenu = async evt => { -// if (evt.target.tagName === 'BUTTON') return; -// ctx.setItems([ { label: "Details", onClick: () => showAuthDetails(row['ObjectGUID']) } ]); -// evt.preventDefault(); -// ctx.show(evt.pageX + 5, {y: evt.pageY + 5 }); -// }; - -// createTd(tr, -// ``, { -// styles: { -// 'position': 'sticky', -// 'left': '0px', -// 'width': '20px', -// 'z-index': '2' -// }, classes: [ -// 'text-align:left' -// ], onclick: () => { -// if(row['ObjectGUID'] === '00000000-0000-0000-0000-000000000001') return; -// deleteUser(row['ObjectGUID'], row['sAMAccountName']); -// } -// }); - -// createTd(tr, row['ObjectGUID'], { classes: [ 'text-align:left' ], styles: { 'max-width': '100px' }, attributes: { 'data-tooltip': row['ObjectGUID'] } }); -// createTd(tr, row['sAMAccountName'], { classes: [ 'text-align:left' ], attributes: { 'data-tooltip': row['sAMAccountName'] } }); -// createTd(tr, row['sn'], { classes: [ 'text-align:left' ], attributes: { 'data-tooltip': row['sn'] } }); -// createTd(tr, row['givenName'], { classes: [ 'text-align:left' ], attributes: { 'data-tooltip': row['givenName'] } }); -// createTd(tr, row['mail'], { classes: [ 'text-align:left' ], attributes: { 'data-tooltip': row['mail'] } }); -// createTd(tr, row['active'], { classes: [ 'text-align:center' ] }); -// createTd(tr, row['online'], { classes: [ 'text-align:center' ] }); -// createTd(tr, row['RoleCount'], { classes: [ 'text-align:center' ] }); -// createTd(tr, row['GroupCount'], { classes: [ 'text-align:center' ] }); -// } -// }); - - -// async function api(url, method = 'GET', body) { -// const res = await fetch(url, { -// method, -// headers: { 'Content-Type': 'application/json' }, -// body: body ? JSON.stringify(body) : undefined -// }); - -// return res.json(); -// } - - -// async function showAuthDetails(guid) { -// const details = await api(`/api/rbac/auth/details/${guid}`) -// if(!details) return; -// feedbox({ -// title: `Details`, -// message: Object.entries(details).map(([key, value]) => /*html*/`
${key}:${value}
`).join(''), -// buttons: { -// yes: { -// text: 'Schließen' -// } -// }, -// lock: true, -// primary: 'yes' -// }) -// } - - -// async function createUser() { -// const name = document.getElementById('newUserName').value; -// if(!name || !name.includes('.')) { -// sendUserEvent('RBAC', 'Der sAMAccountName muss einen Punkt enthaltenMöchtest du den Benutzer ${sAMAccountName} [${guid}] wirklich löschen
-// `, -// buttons: { -// no: { -// text: 'Nein' -// }, -// yes: { -// text: 'Ja', -// onClick: async () => { -// const user = await api(`/api/rbac/auth/${guid}`, 'DELETE', { -// guid -// }); -// if(user) { -// loadUsers(); -// sendUserEvent('RBAC', `Benutzer ${user.sAMAccountName || ''} [${user.ObjectGUID}] gelöscht`, null, 0); -// } -// } -// } -// } -// }); -// } - - -// async function loadUsers() { -// try { -// const users = await api('/api/rbac/auth/get', 'POST'); -// if(users) { -// vt.source(users); -// return; -// } -// sendUserEvent('RBAC', 'Benutzer konnten nicht geladen', null, 4); -// } catch(err) { -// writeEventLog(4, 'RBAC', err); -// } -// } - - -// async function createGroup() { -// const name = document.getElementById('newGroupName').value; -// const group = await api('/api/rbac/group/create', 'POST', { -// name -// }); -// if(group) { -// sendUserEvent('RBAC', `Gruppe ${name} angelegt`, null, 0); -// loadGroups(); -// } -// } - - -// async function deleteGroup(guid, name) { -// feedbox({ -// title: `Gruppe löschen`, -// message: ` -//Möchtest du die Gruppe ${name} [${guid}] wirklich löschen
-// `, -// buttons: { -// no: { -// text: 'Nein' -// }, -// yes: { -// text: 'Ja', -// onClick: async () => { -// const group = await api(`/api/rbac/group/${guid}`, 'DELETE', { -// guid -// }); -// if(group) { -// sendUserEvent('RBAC', `Gruppe ${group.Name || ''} [${group.ObjectGUID}] gelöscht`, null, 0); -// loadGroups(); -// } -// } -// } -// } -// }); -// // const name = document.getElementById('newGroupName').value; -// // const group = await api('/api/rbac/group/create', 'POST', { -// // name -// // }); -// // if(group) { -// // sendUserEvent('RBAC', `Gruppe ${name} angelegt`, null, 0); -// // loadGroups(); -// // } -// } - - -// // HIER WEITER - GRUPPEN KARTEN MÜSSEN HÜBSCHER WERDEN. -// // BENUTZER UND GRUPPEN KÖNNEN NOCH NICHT GELÖSCHT WERDEN. -// // GRUPPEN AUCH OBJECTSOURCE_ID 1? -// async function loadGroups() { -// try { -// const rbacGroupContainer = document.getElementById('rbacGroupContainer'); -// rbacGroupContainer.innerHTML = ''; -// const groups = await api('/api/rbac/group/get', 'POST'); -// if(groups) { -// let fragment = document.createDocumentFragment(); -// groups.forEach(group => { -// const section = document.createElement('section'); - -// createDropZone(section, 'group', group.ObjectGUID); - -// section.innerHTML = `${group.Name}