365 lines
15 KiB
TypeScript
365 lines
15 KiB
TypeScript
import m from "mithril"
|
|
import {hasAppRole, iUser} from "./models/users"
|
|
import {iApplication} from "./models/applications"
|
|
import {iRole} from "./models/roles"
|
|
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "../widgets/Treetable_V2"
|
|
import {gridMountpoints, maingrid} from "../mainlayout"
|
|
import {ModalView, ModalType, iModalView} from "../widgets/Modal"
|
|
import { iWrongEditSelectionMessage, WrongEditSelectionMessage, showServerError} from "./authmessages"
|
|
|
|
|
|
interface iTabelrow {
|
|
rowtype: any
|
|
col1: any
|
|
cols: any[]
|
|
info?: {
|
|
parentuserid: number
|
|
parentappid: number
|
|
roleid: number
|
|
ischecked: boolean
|
|
}
|
|
}
|
|
|
|
const localDataModel = {
|
|
userlist: [] as iUser[],
|
|
applist: [] as iApplication[],
|
|
usernodes: [] as iTreenode[],
|
|
startexpanded: false,
|
|
loadData: () => {
|
|
Promise.all([
|
|
m.request({
|
|
method: "GET",
|
|
url: "/auth/getusers"
|
|
}).then((result) => localDataModel.userlist = result as iUser[]),
|
|
m.request({
|
|
method: "GET",
|
|
url: "/auth/getapplications"
|
|
}).then((result) => localDataModel.applist = result as iApplication[]),
|
|
])
|
|
.then(() => {
|
|
localDataModel.usernodes = []
|
|
localDataModel.userlist.map((u) => {
|
|
let userrow: iTabelrow = {
|
|
rowtype: 'user',
|
|
col1: u.userid,
|
|
cols: [u.username, u.email, u.telefon]
|
|
}
|
|
let usernode: iTreenode = new Treenode(userrow, localDataModel.startexpanded, [])
|
|
localDataModel.applist.forEach((app: iApplication) => {
|
|
let approw: iTabelrow = {
|
|
rowtype: "app",
|
|
col1: app.appid,
|
|
cols: [app.name, app.minversion],
|
|
info: {
|
|
ischecked: false,
|
|
parentuserid: u.id,
|
|
parentappid: null,
|
|
roleid: null
|
|
}
|
|
|
|
}
|
|
let appnode: Treenode = new Treenode(approw, localDataModel.startexpanded, [])
|
|
app.roles.forEach((role: iRole) => {
|
|
let ischecked = hasAppRole(u, app.id, role.id)
|
|
let rolerow: iTabelrow = {
|
|
rowtype: "role",
|
|
col1: role.name,
|
|
cols: [role.roleid],
|
|
info: {
|
|
parentuserid: u.id,
|
|
parentappid: app.id,
|
|
ischecked: ischecked,
|
|
roleid: role.id
|
|
}
|
|
}
|
|
let rolenode: iTreenode = new Treenode(rolerow, localDataModel.startexpanded, [])
|
|
appnode.children.push(rolenode)
|
|
})
|
|
usernode.children.push(appnode)
|
|
})
|
|
localDataModel.usernodes.push(usernode)
|
|
})
|
|
})
|
|
.catch((e) => {
|
|
if (e.code == 401) {
|
|
m.route.set("/login")
|
|
}
|
|
})
|
|
},
|
|
updateUser: (user: iUser) => {
|
|
m.request ({
|
|
method: "POST", // Hier muss POST verwendet werden, weil GET keinen Body hat und Parameter nur im URL transportieren kann
|
|
url: "/auth/updateuser",
|
|
body: user
|
|
})
|
|
.catch((e) => {showServerError(e)})
|
|
.finally(() => localDataModel.loadData())
|
|
},
|
|
deleteUsers: (users: iUser[]) => {
|
|
m.request({
|
|
method: "POST",
|
|
url: "/auth/deleteusers",
|
|
body: users.map((u: iUser) => {return u.userid})
|
|
})
|
|
.catch((e) => {showServerError(e)})
|
|
.finally(() => localDataModel.loadData())
|
|
},
|
|
applyUserAppRole: (tablerow: iTabelrow) => {
|
|
m.request ({
|
|
method: "POST",
|
|
url: "/auth/applyuserapprole",
|
|
body: tablerow.info
|
|
})
|
|
.catch((e) => {showServerError(e); localDataModel.loadData()})
|
|
}
|
|
}
|
|
|
|
export const userlist: m.ClosureComponent = (vnode) => {
|
|
return {
|
|
oninit: (vnode) => {
|
|
localDataModel.loadData()
|
|
},
|
|
view: (vnode) => {
|
|
return m("div.w3-container.w3-content", {style: {'max-width': 'min-content', display: 'flex', 'flex-direction': 'column', height: 'inherit', 'overflow-y': 'inherit'}},
|
|
m("h1", "Benutzerliste"),
|
|
m("div", {style: {flex: '1', 'overflow-y': 'inherit'}},
|
|
m(Treetable,
|
|
{
|
|
startexpanded: localDataModel.startexpanded,
|
|
treenodes: localDataModel.usernodes,
|
|
columnmapper: (node: iTreenode) => {
|
|
let row: iTabelrow = node.nodevalue
|
|
let isChecked = hasCheckedChilds(node)
|
|
if (row.rowtype == "user") {
|
|
return [
|
|
m("strong", row.col1),
|
|
m("strong", row.cols[0]),
|
|
m(isChecked?"div.w3-text-green":"div.w3-text-red", {style: {display: 'flex'}},
|
|
// m("div", {style: {padding: '0px', height:'24px', width: '24px'}},
|
|
// m("i.material-icons", isChecked?null:"dangerous"),
|
|
// ),
|
|
m("div", isChecked?"aktiv":"inaktiv")
|
|
),
|
|
m("div.w3-small",
|
|
m("div", row.cols[1]),
|
|
m("div", row.cols[2])
|
|
),
|
|
m(EditUserButton, {userid: row.col1} as iEditUserButton),
|
|
m(DeleteUserButton, {userid: row.col1} as iDeleteUserButton)
|
|
]
|
|
}
|
|
else if (row.rowtype == "role") {
|
|
return [
|
|
m("span.w3-small", row.col1),
|
|
m("span.w3-button", {
|
|
style: {padding: '0px'},
|
|
onclick: () => {
|
|
row.info.ischecked = !row.info.ischecked
|
|
localDataModel.applyUserAppRole(row)
|
|
}
|
|
},
|
|
m("i.material-icons.w3-theme-light", row.info.ischecked?"check_box":"check_box_outline_blank")
|
|
),
|
|
m("span.w3-small", row.cols[0]),
|
|
m("span.w3-small", row.cols[1]),
|
|
m("span", ""),
|
|
m("span", "")
|
|
]
|
|
}
|
|
else {
|
|
// rowtype "app"
|
|
let isChecked = hasCheckedChilds(node)
|
|
return [
|
|
m(isChecked?"span":"strong.w3-text-red", row.col1),
|
|
m("div", {style: {padding: '0px', height:'24px', width: '24px'}},
|
|
m("i.material-icons", isChecked?"check":null)
|
|
),
|
|
m("span", row.cols[0]),
|
|
m("span", row.cols[1]),
|
|
m("span", ""),
|
|
m("span", "")
|
|
]
|
|
}
|
|
}
|
|
} as iTreetable,
|
|
m(TopbarButton, {
|
|
onclick: () => {
|
|
m.mount(gridMountpoints.modalhook, {
|
|
view: (vnode) => {
|
|
return m(UserForm, {user: {id: -1} as iUser})
|
|
}
|
|
})
|
|
}} as iTopbarButton,
|
|
m("i.material-icons", "add")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
function hasCheckedChilds(parenttreenode: iTreenode): boolean {
|
|
return parenttreenode.children.some((treenode: iTreenode) => {
|
|
if (treenode.hasChildren) {
|
|
return hasCheckedChilds(treenode)
|
|
}
|
|
let tablerow = treenode.nodevalue as iTabelrow
|
|
return tablerow.info.ischecked
|
|
})
|
|
}
|
|
|
|
interface iUserForm {
|
|
user: iUser
|
|
}
|
|
const UserForm: m.ClosureComponent<iUserForm> = () => {
|
|
let form: HTMLFormElement = null;
|
|
let currentuser: iUser
|
|
function reset (e) {
|
|
form.reset()
|
|
}
|
|
function unmount () {
|
|
m.mount(gridMountpoints.modalhook, null)
|
|
}
|
|
function submit (e) {
|
|
e.preventDefault()
|
|
let formdata: FormData = new FormData(e.target as HTMLFormElement)
|
|
|
|
for (let element of formdata) {
|
|
currentuser[element[0]] = element[1]
|
|
}
|
|
localDataModel.updateUser(currentuser)
|
|
unmount()
|
|
}
|
|
return {
|
|
oninit: (vnode) => {
|
|
currentuser = (vnode.attrs.user === undefined) ? {} as iUser : vnode.attrs.user
|
|
},
|
|
view: (vnode) => {
|
|
return m(ModalView,
|
|
{
|
|
title: "Benutzer",
|
|
type: ModalType.MESSAGE,
|
|
width: 'max-content'
|
|
} as iModalView,
|
|
|
|
m("form.w3-padding-16", {oncreate: (vnode) => {form = vnode.dom as HTMLFormElement}, onsubmit: submit},
|
|
m("label", "ID (intern)"),
|
|
m("div.w3-padding-small", currentuser.id),
|
|
m("label", "Benutzer-ID"),
|
|
m("input.w3-input.w3-border", {name: 'userid', type: 'text', value: currentuser.userid}),
|
|
m("label", "Name"),
|
|
m("input.w3-input.w3-border", {name: 'username', type: 'text', value: currentuser.username}),
|
|
m("label", "E-Mail"),
|
|
m("input.w3-input.w3-border", {name: 'email', type: 'email', value: currentuser.email}),
|
|
m("label", "Telefon"),
|
|
m("input.w3-input.w3-border", {name: 'telefon', type: 'tel', value: currentuser.telefon}),
|
|
m("div.w3-bar.w3-padding-16",
|
|
[
|
|
m("button.w3-button.w3-theme.w3-right", {style: {'margin-left': '4px'}, type: "submit"}, "Speichern"),
|
|
m("button.w3-button.w3-theme.w3-right", {style: {'margin-left': '4px'}, onclick: unmount, type: "button"}, "Abbrechen"),
|
|
m("button.w3-button.w3-theme.w3-right", {onclick: reset, type: "button"}, "Zurücksetzen")
|
|
|
|
]
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
const WrongUserEditSelectionMessage: m.Component = {
|
|
view: () => {
|
|
return m(WrongEditSelectionMessage, {elementname: "Benutzer"} as iWrongEditSelectionMessage)
|
|
}
|
|
}
|
|
|
|
interface iDeleteUsersMessage {
|
|
userid: string
|
|
}
|
|
const DeleteUsersMessage: m.ClosureComponent<iDeleteUsersMessage> = (vnode) => {
|
|
let users: iUser[]
|
|
return {
|
|
oninit: (vnode) => {
|
|
users = localDataModel.userlist.filter((u: iUser) => {
|
|
return u.userid == vnode.attrs.userid
|
|
})
|
|
},
|
|
view: (vnode) => {
|
|
return (
|
|
m(ModalView,
|
|
{
|
|
title: "Benutzer löschen",
|
|
type: ModalType.MESSAGE,
|
|
width: '33%'
|
|
} as iModalView,
|
|
m("p", "Sie wollen den folgenden Benutzer löschen:"),
|
|
m("ul",
|
|
users.map((user: iUser) => {
|
|
return m("li", `${user.userid} (${user.username})`)
|
|
})
|
|
),
|
|
m("div.w3-bar.w3-padding-16",
|
|
[
|
|
m("button.w3-button.w3-theme.w3-right",
|
|
{
|
|
style: {'margin-left': '4px'},
|
|
onclick: () => {
|
|
localDataModel.deleteUsers(users);
|
|
m.mount(gridMountpoints.modalhook, null)
|
|
}}, "Löschen"),
|
|
m("button.w3-button.w3-theme.w3-right", {onclick: () => {m.mount(gridMountpoints.modalhook, null)}}, "Abbrechen"),
|
|
]
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
interface iDeleteUserButton {
|
|
userid: string
|
|
}
|
|
export const DeleteUserButton: m.ClosureComponent<iDeleteUserButton> = () => {
|
|
return {
|
|
view: (vnode) => {
|
|
return m("button.w3-button.w3-bar-item", {
|
|
style: {'min-width': '24px', height: '24px', padding: '0'},
|
|
onclick: () => {
|
|
m.mount(gridMountpoints.modalhook, {view: () => {
|
|
return m(DeleteUsersMessage, {userid: vnode.attrs.userid} as iDeleteUsersMessage)
|
|
}})
|
|
},
|
|
title: "Benutzer löschen"
|
|
},
|
|
m("i.material-icons", "delete_forever")
|
|
)
|
|
}
|
|
}
|
|
}
|
|
interface iEditUserButton {
|
|
userid: string
|
|
}
|
|
export const EditUserButton: m.ClosureComponent<iEditUserButton> = () => {
|
|
return {
|
|
view: (vnode) => {
|
|
return m("button.w3-button.w3-bar-item", {
|
|
style: {'min-width': '24px', height: '24px', padding: '0'},
|
|
onclick: () => {
|
|
let users: iUser[] = localDataModel.userlist.filter((u:iUser) => {
|
|
return u.userid == vnode.attrs.userid
|
|
})
|
|
m.mount(gridMountpoints.modalhook, {view: () => {
|
|
return m(UserForm, {user: users[0]} as iUserForm)
|
|
}})
|
|
},
|
|
title: "Benutzer bearbeiten"
|
|
},
|
|
m("i.material-icons", "edit")
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
|