chore: weitere Code-Aufteilung (api.ts, hooks, ldap_sync)
- src/lib/api.ts (1085 Zeilen) → 5 thematische Module unter src/lib/api/ (core, users, ldap, tenants, mail, system) + index.ts Re-Export - useLDAPConfig / useTenantLDAPConfig / useTenantUsers Hooks extrahiert; admin/page.tsx nutzt diese statt roher useState-Blöcke - handleSyncTenantLDAP, handleAdminSyncTenantLDAP, doSyncTenantLDAP, buildTenantTestConfig, syncResult aus ldap_tenants.go in ldap_sync.go verschoben Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+57
-256
@@ -2,6 +2,9 @@
|
||||
|
||||
import { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
import { useLDAPConfig } from "@/hooks/useLDAPConfig";
|
||||
import { useTenantLDAPConfig } from "@/hooks/useTenantLDAPConfig";
|
||||
import { useTenantUsers } from "@/hooks/useTenantUsers";
|
||||
import {
|
||||
getUsers,
|
||||
createUser,
|
||||
@@ -18,24 +21,13 @@ import {
|
||||
getUploadProgress,
|
||||
getSecurityAudit,
|
||||
fixSecurityIssue,
|
||||
getLDAPConfig,
|
||||
saveLDAPConfig,
|
||||
deleteLDAPConfig,
|
||||
testLDAPConfig,
|
||||
getTenants,
|
||||
getTenantUsers,
|
||||
createTenant,
|
||||
updateTenant,
|
||||
deleteTenant,
|
||||
getTenantDomains,
|
||||
addTenantDomain,
|
||||
removeTenantDomain,
|
||||
getTenantLDAPConfig,
|
||||
saveTenantLDAPConfig,
|
||||
deleteTenantLDAPConfig,
|
||||
testTenantLDAPConfig,
|
||||
syncAdminTenantLDAP,
|
||||
type LDAPSyncResult,
|
||||
getAdminLabels,
|
||||
createAdminLabel,
|
||||
deleteAdminLabel,
|
||||
@@ -55,9 +47,6 @@ import {
|
||||
type SystemStats,
|
||||
type UploadJob,
|
||||
type SecurityAuditResult,
|
||||
type LDAPConfig,
|
||||
type LDAPTestResult,
|
||||
type TenantLDAPConfig,
|
||||
type Tenant,
|
||||
type TenantDefaultUser,
|
||||
type TenantDomain,
|
||||
@@ -155,26 +144,23 @@ export default function AdminPage() {
|
||||
const [uploadLoading, setUploadLoading] = useState(false);
|
||||
const uploadPollRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
// LDAP state
|
||||
const [ldapConfig, setLdapConfig] = useState<LDAPConfig | null>(null);
|
||||
const [ldapLoading, setLdapLoading] = useState(false);
|
||||
const [ldapSaving, setLdapSaving] = useState(false);
|
||||
const [ldapTesting, setLdapTesting] = useState(false);
|
||||
const [ldapError, setLdapError] = useState("");
|
||||
const [ldapTestResult, setLdapTestResult] = useState<LDAPTestResult | null>(null);
|
||||
const [ldapForm, setLdapForm] = useState<LDAPConfig>({
|
||||
enabled: false,
|
||||
url: "ldap://",
|
||||
bind_dn: "",
|
||||
bind_password: "",
|
||||
base_dn: "",
|
||||
user_filter: "(sAMAccountName=%s)",
|
||||
tls: false,
|
||||
tls_skip_verify: false,
|
||||
default_role: "user",
|
||||
group_mappings: [],
|
||||
});
|
||||
const [ldapChangePassword, setLdapChangePassword] = useState(false);
|
||||
// LDAP state (global, superadmin) — managed by useLDAPConfig hook
|
||||
const {
|
||||
ldapConfig,
|
||||
ldapLoading,
|
||||
ldapSaving,
|
||||
ldapTesting,
|
||||
ldapError,
|
||||
ldapTestResult,
|
||||
ldapForm,
|
||||
setLdapForm,
|
||||
ldapChangePassword,
|
||||
setLdapChangePassword,
|
||||
loadLDAP,
|
||||
handleSaveLDAP,
|
||||
handleTestLDAP,
|
||||
handleDeleteLDAP,
|
||||
} = useLDAPConfig();
|
||||
|
||||
// Tenants state
|
||||
const [tenants, setTenants] = useState<Tenant[]>([]);
|
||||
@@ -197,26 +183,29 @@ export default function AdminPage() {
|
||||
const [addDomainLoading, setAddDomainLoading] = useState(false);
|
||||
const [domainError, setDomainError] = useState("");
|
||||
|
||||
// Tenant LDAP state (domain_admin own tenant)
|
||||
const [tenantLdapConfig, setTenantLdapConfig] = useState<TenantLDAPConfig | null>(null);
|
||||
const [tenantLdapLoading, setTenantLdapLoading] = useState(false);
|
||||
const [tenantLdapSaving, setTenantLdapSaving] = useState(false);
|
||||
const [tenantLdapTesting, setTenantLdapTesting] = useState(false);
|
||||
const [tenantLdapError, setTenantLdapError] = useState("");
|
||||
const [tenantLdapTestResult, setTenantLdapTestResult] = useState<LDAPTestResult | null>(null);
|
||||
const [tenantLdapForm, setTenantLdapForm] = useState<TenantLDAPConfig>({
|
||||
enabled: false,
|
||||
url: "ldap://",
|
||||
bind_dn: "",
|
||||
bind_password: "",
|
||||
base_dn: "",
|
||||
user_filter: "(sAMAccountName=%s)",
|
||||
tls: false,
|
||||
tls_skip_verify: false,
|
||||
default_role: "user",
|
||||
group_mappings: [],
|
||||
});
|
||||
const [tenantLdapChangePassword, setTenantLdapChangePassword] = useState(false);
|
||||
// Tenant LDAP state (domain_admin own tenant) — managed by useTenantLDAPConfig hook
|
||||
const {
|
||||
tenantLdapConfig,
|
||||
tenantLdapLoading,
|
||||
tenantLdapSaving,
|
||||
tenantLdapTesting,
|
||||
tenantLdapError,
|
||||
tenantLdapTestResult,
|
||||
tenantLdapForm,
|
||||
setTenantLdapForm,
|
||||
tenantLdapChangePassword,
|
||||
setTenantLdapChangePassword,
|
||||
ownLogoPreviewUrl,
|
||||
setOwnLogoPreviewUrl,
|
||||
ownLogoUploading,
|
||||
setOwnLogoUploading,
|
||||
ownLogoError,
|
||||
setOwnLogoError,
|
||||
loadTenantLDAP,
|
||||
handleSaveTenantLDAP,
|
||||
handleTestTenantLDAP,
|
||||
handleDeleteTenantLDAP,
|
||||
} = useTenantLDAPConfig();
|
||||
|
||||
// Superadmin: tenant LDAP dialog
|
||||
const [tenantLdapDialogId, setTenantLdapDialogId] = useState<number | null>(null);
|
||||
@@ -227,20 +216,20 @@ export default function AdminPage() {
|
||||
const [logoUploading, setLogoUploading] = useState(false);
|
||||
const [logoError, setLogoError] = useState("");
|
||||
|
||||
// Logo for domain_admin own tenant
|
||||
const [ownLogoPreviewUrl, setOwnLogoPreviewUrl] = useState<string | null>(null);
|
||||
const [ownLogoUploading, setOwnLogoUploading] = useState(false);
|
||||
const [ownLogoError, setOwnLogoError] = useState("");
|
||||
|
||||
// Tenant users dialog
|
||||
const [tenantUsersDialogId, setTenantUsersDialogId] = useState<number | null>(null);
|
||||
const [tenantUsersDialogName, setTenantUsersDialogName] = useState("");
|
||||
const [tenantUsersDialogLdap, setTenantUsersDialogLdap] = useState(false);
|
||||
const [tenantUsers, setTenantUsers] = useState<User[]>([]);
|
||||
const [tenantUsersLoading, setTenantUsersLoading] = useState(false);
|
||||
const [tenantUsersError, setTenantUsersError] = useState("");
|
||||
const [tenantUsersSyncing, setTenantUsersSyncing] = useState(false);
|
||||
const [tenantUsersSyncResult, setTenantUsersSyncResult] = useState<LDAPSyncResult | null>(null);
|
||||
// Tenant users dialog — managed by useTenantUsers hook
|
||||
const {
|
||||
tenantUsersDialogId,
|
||||
setTenantUsersDialogId,
|
||||
tenantUsersDialogName,
|
||||
tenantUsersDialogLdap,
|
||||
tenantUsers,
|
||||
tenantUsersLoading,
|
||||
tenantUsersError,
|
||||
tenantUsersSyncing,
|
||||
tenantUsersSyncResult,
|
||||
openUsersDialog,
|
||||
handleSyncLDAPUsers,
|
||||
} = useTenantUsers();
|
||||
|
||||
// Labels state
|
||||
const [adminLabels, setAdminLabels] = useState<MailLabel[]>([]);
|
||||
@@ -528,78 +517,6 @@ export default function AdminPage() {
|
||||
}
|
||||
}
|
||||
|
||||
// LDAP handlers
|
||||
const loadLDAP = useCallback(async () => {
|
||||
setLdapLoading(true);
|
||||
setLdapError("");
|
||||
try {
|
||||
const cfg = await getLDAPConfig();
|
||||
if (cfg) {
|
||||
setLdapConfig(cfg);
|
||||
setLdapForm({ ...cfg, bind_password: "" });
|
||||
setLdapChangePassword(false);
|
||||
}
|
||||
} catch {
|
||||
setLdapError("LDAP-Konfiguration konnte nicht geladen werden.");
|
||||
} finally {
|
||||
setLdapLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
async function handleSaveLDAP(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setLdapSaving(true);
|
||||
setLdapError("");
|
||||
try {
|
||||
const payload: Partial<LDAPConfig> = { ...ldapForm };
|
||||
if (!ldapChangePassword) {
|
||||
delete payload.bind_password;
|
||||
}
|
||||
await saveLDAPConfig(payload);
|
||||
await loadLDAP();
|
||||
} catch (err: unknown) {
|
||||
setLdapError(err instanceof Error ? err.message : "Speichern fehlgeschlagen.");
|
||||
} finally {
|
||||
setLdapSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTestLDAP() {
|
||||
setLdapTesting(true);
|
||||
setLdapError("");
|
||||
setLdapTestResult(null);
|
||||
try {
|
||||
const payload = ldapConfig
|
||||
? { use_saved: true }
|
||||
: { use_saved: false, ...ldapForm };
|
||||
const result = await testLDAPConfig(payload as Parameters<typeof testLDAPConfig>[0]);
|
||||
setLdapTestResult(result);
|
||||
} catch (err: unknown) {
|
||||
setLdapError(err instanceof Error ? err.message : "Test fehlgeschlagen.");
|
||||
} finally {
|
||||
setLdapTesting(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDeleteLDAP() {
|
||||
setLdapSaving(true);
|
||||
setLdapError("");
|
||||
try {
|
||||
await deleteLDAPConfig();
|
||||
setLdapConfig(null);
|
||||
setLdapForm({
|
||||
enabled: false, url: "ldap://", bind_dn: "", bind_password: "",
|
||||
base_dn: "", user_filter: "(sAMAccountName=%s)", tls: false,
|
||||
tls_skip_verify: false, default_role: "user", group_mappings: [],
|
||||
});
|
||||
setLdapTestResult(null);
|
||||
} catch (err: unknown) {
|
||||
setLdapError(err instanceof Error ? err.message : "Löschen fehlgeschlagen.");
|
||||
} finally {
|
||||
setLdapSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Tenants handlers
|
||||
const loadTenants = useCallback(async () => {
|
||||
setTenantsLoading(true);
|
||||
@@ -747,40 +664,6 @@ export default function AdminPage() {
|
||||
finally { setDomainsLoading(false); }
|
||||
}
|
||||
|
||||
async function openUsersDialog(t: Tenant) {
|
||||
setTenantUsersDialogId(t.id);
|
||||
setTenantUsersDialogName(t.name);
|
||||
setTenantUsersDialogLdap(t.ldap_enabled === true);
|
||||
setTenantUsersLoading(true);
|
||||
setTenantUsers([]);
|
||||
setTenantUsersError("");
|
||||
setTenantUsersSyncResult(null);
|
||||
try {
|
||||
const users = await getTenantUsers(t.id);
|
||||
setTenantUsers(users || []);
|
||||
} catch (err: unknown) {
|
||||
setTenantUsersError(err instanceof Error ? err.message : "Nutzer konnten nicht geladen werden.");
|
||||
} finally {
|
||||
setTenantUsersLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSyncLDAPUsers() {
|
||||
if (!tenantUsersDialogId) return;
|
||||
setTenantUsersSyncing(true);
|
||||
setTenantUsersSyncResult(null);
|
||||
try {
|
||||
const result = await syncAdminTenantLDAP(tenantUsersDialogId);
|
||||
setTenantUsersSyncResult(result);
|
||||
const users = await getTenantUsers(tenantUsersDialogId);
|
||||
setTenantUsers(users || []);
|
||||
} catch (err: unknown) {
|
||||
setTenantUsersSyncResult({ synced: 0, errors: [err instanceof Error ? err.message : "Sync fehlgeschlagen"] });
|
||||
} finally {
|
||||
setTenantUsersSyncing(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAddDomain() {
|
||||
if (!domainDialogTenant || !newDomain) return;
|
||||
setAddDomainLoading(true);
|
||||
@@ -892,88 +775,6 @@ export default function AdminPage() {
|
||||
}
|
||||
}
|
||||
|
||||
// Tenant LDAP handlers (domain_admin)
|
||||
const loadTenantLDAP = useCallback(async () => {
|
||||
setTenantLdapLoading(true);
|
||||
setTenantLdapError("");
|
||||
try {
|
||||
const cfg = await getTenantLDAPConfig();
|
||||
if (cfg) {
|
||||
setTenantLdapConfig(cfg);
|
||||
setTenantLdapForm({ ...cfg, bind_password: "" });
|
||||
setTenantLdapChangePassword(false);
|
||||
}
|
||||
} catch {
|
||||
setTenantLdapError("LDAP-Konfiguration konnte nicht geladen werden.");
|
||||
} finally {
|
||||
setTenantLdapLoading(false);
|
||||
}
|
||||
// Load own tenant logo preview
|
||||
try {
|
||||
const res = await fetch("/api/tenant/logo", { credentials: "include" });
|
||||
if (res.ok) {
|
||||
const blob = await res.blob();
|
||||
setOwnLogoPreviewUrl(URL.createObjectURL(blob));
|
||||
}
|
||||
} catch {
|
||||
// no logo or not available
|
||||
}
|
||||
}, []);
|
||||
|
||||
async function handleSaveTenantLDAP(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setTenantLdapSaving(true);
|
||||
setTenantLdapError("");
|
||||
try {
|
||||
const payload: Partial<TenantLDAPConfig> = { ...tenantLdapForm };
|
||||
if (!tenantLdapChangePassword) {
|
||||
delete payload.bind_password;
|
||||
}
|
||||
await saveTenantLDAPConfig(payload);
|
||||
await loadTenantLDAP();
|
||||
} catch (err: unknown) {
|
||||
setTenantLdapError(err instanceof Error ? err.message : "Speichern fehlgeschlagen.");
|
||||
} finally {
|
||||
setTenantLdapSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTestTenantLDAP() {
|
||||
setTenantLdapTesting(true);
|
||||
setTenantLdapError("");
|
||||
setTenantLdapTestResult(null);
|
||||
try {
|
||||
const payload = tenantLdapConfig
|
||||
? { use_saved: true }
|
||||
: { use_saved: false, ...tenantLdapForm };
|
||||
const result = await testTenantLDAPConfig(payload as Parameters<typeof testTenantLDAPConfig>[0]);
|
||||
setTenantLdapTestResult(result);
|
||||
} catch (err: unknown) {
|
||||
setTenantLdapError(err instanceof Error ? err.message : "Test fehlgeschlagen.");
|
||||
} finally {
|
||||
setTenantLdapTesting(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDeleteTenantLDAP() {
|
||||
setTenantLdapSaving(true);
|
||||
setTenantLdapError("");
|
||||
try {
|
||||
await deleteTenantLDAPConfig();
|
||||
setTenantLdapConfig(null);
|
||||
setTenantLdapForm({
|
||||
enabled: false, url: "ldap://", bind_dn: "", bind_password: "",
|
||||
base_dn: "", user_filter: "(sAMAccountName=%s)", tls: false,
|
||||
tls_skip_verify: false, default_role: "user", group_mappings: [],
|
||||
});
|
||||
setTenantLdapTestResult(null);
|
||||
} catch (err: unknown) {
|
||||
setTenantLdapError(err instanceof Error ? err.message : "Löschen fehlgeschlagen.");
|
||||
} finally {
|
||||
setTenantLdapSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Navbar username={user?.username ?? ""} role={user?.role ?? ""} />
|
||||
|
||||
Reference in New Issue
Block a user