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:
@@ -0,0 +1,119 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useCallback } from "react";
|
||||
import {
|
||||
getLDAPConfig,
|
||||
saveLDAPConfig,
|
||||
deleteLDAPConfig,
|
||||
testLDAPConfig,
|
||||
type LDAPConfig,
|
||||
type LDAPTestResult,
|
||||
} from "@/lib/api";
|
||||
|
||||
const defaultLDAPForm = (): 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: [],
|
||||
});
|
||||
|
||||
export function useLDAPConfig() {
|
||||
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>(defaultLDAPForm());
|
||||
const [ldapChangePassword, setLdapChangePassword] = useState(false);
|
||||
|
||||
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(defaultLDAPForm());
|
||||
setLdapTestResult(null);
|
||||
} catch (err: unknown) {
|
||||
setLdapError(err instanceof Error ? err.message : "Löschen fehlgeschlagen.");
|
||||
} finally {
|
||||
setLdapSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ldapConfig,
|
||||
ldapLoading,
|
||||
ldapSaving,
|
||||
ldapTesting,
|
||||
ldapError,
|
||||
ldapTestResult,
|
||||
ldapForm,
|
||||
setLdapForm,
|
||||
ldapChangePassword,
|
||||
setLdapChangePassword,
|
||||
loadLDAP,
|
||||
handleSaveLDAP,
|
||||
handleTestLDAP,
|
||||
handleDeleteLDAP,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useCallback } from "react";
|
||||
import {
|
||||
getTenantLDAPConfig,
|
||||
saveTenantLDAPConfig,
|
||||
deleteTenantLDAPConfig,
|
||||
testTenantLDAPConfig,
|
||||
type TenantLDAPConfig,
|
||||
type LDAPTestResult,
|
||||
} from "@/lib/api";
|
||||
|
||||
const defaultTenantLDAPForm = (): 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: [],
|
||||
});
|
||||
|
||||
export function useTenantLDAPConfig() {
|
||||
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>(defaultTenantLDAPForm());
|
||||
const [tenantLdapChangePassword, setTenantLdapChangePassword] = useState(false);
|
||||
|
||||
// Own tenant logo state (lives here because it's loaded together with tenant LDAP)
|
||||
const [ownLogoPreviewUrl, setOwnLogoPreviewUrl] = useState<string | null>(null);
|
||||
const [ownLogoUploading, setOwnLogoUploading] = useState(false);
|
||||
const [ownLogoError, setOwnLogoError] = useState("");
|
||||
|
||||
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(defaultTenantLDAPForm());
|
||||
setTenantLdapTestResult(null);
|
||||
} catch (err: unknown) {
|
||||
setTenantLdapError(err instanceof Error ? err.message : "Löschen fehlgeschlagen.");
|
||||
} finally {
|
||||
setTenantLdapSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tenantLdapConfig,
|
||||
tenantLdapLoading,
|
||||
tenantLdapSaving,
|
||||
tenantLdapTesting,
|
||||
tenantLdapError,
|
||||
tenantLdapTestResult,
|
||||
tenantLdapForm,
|
||||
setTenantLdapForm,
|
||||
tenantLdapChangePassword,
|
||||
setTenantLdapChangePassword,
|
||||
ownLogoPreviewUrl,
|
||||
setOwnLogoPreviewUrl,
|
||||
ownLogoUploading,
|
||||
setOwnLogoUploading,
|
||||
ownLogoError,
|
||||
setOwnLogoError,
|
||||
loadTenantLDAP,
|
||||
handleSaveTenantLDAP,
|
||||
handleTestTenantLDAP,
|
||||
handleDeleteTenantLDAP,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import {
|
||||
getTenantUsers,
|
||||
syncAdminTenantLDAP,
|
||||
type User,
|
||||
type Tenant,
|
||||
type LDAPSyncResult,
|
||||
} from "@/lib/api";
|
||||
|
||||
export function useTenantUsers() {
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tenantUsersDialogId,
|
||||
setTenantUsersDialogId,
|
||||
tenantUsersDialogName,
|
||||
tenantUsersDialogLdap,
|
||||
tenantUsers,
|
||||
tenantUsersLoading,
|
||||
tenantUsersError,
|
||||
tenantUsersSyncing,
|
||||
tenantUsersSyncResult,
|
||||
openUsersDialog,
|
||||
handleSyncLDAPUsers,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user