refactoring
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* User administration view.
|
||||
*
|
||||
* UserAdmin owns the user list, its editable controls and the new-user form.
|
||||
* The application remains responsible for permissions, routing, breadcrumbs
|
||||
* and making the surrounding view visible.
|
||||
*/
|
||||
|
||||
class UserAdmin {
|
||||
/**
|
||||
* goal : Connect the user administration controls to the wiki API.
|
||||
* pre : api performs authenticated requests; translate resolves UI keys;
|
||||
* the user administration form and list exist in the document.
|
||||
* post : Submitting the new-user form creates a user and reloads the list.
|
||||
* result : A directly usable controller for the user administration view.
|
||||
*/
|
||||
constructor(api, translate) {
|
||||
this.api = api;
|
||||
this.translate = translate;
|
||||
this.form = document.getElementById("new-user-form");
|
||||
this.list = document.getElementById("user-list");
|
||||
|
||||
this.form.addEventListener("submit", (event) => {
|
||||
this.#createUser(event).catch((error) => console.error(error));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* goal : Refresh the editable user list from the server.
|
||||
* pre : The current session has administrator permission.
|
||||
* post : Every current user has editable identity, role and password fields.
|
||||
* result : A promise that resolves when all rows have been rendered.
|
||||
* internals: The API supplies public user records. #renderUser creates each
|
||||
* row and connects its save and delete operations to that record.
|
||||
*/
|
||||
async load() {
|
||||
const result = await this.api("/api/admin/users");
|
||||
this.list.replaceChildren();
|
||||
for (const user of result.users) {
|
||||
this.list.append(this.#renderUser(user));
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a user from the dedicated form and reload the canonical list. */
|
||||
async #createUser(event) {
|
||||
event.preventDefault();
|
||||
const username = document.getElementById("new-username").value;
|
||||
await this.api("/api/admin/users", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
displayName: document.getElementById("new-display-name").value || username,
|
||||
email: document.getElementById("new-email").value,
|
||||
password: document.getElementById("new-password").value,
|
||||
role: document.getElementById("new-role").value,
|
||||
enabled: true
|
||||
})
|
||||
});
|
||||
this.form.reset();
|
||||
await this.load();
|
||||
}
|
||||
|
||||
/** Build one editable user row and connect its actions. */
|
||||
#renderUser(user) {
|
||||
const row = document.createElement("div");
|
||||
row.className = "user-row";
|
||||
|
||||
const username = document.createElement("strong");
|
||||
username.textContent = user.username;
|
||||
|
||||
const displayName = document.createElement("input");
|
||||
displayName.value = user.displayName;
|
||||
|
||||
const email = document.createElement("input");
|
||||
email.type = "email";
|
||||
email.value = user.email || "";
|
||||
email.placeholder = this.translate("email-address", "Email address");
|
||||
|
||||
const role = this.#roleSelect(user.role);
|
||||
|
||||
const enabled = document.createElement("input");
|
||||
enabled.type = "checkbox";
|
||||
enabled.checked = user.enabled;
|
||||
|
||||
const password = document.createElement("input");
|
||||
password.type = "password";
|
||||
password.placeholder = this.translate("new-password", "New password");
|
||||
password.autocomplete = "new-password";
|
||||
|
||||
const save = document.createElement("button");
|
||||
save.textContent = this.translate("save", "Save");
|
||||
save.addEventListener("click", () => {
|
||||
this.#updateUser(user, displayName, email, role, enabled, password)
|
||||
.catch((error) => console.error(error));
|
||||
});
|
||||
|
||||
const remove = document.createElement("button");
|
||||
remove.textContent = this.translate("delete", "Delete");
|
||||
remove.className = "danger";
|
||||
remove.addEventListener("click", () => {
|
||||
this.#deleteUser(user).catch((error) => console.error(error));
|
||||
});
|
||||
|
||||
const actions = document.createElement("div");
|
||||
actions.append(save, remove);
|
||||
row.append(username, displayName, email, role, enabled, password, actions);
|
||||
return row;
|
||||
}
|
||||
|
||||
/** Build the translated role selector for one user row. */
|
||||
#roleSelect(selectedRole) {
|
||||
const select = document.createElement("select");
|
||||
for (const roleName of ["reader", "editor", "admin"]) {
|
||||
const option = document.createElement("option");
|
||||
option.value = roleName;
|
||||
option.textContent = this.translate(`role-${roleName}`, roleName);
|
||||
option.selected = roleName === selectedRole;
|
||||
select.append(option);
|
||||
}
|
||||
return select;
|
||||
}
|
||||
|
||||
/** Store the current controls of one user row. */
|
||||
async #updateUser(user, displayName, email, role, enabled, password) {
|
||||
await this.api(`/api/admin/users/${user.id}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
displayName: displayName.value,
|
||||
email: email.value,
|
||||
role: role.value,
|
||||
enabled: enabled.checked,
|
||||
password: password.value || undefined
|
||||
})
|
||||
});
|
||||
password.value = "";
|
||||
}
|
||||
|
||||
/** Confirm and remove one user, then reload the canonical list. */
|
||||
async #deleteUser(user) {
|
||||
const question = this.translate("delete-user-confirm", "Delete user {username}?")
|
||||
.replace("{username}", user.username);
|
||||
if (!window.confirm(question)) return;
|
||||
await this.api(`/api/admin/users/${user.id}`, { method: "DELETE" });
|
||||
await this.load();
|
||||
}
|
||||
}
|
||||
|
||||
export { UserAdmin };
|
||||
Reference in New Issue
Block a user