267 lines
8.4 KiB
JavaScript
Executable File
267 lines
8.4 KiB
JavaScript
Executable File
'use strict'
|
|
/**
|
|
__ __
|
|
( )( ) ___ ____ ____
|
|
)( )( / __)( ___)( _ \
|
|
)(__)( \__ \ )__) ) /
|
|
(______)(___/(____)(_)\_)
|
|
By Nike
|
|
|
|
This file is part of P42 implementation of SPARC.
|
|
* @category MyEic
|
|
* @subcategory Libraries
|
|
* @extends User
|
|
*/
|
|
class myUser extends app.LoadedClasses.User {
|
|
|
|
authUrl = '';
|
|
preferences = {}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
constructor() { super(); }
|
|
|
|
/**
|
|
* Checks if user belongs to a role
|
|
* @param {string} role
|
|
* @returns {boolean}
|
|
*/
|
|
hasRole(role) { return(this.roles.indexOf(role)>-1); }
|
|
|
|
/**
|
|
*
|
|
* @returns {Array<string>}
|
|
*/
|
|
getRoles() { return(app.User.roles); }
|
|
|
|
/**
|
|
*
|
|
* @returns {Promise<Array>}
|
|
*/
|
|
fetchServices() {
|
|
return(fetch('/app/assets/json/global/services.json?'+crypto.randomUUID(), {
|
|
method: 'GET'
|
|
})
|
|
.then(response => response.text())
|
|
.then(response => JSON.parse(response))
|
|
.then(response => app.config.api = response.payload)
|
|
)
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {*} callBack
|
|
*/
|
|
async checkAuthenticated(callBack){
|
|
const startbtn = document.querySelector('#startbtn')
|
|
const gobtn = document.querySelector('#login-dialog button')
|
|
|
|
gobtn.addEventListener('click', () => this.launchLogin(callBack))
|
|
|
|
startbtn.addEventListener('click', async () => {
|
|
startbtn.disabled = true
|
|
this.isAuthenticated = false
|
|
const response = await fetch(app.config.userLib.checkauthEndpoint+'?'+crypto.randomUUID())
|
|
let jsonresp = null
|
|
if(response.ok) { jsonresp = await response.json() }
|
|
if(!jsonresp ||(!jsonresp.payload)) {
|
|
console.error('No valid response from checkauth !?')
|
|
startbtn.disabled = false
|
|
} else if(!jsonresp.payload.authenticated){
|
|
document.querySelector('div.loginerr').classList.remove('show')
|
|
document.getElementById('login-dialog').classList.add('show')
|
|
document.querySelector('input[name="username"]').focus()
|
|
document.getElementById('login-dialog').addEventListener('keyup',(event)=>{
|
|
if(event.key=='Enter') this.launchLogin(callBack)
|
|
})
|
|
if(jsonresp.payload.locked){
|
|
document.querySelector('div.loginerr').classList.add('show')
|
|
document.querySelector('div.loginerr').innerHTML = `
|
|
The account has been locked !<br>
|
|
(Ask an admin to unlock it.)
|
|
`
|
|
}
|
|
} else {
|
|
console.log('authenticated!')
|
|
this.isAuthenticated = true
|
|
this.identity = jsonresp.payload.userInfos.identity
|
|
this.roles = jsonresp.payload.userInfos.roles
|
|
this.loadUserModel()
|
|
callBack()
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
|
|
async launchLogin(callBack){
|
|
const gobtn = document.querySelector('#login-dialog button')
|
|
gobtn.disabled = true
|
|
if(await this.login()) {
|
|
document.querySelector('div.loginerr').classList.remove('show')
|
|
console.log('Successful login !!!')
|
|
this.loadUserModel()
|
|
callBack()
|
|
} else {
|
|
gobtn.disabled = false
|
|
}
|
|
}
|
|
|
|
loadUserModel(){
|
|
app.events.addEvent('core.mvcReady', async () => {
|
|
await Loader.loadScripts({
|
|
'scripts':[app.config.userLib.modelPath],
|
|
'dependencies':[],
|
|
})
|
|
this.model = new MyUserModleModel()
|
|
this.loadPreferences()
|
|
this.fetchServices()
|
|
}, 'myUser')
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
getMessageBusUserInfo() { return(this.identity.username) }
|
|
|
|
async login(){
|
|
const response = await fetch(app.config.userLib.loginEndpoint+'?'+crypto.randomUUID(), {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
username: document.querySelector('input[name="username"]').value,
|
|
passwd: document.querySelector('input[name="password"]').value,
|
|
})
|
|
})
|
|
let jsonresp = null
|
|
if(response.ok) { jsonresp = await response.json() }
|
|
if(jsonresp && jsonresp.success && jsonresp.payload){
|
|
if(jsonresp.payload.authenticated){
|
|
this.isAuthenticated = true
|
|
this.identity = jsonresp.payload.userInfos.identity
|
|
this.roles = jsonresp.payload.userInfos.roles
|
|
return(true)
|
|
} else {
|
|
document.querySelector('div.loginerr').classList.add('show')
|
|
if(!jsonresp.payload.locked){
|
|
document.querySelector('div.loginerr').innerHTML = `
|
|
Bad username or password !<br>
|
|
(${jsonresp.payload.trials} trials left.)
|
|
`
|
|
} else {
|
|
document.querySelector('div.loginerr').innerHTML = `
|
|
The account has been locked !<br>
|
|
(Ask an admin to unlock it.)
|
|
`
|
|
}
|
|
}
|
|
}
|
|
this.isAuthenticated = false
|
|
this.identity = null
|
|
return(false)
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} jumpTo
|
|
*/
|
|
logout(jumpTo='') {
|
|
jumpTo = jumpTo ? jumpTo : this.logoutUrl
|
|
fetch(app.config.userLib.logoutEndpoint+'?'+crypto.randomUUID(),{
|
|
method: 'GET',
|
|
credentials: 'include'
|
|
}).then((resp) =>{
|
|
window.onbeforeunload = null // If user confirmed to logout, not need to have him confirm he's leaving the app !
|
|
document.location.href = jumpTo;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This is separated, so that upper layer has a chance to use a login button, or avoid redirection loops.
|
|
*/
|
|
gotoLogin() {
|
|
window.onbeforeunload = null // If user asks to relogin, not need to have him confirm he's leaving the app !
|
|
document.location.href = this.authUrl;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {*} info
|
|
*/
|
|
async parseUserInfo(info) {
|
|
|
|
this.identity = {
|
|
uuid: info.euLoginId,
|
|
firstname: info.family_name,
|
|
lastname: info.given_name,
|
|
email: info.email
|
|
};
|
|
this.roles = info.userRoles || []
|
|
}
|
|
|
|
loadPreferences() {
|
|
this.model.getPreferences().then(settings => {
|
|
this.preferences = settings.value || {}
|
|
})
|
|
}
|
|
|
|
savePreferences() {
|
|
this.model.setPreferences({
|
|
key: `${this.identity.uuid}:userPrefs`,
|
|
value: this.preferences
|
|
})
|
|
}
|
|
|
|
getPreference(path) {
|
|
let value = null;
|
|
let segments = path.split('.');
|
|
let pointer = this.preferences;
|
|
if(pointer) {
|
|
for(let segment of segments) {
|
|
if(pointer[segment]) {
|
|
if(typeof pointer[segment] == 'object') {
|
|
pointer = pointer[segment];
|
|
} else {
|
|
value = pointer[segment];
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
setPreference(path, value) {
|
|
const segments = path.split('.')
|
|
let pointer = this.preferences
|
|
|
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
const segment = segments[i]
|
|
if (!pointer[segment] || typeof pointer[segment] !== 'object') {
|
|
pointer[segment] = {}
|
|
}
|
|
pointer = pointer[segment]
|
|
}
|
|
|
|
const lastKey = segments.at(-1)
|
|
const existing = pointer[lastKey]
|
|
if ((typeof(value) == 'object') && (value !== null) && (typeof(existing) == 'object') && (existing !== null)) { // merge instead of overwrite
|
|
Object.assign(existing, value)
|
|
} else {
|
|
pointer[lastKey] = value
|
|
}
|
|
|
|
this.savePreferences()
|
|
}
|
|
|
|
|
|
}
|
|
|
|
app.registerClass('User', myUser, true); // for Sparc to use
|
|
app.registerClass('myUser', myUser, true); // Just to avoid double-loading if squeezed
|