Add sysadmin settings

This commit is contained in:
2026-01-09 21:42:18 +01:00
parent e8b9c31688
commit 2b08baf375
3 changed files with 54 additions and 13 deletions

View File

@@ -2,14 +2,16 @@ package dev.kruhlmann.imgfloat.service;
import dev.kruhlmann.imgfloat.model.SystemAdministrator; import dev.kruhlmann.imgfloat.model.SystemAdministrator;
import dev.kruhlmann.imgfloat.repository.SystemAdministratorRepository; import dev.kruhlmann.imgfloat.repository.SystemAdministratorRepository;
import jakarta.annotation.PostConstruct;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.context.event.EventListener;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class SystemAdministratorService { public class SystemAdministratorService {
@@ -27,8 +29,13 @@ public class SystemAdministratorService {
this.environment = environment; this.environment = environment;
} }
@PostConstruct @EventListener(ApplicationReadyEvent.class)
public void initDefaults() { public void initDefaults() {
initDefaultsInTransaction();
}
@Transactional
void initDefaultsInTransaction() {
if ( if (
Boolean.parseBoolean( Boolean.parseBoolean(
environment.getProperty("org.springframework.boot.test.context.SpringBootTestContextBootstrapper") environment.getProperty("org.springframework.boot.test.context.SpringBootTestContextBootstrapper")

View File

@@ -2014,6 +2014,17 @@ button:disabled:hover {
font-weight: 700; font-weight: 700;
} }
.sysadmin-title-row {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.sysadmin-badge {
font-size: 12px;
}
.identity-row { .identity-row {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -151,17 +151,46 @@ function renderSystemAdministrators(admins) {
} }
admins.forEach((admin) => { admins.forEach((admin) => {
const normalizedAdmin = admin?.trim().toLowerCase();
const isInitialSysadmin = initialSysadmin && normalizedAdmin === initialSysadmin;
const listItem = document.createElement("li"); const listItem = document.createElement("li");
listItem.classList.add("stacked-list-item"); listItem.classList.add("stacked-list-item");
const text = document.createElement("div"); const text = document.createElement("div");
text.innerHTML = `<p class="list-title">${admin}</p><p class="muted">System admin access</p>`; const titleRow = document.createElement("div");
titleRow.classList.add("sysadmin-title-row");
const title = document.createElement("p");
title.classList.add("list-title");
title.textContent = admin;
titleRow.appendChild(title);
if (isInitialSysadmin) {
const badge = document.createElement("span");
badge.classList.add("chip", "subtle", "sysadmin-badge");
badge.textContent = "Initial system admin";
titleRow.appendChild(badge);
}
const subtitle = document.createElement("p");
subtitle.classList.add("muted");
subtitle.textContent = "System admin access";
text.appendChild(titleRow);
text.appendChild(subtitle);
const button = document.createElement("button"); const button = document.createElement("button");
button.classList.add("button", "secondary"); button.classList.add("button", "secondary");
button.type = "button"; button.type = "button";
button.textContent = "Remove"; button.textContent = "Remove";
button.addEventListener("click", () => removeSystemAdministrator(admin)); button.addEventListener("click", () => removeSystemAdministrator(admin));
button.setAttribute("data-sysadmin-remove", "true");
button.setAttribute("data-sysadmin-username", admin);
if (isInitialSysadmin) {
button.disabled = true;
button.title = "The initial system administrator cannot be removed.";
}
listItem.appendChild(text); listItem.appendChild(text);
listItem.appendChild(button); listItem.appendChild(button);
@@ -215,6 +244,10 @@ function addSystemAdministrator() {
} }
function removeSystemAdministrator(username) { function removeSystemAdministrator(username) {
if (initialSysadmin && username.trim().toLowerCase() === initialSysadmin) {
showToast("The initial system administrator cannot be removed.", "warning");
return;
}
fetch(`/api/system-administrators/${encodeURIComponent(username)}`, { method: "DELETE" }) fetch(`/api/system-administrators/${encodeURIComponent(username)}`, { method: "DELETE" })
.then((r) => { .then((r) => {
if (!r.ok) { if (!r.ok) {
@@ -258,13 +291,3 @@ setFormSettings(currentSettings);
updateStatCards(currentSettings); updateStatCards(currentSettings);
updateSubmitButtonDisabledState(); updateSubmitButtonDisabledState();
loadSystemAdministrators(); loadSystemAdministrators();
if (initialSysadmin) {
document.querySelectorAll("[data-sysadmin-remove]").forEach((button) => {
const username = button.getAttribute("data-sysadmin-username");
if (username && username.trim().toLowerCase() === initialSysadmin) {
button.disabled = true;
button.title = "The initial system administrator cannot be removed.";
}
});
}