manageable-users/Public/scripts/manage.js

407 lines
16 KiB
JavaScript

async function loadData (block) {
const source = block.dataset.source;
block.classList.remove ("loaded");
try {
const response = await fetch (source);
if (response.ok) {
const items = await response.json();
var itemLoaders = [];
if (Array.isArray (items)) {
const template = block.querySelector ("template");
const tableBody = block.querySelector ("table tbody");
tableBody.innerHTML = "";
items.forEach (item => {
const clone = template.content.cloneNode (true);
const loader = window["populate" + block.dataset.item] (clone, item);
if (loader != null) {
itemLoaders.push (loader);
}
tableBody.appendChild (clone);
tableBody.lastElementChild.dataset.itemid = item.id;
});
} else {
const loader = window["populate" + block.dataset.item] (block, items);
if (loader != null) {
itemLoaders.push (loader);
}
}
block.classList.add ("loaded");
for (const loader of itemLoaders) {
await loader();
}
} else {
if ((response.status == 401) || (response.status == 403)) {
document.location.href = document.body.dataset.baseurl;
} else {
block.classList.add ("failed");
}
}
} catch (error) {
block.classList.add ("failed");
}
}
function populateUser (row, user) {
row.querySelector (".email").innerText = user.email;
row.querySelector (".fullname").innerText = user.fullName;
row.querySelector (".roles").innerText = user.roles.join (", ");
row.querySelector (".active").innerText = user.isActive ? "✓" : "";
}
async function displayUser (container, dialog, userUrl) {
dialog.querySelectorAll (".error")
.forEach (element => {
element.hidden = true;
});
const response = await fetch (userUrl);
if (response.ok) {
const user = await response.json();
dialog.querySelector ("input[name=userid]").value = user.id;
dialog.querySelector ("input[name=email]").value = user.email;
dialog.querySelector ("input[name=fullname]").value = user.fullName;
dialog.querySelector ("input[name=active]").checked = user.isActive;
dialog.querySelectorAll ("input.role")
.forEach (checkbox => {
checkbox.checked = user.roles.includes (checkbox.value);
});
container.classList.add ("loaded");
} else {
if ((response.status == 401) || (response.status == 403)) {
document.location.href = document.body.dataset.baseurl;
} else {
container.classList.add ("failed");
}
}
}
function emptyUser (dialog) {
dialog.querySelector ("input[name=email]").value = null;
dialog.querySelector ("input[name=fullname]").value = null;
dialog.querySelectorAll ("input[name=role]")
.forEach (checkbox => {
checkbox.checked = false;
});
dialog.querySelectorAll (".error")
.forEach (element => {
element.hidden = true;
});
dialog.querySelector ("button.invite").disabled = false;
}
function selectUser (event) {
const row = event.target.closest ("tbody tr");
if (row && this.contains (row)) {
const dialog = document.querySelector (this.dataset.dialog);
window["display" + this.dataset.item] (this, dialog, this.dataset.source + "/" + row.dataset.itemid);
dialog.showModal();
dialog.querySelector ("input[name=email]").focus();
} else if (event.target.classList.contains ("new")) {
const dialog = document.querySelector (event.target.dataset.dialog);
window["empty" + this.dataset.item] (dialog);
dialog.showModal();
dialog.querySelector ("input[name=email]").focus();
}
}
async function saveUser (event) {
event.preventDefault();
const dialog = event.target.closest ("dialog");
if (event.submitter.classList.contains ("save")) {
const userId = event.target.querySelector ("input[name=userid]").value;
const email = event.target.querySelector ("input[name=email]").value;
const fullname = event.target.querySelector ("input[name=fullname]").value;
const isActive = event.target.querySelector ("input[name=active]").checked;
const roles = Array.from (event.target.querySelectorAll ("input[name=role]:checked")).map (checkbox => { return checkbox.value });
let valid = true;
if (email) {
dialog.querySelector (".error[for=email]").hidden = true;
} else {
dialog.querySelector (".error[for=email]").hidden = false;
valid = false;
}
if (fullname) {
dialog.querySelector (".error[for=fullname]").hidden = true;
} else {
dialog.querySelector (".error[for=fullname]").hidden = false;
valid = false;
}
if (valid) {
event.target.querySelector ("button.save").disabled = true;
try {
const url = dialog.dataset.saveUrl + "/" + userId;
const response = await fetch (url,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify ({email: email, fullname: fullname, isActive: isActive, roles: roles})
});
if (response.ok) {
dialog.close();
event.target.querySelector ("button.save").disabled = false;
loadData (document.querySelector (".users.loading"));
return true;
} else {
console.error (url + " returned " + response.status);
dialog.querySelector (".error#failure").hidden = false;
dialog.querySelector ("button.save").disabled = false;
if ((response.status == 401) || (response.status == 403)) {
document.location.href = document.body.dataset.baseurl;
}
return true;
}
} catch (error) {
console.error (error);
dialog.querySelector (".error#failure").hidden = false;
dialog.querySelector ("button.save").disabled = false;
}
} else {
return false;
}
} else {
dialog.close();
}
}
async function inviteUser (event) {
event.preventDefault();
const dialog = event.target.closest ("dialog");
if (event.submitter.classList.contains ("invite")) {
const email = event.target.querySelector ("input[name=email]").value;
const fullname = event.target.querySelector ("input[name=fullname").value;
const roles = Array.from (event.target.querySelectorAll ("input[name=role]:checked")).map (checkbox => { return checkbox.value });
let valid = true;
if (email) {
dialog.querySelector (".error[for=email]").hidden = true;
} else {
dialog.querySelector (".error[for=email]").hidden = false;
valid = false;
}
if (fullname) {
dialog.querySelector (".error[for=fullname]").hidden = true;
} else {
dialog.querySelector (".error[for=fullname]").hidden = false;
valid = false;
}
if (valid) {
event.target.querySelector ("button.invite").disabled = true;
try {
const url = dialog.dataset.inviteUrl;
const response = await fetch (url,
{
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify ({email: email, fullname: fullname, roles: roles})
});
if (response.ok) {
dialog.close();
event.target.querySelector ("button.invite").disabled = false;
loadData (document.querySelector (".users.loading"));
return true;
} else {
console.error (url + " returned " + response.status);
dialog.querySelector (".error#failure").hidden = false;
dialog.querySelector ("button.invite").disabled = false;
if ((response.status == 401) || (response.status == 403)) {
document.location.href = document.body.dataset.baseurl;
}
return true;
}
} catch (error) {
console.error (error);
dialog.querySelector (".error#failure").hidden = false;
dialog.querySelector ("button.invite").disabled = false;
}
} else {
return false;
}
} else {
dialog.close();
}
}
function populatePassword (container, token) {
container.querySelector (".email").innerText = token.email;
container.querySelector ("button.save").disabled = false;
container.querySelector (".invalidPassword").hidden = true;
}
async function savePassword (event) {
event.preventDefault();
if (event.submitter.classList.contains ("save")) {
const password = event.target.querySelector ("input[name=password]").value;
const saveUrl = event.target.dataset.saveUrl;
const loginUrl = event.target.dataset.loginUrl;
if (password && (password.length >= 12)) {
try {
event.target.querySelector ("button.save").disabled = true;
event.target.querySelector (".invalidPassword").hidden = true;
const response = await fetch (saveUrl,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify ({password: password})
});
if (response.ok) {
document.location.href = loginUrl;
return true;
} else {
console.error (saveUrl + " returned " + response.status);
event.target.querySelector (".error#failure").hidden = false;
event.target.querySelector ("button.save").disabled = false;
return false;
}
} catch (error) {
console.error (saveUrl + " returned " + error);
event.target.querySelector (".error#failure").hidden = false;
event.target.querySelector ("button.save").disabled = false;
}
} else {
event.target.querySelector (".invalidPassword").hidden = false;
return false;
}
} else {
dialog.close();
}
}
async function login (event) {
event.preventDefault();
const email = event.target.querySelector ("input[name=email]").value;
const password = event.target.querySelector ("input[name=password]").value;
const loginUrl = event.target.dataset.loginUrl;
if (email && password) {
try {
event.target.querySelector ("button#login").disabled = true;
event.target.querySelector (".error#failure").hidden = true;
event.target.querySelector (".invalidEmail").hidden = true;
event.target.querySelector (".invalidPassword").hidden = true;
const response = await fetch (loginUrl,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify ({email: email, password: password})
});
if (response.ok) {
event.target.querySelector ("button#login").disabled = false;
document.location.href = document.body.dataset.baseurl;
return true;
} else {
console.error (loginUrl + " returned " + response.status);
event.target.querySelector (".error#failure").hidden = false;
event.target.querySelector ("button#login").disabled = false;
return false;
}
} catch (error) {
console.error (loginUrl + " returned " + error);
event.target.querySelector (".error#failure").hidden = false;
event.target.querySelector ("button#login").disabled = false;
}
return true;
} else {
event.target.querySelector (".invalidEmail").hidden = email;
event.target.querySelector (".invalidPassword").hidden = password;
return false;
}
}
function showForgotPassword (event) {
event.preventDefault();
document.querySelector ("form#login").hidden = true;
document.querySelector ("form#forgot").hidden = false;
}
async function submitForgotPassword (event) {
event.preventDefault();
const email = event.target.querySelector ("input[name=email]").value;
const resetUrl = event.target.dataset.resetUrl;
if (email) {
try {
event.target.querySelector ("button#reset-password").disabled = true;
const response = await fetch (resetUrl,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify ({email: email})
});
if (response.ok) {
document.querySelector ("form#forgot").hidden = true;
document.querySelector ("div#reset-info").hidden = false;
return true;
} else {
console.error (saveUrl + " returned " + response.status);
event.target.querySelector (".error#failure").hidden = false;
event.target.querySelector ("button#reset-password").disabled = false;
return false;
}
} catch (error) {
console.error (saveUrl + " returned " + error);
event.target.querySelector (".error#failure").hidden = false;
event.target.querySelector ("button#reset-password").disabled = false;
}
} else {
event.target.querySelector (".invalidEmail").hidden = false;
return false;
}
}
function setupGlobalEnvironment() {
document.querySelectorAll (".loading")
.forEach (function (block) {
loadData (block);
block.addEventListener ("click", window["select" + block.dataset.item]);
});
document.querySelectorAll ("form#login")
.forEach (function (form) {
form.addEventListener ("submit", login);
});
document.querySelectorAll ("button#forgot-password")
.forEach (function (button) {
button.addEventListener ("click", showForgotPassword);
});
document.querySelectorAll ("form#forgot")
.forEach (function (form) {
form.addEventListener ("submit", submitForgotPassword);
});
}
document.addEventListener ("DOMContentLoaded", setupGlobalEnvironment);