completed code and example
This commit is contained in:
parent
f574b323ce
commit
8748836d9f
|
@ -6,11 +6,11 @@
|
|||
<script src="../boot/d4s-boot.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<d4s-boot-2 context="_myextapp"
|
||||
<d4s-boot-2 context="%2Fgcube%2Fdevsec%2FCCP"
|
||||
gateway="next.d4science.org"
|
||||
redirect-url="http://localhost:8080"
|
||||
url="https://accounts.dev.d4science.org/auth">
|
||||
</d4s-boot-2>
|
||||
<d4s-extapp-role-manager appid="076bfe7d-12a2-41d1-a720-05911f0ae527"></d4s-extapp-role-manager>
|
||||
<d4s-extapp-role-manager groupid="8131621c-f896-4d41-81fd-3f6294bf1376" appid="076bfe7d-12a2-41d1-a720-05911f0ae527"></d4s-extapp-role-manager>
|
||||
</body>
|
||||
</html>
|
|
@ -3,35 +3,169 @@ class ExtAppRoleController extends HTMLElement{
|
|||
#boot;
|
||||
#roles;
|
||||
#users;
|
||||
#mappings;
|
||||
#serviceurl;
|
||||
#appid;
|
||||
#groupid;
|
||||
#loading = false;
|
||||
|
||||
#header;
|
||||
#section;
|
||||
|
||||
#userfilter = null;
|
||||
#rolefilter = null;
|
||||
|
||||
constructor(){
|
||||
super()
|
||||
this.#boot = document.querySelector("d4s-boot-2")
|
||||
this.#serviceurl = this.#boot.url
|
||||
this.attachShadow({ mode: "open" });
|
||||
}
|
||||
|
||||
connectedCallback(){
|
||||
this.#appid = this.getAttribute("appid")
|
||||
this.#groupid = this.getAttribute("groupid")
|
||||
if(!this.#loading){
|
||||
this.#loading = true
|
||||
this.loadData()
|
||||
}
|
||||
this.renderStructure()
|
||||
}
|
||||
|
||||
renderStructure(){
|
||||
this.shadowRoot.innerHTML = `
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"/>
|
||||
<style>
|
||||
.dyn-opacity{
|
||||
opacity: .8;
|
||||
transition: opacity .5s;
|
||||
}
|
||||
.dyn-opacity:hover{
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
<header></header>
|
||||
<section></section>
|
||||
`
|
||||
this.#header = this.shadowRoot.querySelector("header")
|
||||
this.#section = this.shadowRoot.querySelector("section")
|
||||
}
|
||||
|
||||
renderHeader(){
|
||||
this.#header.innerHTML = `
|
||||
<div class="row g-0 mb-3" style="gap: 1rem;align-items:baseline;">
|
||||
<input class="col-3 form-control" id="search_user_filter" placeholder="Search by name" style="min-width: 10rem;max-width: 100rem;width: 30rem">
|
||||
<div class="role-filter col-9 d-flex" style="gap:1rem;">
|
||||
${
|
||||
this.#roles.map(r=>{
|
||||
return r.name === 'uma_protection' ? '' : `
|
||||
<div class="form-check form-switch">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" name="${r.id}">
|
||||
<span>${r.name}</span>
|
||||
</label>
|
||||
</div>
|
||||
`
|
||||
}).join("")
|
||||
}
|
||||
</div>
|
||||
</div>`
|
||||
this.attachHeaderEvents()
|
||||
}
|
||||
|
||||
renderUsers(){
|
||||
var users = this.#rolefilter && this.#rolefilter.length ?
|
||||
this.#users.filter(u=>{
|
||||
const assigned = u.mappings.map(m=>m.id)
|
||||
return this.#rolefilter.reduce((a,f)=>{
|
||||
return a && (assigned.indexOf(f) !== -1)
|
||||
}, true)
|
||||
}) : this.#users
|
||||
users = this.#userfilter ?
|
||||
this.#users.filter(u=>{
|
||||
return u.username.toLowerCase().startsWith(this.#userfilter) ||
|
||||
u.lastName.toLowerCase().startsWith(this.#userfilter) ||
|
||||
u.firstName.toLowerCase().startsWith(this.#userfilter) ||
|
||||
u.email.toLowerCase().startsWith(this.#userfilter)}) : users
|
||||
const html = `
|
||||
<ul name="users" style="list-style:none" class="d-flex flex-row flex-wrap gap-2 p-0">
|
||||
${users.map( u=>{
|
||||
return `
|
||||
<li name="user" data-userid="${u.id}" style="user-select:none">
|
||||
<div class="card" style="width:20rem;height:10rem">
|
||||
<div class="card-header">
|
||||
<span name="name" class="fw-bold">${u.firstName} ${u.lastName}</span>
|
||||
</div>
|
||||
<div class="card-body d-flex" style="overflow-y:auto;padding:.5rem">
|
||||
<ul name="roles" style="list-style:none;min-width:70%;overflow-y:auto;align-items: flex-start" class="d-flex flex-row flex-wrap gap-1 pt-1 pb-1 ps-0 me-2">
|
||||
${this.renderMappings(u)}
|
||||
</ul>
|
||||
</divExtAppRoleController>
|
||||
</div>
|
||||
</li>`
|
||||
}).join('')}
|
||||
</li>
|
||||
</ul>
|
||||
`
|
||||
this.#section.innerHTML = html
|
||||
this.attachSectionEvents()
|
||||
}
|
||||
|
||||
renderMappings(u){
|
||||
const html = `
|
||||
<ul name="roles" style="list-style:none;min-width:70%;overflow-y:auto" class="d-flex flex-row flex-wrap gap-1 pt-1 pb-1 ps-0 me-2">
|
||||
${this.#roles ? this.#roles.map(r=>{
|
||||
const assigned = this.isAssigned(u, r)
|
||||
return r.name !== 'uma_protection' ? `
|
||||
<li data-userid="${u.id}" data-roleid="${r.id}" name="role" class="dyn-opacity btn m-0 p-0 ${assigned ? 'active' : ''}">
|
||||
<span style="pointer-events: none" name="name" class="badge bg-${assigned ? 'success' : 'secondary'}">${r.name}</span>
|
||||
</li>` : ''
|
||||
}).join('') : ''}
|
||||
</ul>
|
||||
`
|
||||
return html
|
||||
}
|
||||
|
||||
isAssigned(u, r){
|
||||
return u.mappings && u.mappings.filter(m=>m.id === r.id).length > 0
|
||||
}
|
||||
|
||||
attachSectionEvents(){
|
||||
this.#section.querySelector("ul[name=users]").addEventListener("click", ev=>{
|
||||
const tgt = ev.target
|
||||
if(tgt.getAttribute("name") === "role"){
|
||||
const uid = tgt.getAttribute("data-userid")
|
||||
const rid = tgt.getAttribute("data-roleid")
|
||||
if(tgt.classList.contains("active")){
|
||||
this.toggleMapping(uid, rid)
|
||||
}else{
|
||||
this.toggleMapping(uid, rid, true)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
attachHeaderEvents(){
|
||||
this.#header.querySelector("#search_user_filter").addEventListener("input", ev=>{
|
||||
this.#userfilter = ev.target.value.toLowerCase()
|
||||
this.renderUsers()
|
||||
})
|
||||
|
||||
this.#header.querySelector("div.role-filter").addEventListener("change", ev=>{
|
||||
this.#rolefilter = Array.prototype.slice.call(ev.currentTarget.querySelectorAll("input:checked")).map(r=>r.name)
|
||||
this.renderUsers()
|
||||
})
|
||||
}
|
||||
|
||||
loadData(){
|
||||
Promise.all([
|
||||
this.loadEligibleUsers(), this.loadRoles()
|
||||
]).then(()=>{
|
||||
console.log("Done. Ui should be complete now")
|
||||
//console.log("Done. Ui should be complete now")
|
||||
}).catch(err=>alert(err))
|
||||
}
|
||||
|
||||
loadEligibleUsers(){
|
||||
const url = this.#serviceurl + `/admin/realms/d4science/clients/${this.#appid}/roles/eligible/users?briefRepresentation=true&max=-1&first=0`
|
||||
const url = this.#serviceurl + `/admin/realms/d4science/groups/${this.#groupid}/members?first=0&max=-1&briefRepresentation=true`
|
||||
return this.#boot.secureFetch(url).then(resp=>{
|
||||
if(resp.ok){
|
||||
return resp.json()
|
||||
|
@ -41,11 +175,10 @@ class ExtAppRoleController extends HTMLElement{
|
|||
throw "Fetching users: Unspecified error"
|
||||
}
|
||||
}).then(json=>{
|
||||
console.log("Fetched eligible users can show table")
|
||||
this.#users = json
|
||||
return loadMappings()
|
||||
}).then(()=>{
|
||||
console.log(this.#mappings)
|
||||
const prom = this.loadMappings()
|
||||
this.renderUsers()
|
||||
return prom
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -61,30 +194,53 @@ class ExtAppRoleController extends HTMLElement{
|
|||
}
|
||||
}).then(json=>{
|
||||
this.#roles = json
|
||||
console.log("Roles loaded, could draw header")
|
||||
this.renderHeader()
|
||||
})
|
||||
}
|
||||
|
||||
loadMappings(){
|
||||
return Promise.all(
|
||||
this.#users.forEach(u => {
|
||||
const url = this.#serviceurl + `/admin/realms/d4science/users/${u.id}/clients/${this.#appid}/roles`
|
||||
this.#boot.secureFetch(url).then(resp=>{
|
||||
if(resp.ok){
|
||||
return resp.json()
|
||||
}else if(resp.status === 403){
|
||||
throw "Fetching role mappings: You are not allowed to manage roles for this application."
|
||||
}else{
|
||||
throw "Fetching role mappings: Unspecified error"
|
||||
}
|
||||
}).then(json=>{
|
||||
u.mappings = json
|
||||
console.log(`Fetched mappings for user ${u.id} can update the proper table`)
|
||||
})
|
||||
this.#users.map(u => {
|
||||
return this.loadMapping(u)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
loadMapping(u){
|
||||
const url = this.#serviceurl + `/admin/realms/d4science/users/${u.id}/role-mappings/clients/${this.#appid}`
|
||||
return this.#boot.secureFetch(url).then(resp=>{
|
||||
if(resp.ok){
|
||||
return resp.json()
|
||||
}else if(resp.status === 403){
|
||||
throw "Fetching role mappings: You are not allowed to manage roles for this application."
|
||||
}else{
|
||||
throw "Fetching role mappings: Unspecified error"
|
||||
}
|
||||
}).then(json=>{
|
||||
u.mappings = json
|
||||
this.renderUsers()
|
||||
})
|
||||
}
|
||||
|
||||
toggleMapping(uid, rid, add){
|
||||
const url = this.#serviceurl + `/admin/realms/d4science/users/${uid}/role-mappings/clients/${this.#appid}`
|
||||
const role = this.#roles.filter(r=>r.id === rid)
|
||||
if(role.length !== 1){
|
||||
alert("Something went wrong with looking up the role")
|
||||
return
|
||||
}
|
||||
this.#boot.secureFetch(url, { method : add ? "POST" : "DELETE", body : JSON.stringify(role), headers : { "Content-Type" : "application/json"}}).then(resp=>{
|
||||
if(resp.ok){
|
||||
return resp.text()
|
||||
}else if(resp.status === 403){
|
||||
throw "Assigning or removing role: You are not allowed to manage roles for this application."
|
||||
}else{
|
||||
throw "Assigning or removing role: Unspecified error"
|
||||
}
|
||||
}).then(()=>{
|
||||
return this.loadMapping(this.#users.filter(u=>u.id === uid)[0])
|
||||
}).catch(err=>alert(err))
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('d4s-extapp-role-manager', ExtAppRoleController);
|
Loading…
Reference in New Issue