client/ split to a separate repository.
Repository URL is https://git.karchnu.fr/WeirdOS/authd-maquettec.gitipc07
parent
1270408aca
commit
8a6719fe26
141
client/authws.ls
141
client/authws.ls
|
@ -1,141 +0,0 @@
|
||||||
bulma = require "./bulma.ls"
|
|
||||||
h = require 'maquette' .h
|
|
||||||
|
|
||||||
AuthWS = (socket-url) ->
|
|
||||||
self = {}
|
|
||||||
|
|
||||||
request-types = {
|
|
||||||
"get-token": 0
|
|
||||||
"add-user": 1
|
|
||||||
"get-user": 2
|
|
||||||
"get-user-by-credentials": 3
|
|
||||||
"mod-user": 4
|
|
||||||
"register": 5
|
|
||||||
"get-extra": 6
|
|
||||||
"set-extra": 7
|
|
||||||
"update-password": 8
|
|
||||||
"list-users": 9
|
|
||||||
}
|
|
||||||
|
|
||||||
response-types = {
|
|
||||||
"error": 0
|
|
||||||
"token": 1
|
|
||||||
"user": 2
|
|
||||||
"user-added": 3
|
|
||||||
"user-edited": 4
|
|
||||||
"extra": 5
|
|
||||||
"extra-updated": 6
|
|
||||||
"users-list": 7
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: naming convention
|
|
||||||
# users can record functions to run on events
|
|
||||||
self.user-on-socket-error = []
|
|
||||||
self.user-on-socket-close = []
|
|
||||||
|
|
||||||
self.callbacks = {}
|
|
||||||
for key, value of response-types
|
|
||||||
self.callbacks[value] = []
|
|
||||||
|
|
||||||
self.add-event-listener = (type, callback) ->
|
|
||||||
type = response-types[type]
|
|
||||||
|
|
||||||
self.callbacks[type] ++= [callback]
|
|
||||||
|
|
||||||
self.open-socket = ->
|
|
||||||
self.socket := new WebSocket socket-url
|
|
||||||
|
|
||||||
self.socket.onerror = (event) ->
|
|
||||||
for f in self.user-on-socket-error
|
|
||||||
f event
|
|
||||||
self.socket.close!
|
|
||||||
|
|
||||||
self.socket.onclose = (event) ->
|
|
||||||
for f in self.user-on-socket-close
|
|
||||||
f event
|
|
||||||
|
|
||||||
self.socket.onmessage = (event) ->
|
|
||||||
message = JSON.parse(event.data)
|
|
||||||
|
|
||||||
for f in self.callbacks[message.mtype]
|
|
||||||
f JSON.parse(message.payload)
|
|
||||||
|
|
||||||
self.reopen = ->
|
|
||||||
self.socket.close!
|
|
||||||
self.open-socket!
|
|
||||||
|
|
||||||
self.open-socket!
|
|
||||||
|
|
||||||
self.send = (type, opts) ->
|
|
||||||
self.socket.send JSON.stringify { mtype: type, payload: opts }
|
|
||||||
|
|
||||||
self.get-token = (login, password) ->
|
|
||||||
self.send request-types[\get-token], JSON.stringify {
|
|
||||||
login: login
|
|
||||||
password: password
|
|
||||||
}
|
|
||||||
|
|
||||||
self.get-user-by-credentials = (login, password) ->
|
|
||||||
self.send request-types[\get-user-by-credentials], JSON.stringify {
|
|
||||||
login: login
|
|
||||||
password: password
|
|
||||||
}
|
|
||||||
|
|
||||||
self.login = (login, password) ->
|
|
||||||
self.get-token login, password
|
|
||||||
self.get-user-by-credentials login, password
|
|
||||||
|
|
||||||
|
|
||||||
self.get-user = (uid) ->
|
|
||||||
self.send request-types[\get-user], JSON.stringify {
|
|
||||||
uid: uid
|
|
||||||
}
|
|
||||||
|
|
||||||
self.register = (login, password) ->
|
|
||||||
self.send request-types[\register], JSON.stringify {
|
|
||||||
login: login
|
|
||||||
password: password
|
|
||||||
}
|
|
||||||
|
|
||||||
self.get-extra = (token, name) ->
|
|
||||||
self.send request-types[\get-extra], JSON.stringify {
|
|
||||||
token: token
|
|
||||||
name: name
|
|
||||||
}
|
|
||||||
|
|
||||||
self.set-extra = (token, name, extra) ->
|
|
||||||
self.send request-types[\set-extra], JSON.stringify {
|
|
||||||
token: token
|
|
||||||
name: name
|
|
||||||
extra: extra
|
|
||||||
}
|
|
||||||
|
|
||||||
self.update-password = (login, old-password, new-password) ->
|
|
||||||
self.send request-types[\update-password], JSON.stringify {
|
|
||||||
login: login
|
|
||||||
old_password: old-password
|
|
||||||
new_password: new-password
|
|
||||||
}
|
|
||||||
|
|
||||||
self.list-users = (token) ->
|
|
||||||
self.send request-types[\list-users], JSON.stringify {
|
|
||||||
token: token
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: authd overhaul required
|
|
||||||
#self.add-user = (login, password) ->
|
|
||||||
# self.send request-types[\add-user], JSON.stringify {
|
|
||||||
# login: login
|
|
||||||
# password: password
|
|
||||||
# }
|
|
||||||
|
|
||||||
# TODO: authd overhaul required
|
|
||||||
#self.mod-user = (uid) ->
|
|
||||||
# self.send request-types[\mod-user], JSON.stringify {
|
|
||||||
# uid: uid
|
|
||||||
# }
|
|
||||||
|
|
||||||
self
|
|
||||||
|
|
||||||
module.exports = AuthWS
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
|
|
||||||
h = require 'maquette' .h
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
box: (args, children) ->
|
|
||||||
h \div.box args, children
|
|
||||||
title: (level, args, label) ->
|
|
||||||
if not label
|
|
||||||
label = args
|
|
||||||
args = {}
|
|
||||||
|
|
||||||
h "div.title.is-#{level}", args, [label]
|
|
||||||
label: (args, label) ->
|
|
||||||
if not label
|
|
||||||
label = args
|
|
||||||
args = {}
|
|
||||||
|
|
||||||
h \label.label args, [label]
|
|
||||||
input: (args, children) ->
|
|
||||||
h \input.input args, children
|
|
||||||
|
|
||||||
# FIXME: Use only args and add args.label and args.input?
|
|
||||||
# Or maybe args.name and args.type could be used directly?
|
|
||||||
field: (args, children) ->
|
|
||||||
h \div.field args, children
|
|
||||||
|
|
||||||
modal: (args, content) ->
|
|
||||||
h \div.modal args, [
|
|
||||||
h \div.modal-background args.background
|
|
||||||
h \div.modal-content [args.content]
|
|
||||||
]
|
|
||||||
|
|
||||||
form: (method, url, content) ->
|
|
||||||
h \form.form {
|
|
||||||
action: url
|
|
||||||
method: method
|
|
||||||
}, content
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>AuthD</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<link rel="stylesheet" href="/style.css"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="/main.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,92 +0,0 @@
|
||||||
maquette = require "maquette"
|
|
||||||
|
|
||||||
{create-projector, h} = maquette
|
|
||||||
|
|
||||||
projector = create-projector!
|
|
||||||
|
|
||||||
bulma = require "./bulma.ls"
|
|
||||||
|
|
||||||
AuthWS = require "./authws.ls"
|
|
||||||
|
|
||||||
LoginForm = require "./login-form.ls"
|
|
||||||
UserConfigurationPanel = require "./user-configuration-panel.ls"
|
|
||||||
UserAdminPanel = require "./user-admin-panel.ls"
|
|
||||||
|
|
||||||
model = {
|
|
||||||
token: void
|
|
||||||
}
|
|
||||||
|
|
||||||
authws-url = "ws://localhost:9999/auth.JSON"
|
|
||||||
|
|
||||||
document.add-event-listener \DOMContentLoaded ->
|
|
||||||
user-config-panel = void
|
|
||||||
user-admin-panel = void
|
|
||||||
|
|
||||||
login-form = LoginForm {
|
|
||||||
enable-registration: true
|
|
||||||
authws-url: authws-url
|
|
||||||
|
|
||||||
on-login: (user, token) ->
|
|
||||||
model.user := user
|
|
||||||
model.token := token
|
|
||||||
|
|
||||||
if user.groups.find (== "authd")
|
|
||||||
user-admin-panel := UserAdminPanel {
|
|
||||||
authws-url: authws-url
|
|
||||||
user: model.user
|
|
||||||
token: model.token
|
|
||||||
|
|
||||||
on-model-update: ->
|
|
||||||
projector.schedule-render!
|
|
||||||
on-logout: ->
|
|
||||||
model.token := void
|
|
||||||
model.user := void
|
|
||||||
}
|
|
||||||
else
|
|
||||||
user-config-panel := UserConfigurationPanel {
|
|
||||||
authws-url: authws-url
|
|
||||||
user: model.user
|
|
||||||
token: model.token
|
|
||||||
|
|
||||||
on-model-update: ->
|
|
||||||
projector.schedule-render!
|
|
||||||
on-logout: ->
|
|
||||||
model.token := void
|
|
||||||
model.user := void
|
|
||||||
}
|
|
||||||
|
|
||||||
projector.schedule-render!
|
|
||||||
on-error: (error) ->
|
|
||||||
projector.schedule-render!
|
|
||||||
}
|
|
||||||
|
|
||||||
projector.append document.body, ->
|
|
||||||
h \div.body [
|
|
||||||
if model.token == void
|
|
||||||
h \div.section.hero.is-fullheight [
|
|
||||||
h \div.hero-body [
|
|
||||||
h \div.container [
|
|
||||||
h \div.columns [
|
|
||||||
h \div.column []
|
|
||||||
h \div.column.is-3 [
|
|
||||||
login-form.render!
|
|
||||||
]
|
|
||||||
h \div.column []
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
else if user-config-panel
|
|
||||||
h \div.section [
|
|
||||||
h \div.container [
|
|
||||||
user-config-panel.render!
|
|
||||||
]
|
|
||||||
]
|
|
||||||
else if user-admin-panel
|
|
||||||
h \div.section [
|
|
||||||
h \div.container [
|
|
||||||
user-admin-panel.render!
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,221 +0,0 @@
|
||||||
maquette = require "maquette"
|
|
||||||
|
|
||||||
{h} = maquette
|
|
||||||
|
|
||||||
bulma = require "./bulma.ls"
|
|
||||||
|
|
||||||
AuthWS = require "./authws.ls"
|
|
||||||
|
|
||||||
LoginForm = (args) ->
|
|
||||||
args or= {}
|
|
||||||
|
|
||||||
self = {
|
|
||||||
on-login: args.on-login || ->
|
|
||||||
on-error: args.on-error || ->
|
|
||||||
schedule-render: args.schedule-render || ->
|
|
||||||
current-view: "login"
|
|
||||||
|
|
||||||
enable-registration: args.enable-registration || false
|
|
||||||
registrating: false
|
|
||||||
|
|
||||||
input: {
|
|
||||||
login: ""
|
|
||||||
password: ""
|
|
||||||
repeat-password: ""
|
|
||||||
}
|
|
||||||
locked-input: true
|
|
||||||
|
|
||||||
error: void
|
|
||||||
|
|
||||||
authws-url: args.authws-url ||
|
|
||||||
((if location.protocol == 'https' then 'wss' else 'ws') +
|
|
||||||
'://' + location.hostname + ":9999/auth.JSON")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
auth-ws = AuthWS self.authws-url
|
|
||||||
|
|
||||||
auth-ws.socket.onopen = ->
|
|
||||||
self.locked-input := false
|
|
||||||
self.schedule-render!
|
|
||||||
|
|
||||||
auth-ws.user-on-socket-error.push (...) ->
|
|
||||||
self.error = "socket error"
|
|
||||||
self.on-error ...
|
|
||||||
|
|
||||||
auth-ws.add-event-listener \token, (message) ->
|
|
||||||
self.error := void
|
|
||||||
|
|
||||||
self.token = message.token
|
|
||||||
self.locked-input := false
|
|
||||||
|
|
||||||
if self.user
|
|
||||||
self.on-login self.user, self.token
|
|
||||||
|
|
||||||
auth-ws.add-event-listener \user, (message) ->
|
|
||||||
self.error := void
|
|
||||||
|
|
||||||
self.user = message.user
|
|
||||||
|
|
||||||
if self.token
|
|
||||||
self.on-login self.user, self.token
|
|
||||||
|
|
||||||
auth-ws.add-event-listener \user-added, (message) ->
|
|
||||||
{login, password} = {self.input.login, self.input.password}
|
|
||||||
|
|
||||||
console.log "user added, duh"
|
|
||||||
|
|
||||||
self.user := message.user
|
|
||||||
|
|
||||||
auth-ws.get-token login, password
|
|
||||||
|
|
||||||
auth-ws.add-event-listener \error, (message) ->
|
|
||||||
# We’ll get another error that’s clearer. Dropping that one.
|
|
||||||
if message.reason == "user not found"
|
|
||||||
return
|
|
||||||
|
|
||||||
self.error := message.reason
|
|
||||||
self.locked-input := false
|
|
||||||
|
|
||||||
self.on-error message.reason
|
|
||||||
|
|
||||||
self.render = ->
|
|
||||||
if self.error == "socket error"
|
|
||||||
return h \div.notification.is-danger [
|
|
||||||
h \div.title.is-4 [ "WebSocket error!" ]
|
|
||||||
h \p [ "Cannot connect to authd." ]
|
|
||||||
]
|
|
||||||
|
|
||||||
h \form.form.login-form {
|
|
||||||
key: self
|
|
||||||
onsubmit: (e) ->
|
|
||||||
{login, password} = {self.input.login, self.input.password}
|
|
||||||
|
|
||||||
self.locked-input := true
|
|
||||||
|
|
||||||
if self.registrating
|
|
||||||
auth-ws.register login, password
|
|
||||||
else
|
|
||||||
auth-ws.get-token login, password
|
|
||||||
auth-ws.get-user-by-credentials login, password
|
|
||||||
|
|
||||||
e.prevent-default!
|
|
||||||
}, [
|
|
||||||
h \div.field {key: \login} [
|
|
||||||
bulma.label "Login"
|
|
||||||
bulma.input {
|
|
||||||
type: "text"
|
|
||||||
id: "login"
|
|
||||||
name: "login"
|
|
||||||
classes: {
|
|
||||||
"is-danger": self.error == "invalid credentials"
|
|
||||||
}
|
|
||||||
disabled: self.locked-input
|
|
||||||
oninput: (e) ->
|
|
||||||
self.input.login = e.target.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
h \div.field {key: \password} [
|
|
||||||
bulma.label "Password"
|
|
||||||
bulma.input {
|
|
||||||
type: "password"
|
|
||||||
id: "password"
|
|
||||||
name: "password"
|
|
||||||
classes: {
|
|
||||||
"is-danger": self.error == "invalid credentials"
|
|
||||||
}
|
|
||||||
oninput: (e) ->
|
|
||||||
self.input.password = e.target.value
|
|
||||||
disabled: self.locked-input
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
if self.registrating
|
|
||||||
h \div.field {key: \password-repeat} [
|
|
||||||
bulma.label "Password (reapeat)"
|
|
||||||
bulma.input {
|
|
||||||
type: \password
|
|
||||||
id: \password-repeat
|
|
||||||
name: \password-repeat
|
|
||||||
classes: {
|
|
||||||
"is-danger": self.input.password != self.input.repeat-password
|
|
||||||
}
|
|
||||||
disabled: self.locked-input
|
|
||||||
oninput: (e) ->
|
|
||||||
self.input.repeat-password = e.target.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
if self.error
|
|
||||||
h \div.field {key: \error-notification} [
|
|
||||||
h \div.notification.is-danger [
|
|
||||||
self.error
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
if self.registrating
|
|
||||||
h \div.field.is-grouped {key: \login-button} [
|
|
||||||
if self.input.login == ""
|
|
||||||
h \button.button.is-static.is-fullwidth {
|
|
||||||
type: \submit
|
|
||||||
} [
|
|
||||||
"(empty login)"
|
|
||||||
]
|
|
||||||
else if self.input.password != self.input.repeat-password
|
|
||||||
h \button.button.is-static.is-fullwidth {
|
|
||||||
type: \submit
|
|
||||||
} [
|
|
||||||
"(passwords don’t match)"
|
|
||||||
]
|
|
||||||
else if self.input.password == ""
|
|
||||||
h \button.button.is-static.is-fullwidth {
|
|
||||||
type: \submit
|
|
||||||
} [
|
|
||||||
"(empty password)"
|
|
||||||
]
|
|
||||||
else
|
|
||||||
h \button.button.is-success.is-fullwidth {
|
|
||||||
type: \submit
|
|
||||||
} [
|
|
||||||
"Register!"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
else
|
|
||||||
h \div.field.is-grouped {key: \login-button} [
|
|
||||||
h \button.button.is-fullwidth.is-success {
|
|
||||||
type: \submit
|
|
||||||
} [
|
|
||||||
"Log in!"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
h \div.field.level {key: \extra-buttons} [
|
|
||||||
#h \div.level-left [
|
|
||||||
# h \a.link [ "(lala, remember me?)" ]
|
|
||||||
#]
|
|
||||||
|
|
||||||
if self.enable-registration
|
|
||||||
h \div.level-right [
|
|
||||||
if self.registrating
|
|
||||||
h \a.link {
|
|
||||||
onclick: (e) ->
|
|
||||||
self.registrating := false
|
|
||||||
} [
|
|
||||||
"Log in"
|
|
||||||
]
|
|
||||||
else
|
|
||||||
h \a.link {
|
|
||||||
onclick: (e) ->
|
|
||||||
self.registrating := true
|
|
||||||
} [
|
|
||||||
"Create account!"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
self
|
|
||||||
|
|
||||||
module.exports = LoginForm
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
@charset "utf-8"
|
|
||||||
|
|
||||||
//@import "../node_modules/bulmaswatch/superhero/_variables.scss"
|
|
||||||
|
|
||||||
// Import Bulma core
|
|
||||||
@import "../node_modules/bulma/bulma"
|
|
||||||
|
|
||||||
//@import "../node_modules/bulmaswatch/superhero/_overrides.scss"
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
{h} = require "maquette"
|
|
||||||
|
|
||||||
AuthWS = require "./authws.ls"
|
|
||||||
|
|
||||||
UserAdminPanel = (args) ->
|
|
||||||
self = {
|
|
||||||
token: args.token
|
|
||||||
authws-url: args.authws-url
|
|
||||||
on-logout: args.on-logout || ->
|
|
||||||
on-model-update: args.on-model-update || ->
|
|
||||||
users: []
|
|
||||||
}
|
|
||||||
|
|
||||||
authws = AuthWS self.authws-url
|
|
||||||
|
|
||||||
authws.socket.onopen = ->
|
|
||||||
authws.list-users self.token
|
|
||||||
|
|
||||||
authws.add-event-listener \users-list (message) ->
|
|
||||||
self.users = message.users
|
|
||||||
|
|
||||||
self.on-model-update!
|
|
||||||
|
|
||||||
self.render = ->
|
|
||||||
h \div.section [
|
|
||||||
h \div.container [
|
|
||||||
h \table.table.is-fullwidth [
|
|
||||||
h \thead [
|
|
||||||
h \tr [
|
|
||||||
h \th [ "Login" ]
|
|
||||||
h \th [ "UID" ]
|
|
||||||
h \th [ "GID" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
h \tbody [
|
|
||||||
for user in self.users
|
|
||||||
h \tr {key: user.uid} [
|
|
||||||
h \td [
|
|
||||||
user.login
|
|
||||||
]
|
|
||||||
h \td [
|
|
||||||
user.uid.toString!
|
|
||||||
]
|
|
||||||
h \td [
|
|
||||||
user.gid.toString!
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
h \div.button {
|
|
||||||
onclick: ->
|
|
||||||
self.on-logout!
|
|
||||||
self.on-model-update!
|
|
||||||
} [
|
|
||||||
"Log out"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
self
|
|
||||||
|
|
||||||
module.exports = UserAdminPanel
|
|
||||||
|
|
|
@ -1,267 +0,0 @@
|
||||||
|
|
||||||
{h} = require "maquette"
|
|
||||||
|
|
||||||
AuthWS = require "./authws.ls"
|
|
||||||
|
|
||||||
get-full-name = (self) ->
|
|
||||||
full-name = self.profile && self.profile.full-name || ""
|
|
||||||
if full-name == ""
|
|
||||||
self.user.login
|
|
||||||
else
|
|
||||||
full-name
|
|
||||||
|
|
||||||
default-side-bar-renderer = (self) ->
|
|
||||||
h \div { key: \side-bar } [
|
|
||||||
h \figure.image.is-128x128.is-clipped [
|
|
||||||
if self.profile && self.profile.avatar
|
|
||||||
h \img {
|
|
||||||
src: self.profile.avatar
|
|
||||||
alt: "Avatar of #{get-full-name self}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
default-heading-renderer = (self) ->
|
|
||||||
full-name = get-full-name self
|
|
||||||
|
|
||||||
h \div.section {key: \heading} [
|
|
||||||
h \div.media [
|
|
||||||
h \div.media-content [
|
|
||||||
h \div.title.is-2 [ full-name ]
|
|
||||||
|
|
||||||
if full-name != self.user.login
|
|
||||||
h \div.title.is-3.subtitle [
|
|
||||||
self.user.login
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
if self.on-logout
|
|
||||||
h \div.media-right [
|
|
||||||
h \a {
|
|
||||||
onclick: ->
|
|
||||||
self.on-logout!
|
|
||||||
} [ "Logout" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
Fields = {
|
|
||||||
render-text-input: (token, auth-ws, key, inputs, model, on-request) ->
|
|
||||||
upload = ->
|
|
||||||
console.log "clickity click", key, inputs[key], inputs
|
|
||||||
return unless inputs[key]
|
|
||||||
|
|
||||||
payload = {}
|
|
||||||
for _key, value of model
|
|
||||||
payload[_key] = value
|
|
||||||
payload[key] = inputs[key]
|
|
||||||
|
|
||||||
inputs[key] := void
|
|
||||||
|
|
||||||
on-request!
|
|
||||||
auth-ws.set-extra token, "profile", payload
|
|
||||||
|
|
||||||
h \div.field.has-addons {key: key} [
|
|
||||||
h \div.control.is-expanded [
|
|
||||||
h \input.input {
|
|
||||||
value: inputs[key] || model[key]
|
|
||||||
oninput: (e) ->
|
|
||||||
console.log "input for",key
|
|
||||||
inputs[key] := e.target.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
h \div.control [
|
|
||||||
h \div.button {
|
|
||||||
onclick: upload
|
|
||||||
} [ "Update" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
UserConfigurationPanel = (args) ->
|
|
||||||
self = {
|
|
||||||
user: args.user || {}
|
|
||||||
profile: args.profile
|
|
||||||
token: args.token
|
|
||||||
authws-url: args.authws-url ||
|
|
||||||
((if location.protocol == 'https' then 'wss' else 'ws') +
|
|
||||||
'://' + location.hostname + ":9999/auth.JSON")
|
|
||||||
|
|
||||||
side-bar-renderer: args.side-bar-renderer || default-side-bar-renderer
|
|
||||||
heading-renderer: args.heading-renderer || default-heading-renderer
|
|
||||||
|
|
||||||
on-model-update: args.on-model-update || ->
|
|
||||||
on-logout: args.on-logout || void
|
|
||||||
|
|
||||||
model: args.model || [
|
|
||||||
["fullName", "Full Name", "string"]
|
|
||||||
["avatar", "Profile Picture", "image-url"]
|
|
||||||
["email", "Mail Address", "string"]
|
|
||||||
]
|
|
||||||
|
|
||||||
input: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
auth-ws = AuthWS self.authws-url
|
|
||||||
|
|
||||||
auth-ws.add-event-listener \extra, (message) ->
|
|
||||||
if message.name == "profile"
|
|
||||||
console.log "got profile", message.extra
|
|
||||||
self.profile = message.extra || {}
|
|
||||||
|
|
||||||
self.on-model-update!
|
|
||||||
|
|
||||||
auth-ws.add-event-listener \extra-updated, (message) ->
|
|
||||||
if message.name == "profile"
|
|
||||||
console.log "got profile", message.extra
|
|
||||||
self.profile = message.extra || {}
|
|
||||||
|
|
||||||
self.on-model-update!
|
|
||||||
|
|
||||||
auth-ws.add-event-listener \error, (message) ->
|
|
||||||
self.error := message.reason
|
|
||||||
|
|
||||||
self.on-model-update!
|
|
||||||
|
|
||||||
# Profile updates would be a \extra-updated, so this is specific to the
|
|
||||||
# password.
|
|
||||||
auth-ws.add-event-listener \user-edited, (message) ->
|
|
||||||
self.input["password.old"] := void
|
|
||||||
self.input["password.new"] := void
|
|
||||||
self.input["password.new2"] := void
|
|
||||||
self.success := "password"
|
|
||||||
self.on-model-update!
|
|
||||||
|
|
||||||
unless self.profile
|
|
||||||
auth-ws.socket.onopen = ->
|
|
||||||
auth-ws.get-extra self.token, "profile"
|
|
||||||
|
|
||||||
self.render = ->
|
|
||||||
h \div.columns {
|
|
||||||
key: self
|
|
||||||
} [
|
|
||||||
h \div.column.is-narrow [
|
|
||||||
self.side-bar-renderer self
|
|
||||||
]
|
|
||||||
h \div.column [
|
|
||||||
self.heading-renderer self
|
|
||||||
|
|
||||||
if self.profile
|
|
||||||
h \div.box {key: \profile} [
|
|
||||||
h \div.form [
|
|
||||||
h \div.title.is-4 [ "Profile" ]
|
|
||||||
|
|
||||||
for element in self.model
|
|
||||||
[key, label, type] = element
|
|
||||||
|
|
||||||
switch type
|
|
||||||
when "string", "image-url"
|
|
||||||
h \div.field { key: key } [
|
|
||||||
h \div.label [ label ]
|
|
||||||
Fields.render-text-input self.token, auth-ws, key, self.input, self.profile, (-> self.error := void)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
else
|
|
||||||
# FIXME: urk, ugly loader.
|
|
||||||
h \div.button.is-loading
|
|
||||||
|
|
||||||
h \div.box { key: \password } [
|
|
||||||
h \div.title.is-4 [ "Password" ]
|
|
||||||
h \div.label [ "Old password" ]
|
|
||||||
h \div.control [
|
|
||||||
h \input.input {
|
|
||||||
type: \password
|
|
||||||
value: self.input["password.old"]
|
|
||||||
oninput: (e) ->
|
|
||||||
self.input["password.old"] = e.target.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.error == "invalid credentials"
|
|
||||||
h \div.help.is-danger [
|
|
||||||
"The old password was invalid!"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
h \div.label [ "New password" ]
|
|
||||||
h \div.control [
|
|
||||||
h \input.input {
|
|
||||||
type: \password
|
|
||||||
value: self.input["password.new"]
|
|
||||||
oninput: (e) ->
|
|
||||||
self.input["password.new"] = e.target.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
h \div.label [ "New password (repeat)" ]
|
|
||||||
h \div.field.has-addons [
|
|
||||||
h \div.control.is-expanded [
|
|
||||||
h \input.input {
|
|
||||||
type: \password
|
|
||||||
value: self.input["password.new2"]
|
|
||||||
oninput: (e) ->
|
|
||||||
self.input["password.new2"] = e.target.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
h \div.control [
|
|
||||||
h \div.button {
|
|
||||||
classes: {
|
|
||||||
"is-danger": self.input["password.new"] && self.input["password.new"] != self.input["password.new2"]
|
|
||||||
"is-static": (!self.input["password.new"]) && self.input["password.new"] != self.input["password.new2"]
|
|
||||||
}
|
|
||||||
onclick: ->
|
|
||||||
if self.input["password.new"] != self.input["password.new2"]
|
|
||||||
return
|
|
||||||
|
|
||||||
self.error := void
|
|
||||||
auth-ws.update-password self.user.login, self.input["password.old"], self.input["password.new"]
|
|
||||||
|
|
||||||
} [ "Update" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
if self.success == "password"
|
|
||||||
h \div.help.is-success [
|
|
||||||
"Password successfully updated!"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
if self.show-developer
|
|
||||||
h \div.box {key: \passwd} [
|
|
||||||
h \div.title.is-4 [ "Permissions" ]
|
|
||||||
|
|
||||||
h \div.form [
|
|
||||||
h \div.field {key: \uid} [
|
|
||||||
h \div.label [ "User ID" ]
|
|
||||||
h \div.control [ self.user.uid.to-string! ]
|
|
||||||
]
|
|
||||||
|
|
||||||
h \div.field {key: \gid} [
|
|
||||||
h \div.label [ "Group ID" ]
|
|
||||||
h \div.control [ self.user.gid.to-string! ]
|
|
||||||
]
|
|
||||||
|
|
||||||
h \div.field {key: \groups} [
|
|
||||||
h \div.label [ "Groups" ]
|
|
||||||
h \div.control.is-grouped [
|
|
||||||
h \div.tags self.user.groups.map (group) ->
|
|
||||||
h \div.tag [ group ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
else
|
|
||||||
h \a.is-pulled-right.is-small.has-text-grey {
|
|
||||||
key: \passwd
|
|
||||||
onclick: ->
|
|
||||||
self.show-developer := true
|
|
||||||
self.on-model-update!
|
|
||||||
} [
|
|
||||||
"Show developer data!"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
self
|
|
||||||
|
|
||||||
module.exports = UserConfigurationPanel
|
|
||||||
|
|
Loading…
Reference in New Issue