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,206 @@
|
||||
import { API_BASE, request } from "./core";
|
||||
import { User } from "./users";
|
||||
import { LDAPConfig, LDAPTestResult } from "./ldap";
|
||||
|
||||
// ── Types ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface Tenant {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
active: boolean;
|
||||
created_at: string;
|
||||
domain_count?: number;
|
||||
user_count?: number;
|
||||
ldap_enabled?: boolean;
|
||||
ldap_url?: string;
|
||||
has_logo?: boolean;
|
||||
}
|
||||
|
||||
export interface TenantDomain {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
domain: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface TenantDefaultUser {
|
||||
username: string;
|
||||
password: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
export interface CreateTenantResponse extends Tenant {
|
||||
default_users: TenantDefaultUser[];
|
||||
}
|
||||
|
||||
export interface TenantLDAPConfig extends LDAPConfig {
|
||||
tenant_id?: number;
|
||||
}
|
||||
|
||||
export interface LDAPSyncResult {
|
||||
synced: number;
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
// ── Tenant CRUD ───────────────────────────────────────────────────────────────
|
||||
|
||||
export async function getTenants(): Promise<Tenant[]> {
|
||||
return request<Tenant[]>("/api/tenants");
|
||||
}
|
||||
|
||||
export async function getTenantUsers(tenantId: number): Promise<User[]> {
|
||||
return request<User[]>(`/api/tenants/${tenantId}/users`);
|
||||
}
|
||||
|
||||
export async function createTenant(name: string, slug: string): Promise<CreateTenantResponse> {
|
||||
return request<CreateTenantResponse>("/api/tenants", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name, slug }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateTenant(
|
||||
id: number,
|
||||
data: { name?: string; active?: boolean }
|
||||
): Promise<Tenant> {
|
||||
return request<Tenant>(`/api/tenants/${id}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteTenant(id: number): Promise<void> {
|
||||
await request<void>(`/api/tenants/${id}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
// ── Tenant Domains ────────────────────────────────────────────────────────────
|
||||
|
||||
export async function getTenantDomains(id: number): Promise<TenantDomain[]> {
|
||||
return request<TenantDomain[]>(`/api/tenants/${id}/domains`);
|
||||
}
|
||||
|
||||
export async function addTenantDomain(
|
||||
tenantId: number,
|
||||
domain: string
|
||||
): Promise<TenantDomain> {
|
||||
return request<TenantDomain>(`/api/tenants/${tenantId}/domains`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ domain }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function removeTenantDomain(
|
||||
tenantId: number,
|
||||
domainId: number
|
||||
): Promise<void> {
|
||||
await request<void>(`/api/tenants/${tenantId}/domains/${domainId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
// ── Tenant Logo ───────────────────────────────────────────────────────────────
|
||||
|
||||
export function getTenantLogoUrl(tenantId: number): string {
|
||||
return `${API_BASE}/api/tenants/${tenantId}/logo`;
|
||||
}
|
||||
|
||||
export async function uploadTenantLogo(tenantId: number, file: File): Promise<void> {
|
||||
const form = new FormData();
|
||||
form.append("logo", file);
|
||||
const res = await fetch(`${API_BASE}/api/tenants/${tenantId}/logo`, {
|
||||
method: "POST",
|
||||
body: form,
|
||||
credentials: "include",
|
||||
});
|
||||
if (!res.ok) {
|
||||
const body = await res.text();
|
||||
throw new Error(body || `Upload failed: ${res.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteTenantLogo(tenantId: number): Promise<void> {
|
||||
await request<void>(`/api/tenants/${tenantId}/logo`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
// domain_admin: own tenant logo
|
||||
export async function uploadMyTenantLogo(file: File): Promise<void> {
|
||||
const form = new FormData();
|
||||
form.append("logo", file);
|
||||
const res = await fetch(`${API_BASE}/api/tenant/logo`, {
|
||||
method: "POST",
|
||||
body: form,
|
||||
credentials: "include",
|
||||
});
|
||||
if (!res.ok) {
|
||||
const body = await res.text();
|
||||
throw new Error(body || `Upload failed: ${res.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteMyTenantLogo(): Promise<void> {
|
||||
await request<void>("/api/tenant/logo", { method: "DELETE" });
|
||||
}
|
||||
|
||||
// ── Per-Tenant LDAP (domain_admin: own tenant) ────────────────────────────────
|
||||
|
||||
export async function getTenantLDAPConfig(): Promise<TenantLDAPConfig | null> {
|
||||
try {
|
||||
return await request<TenantLDAPConfig>("/api/tenant/ldap");
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error && e.message.includes("404")) return null;
|
||||
if (e instanceof Error && e.message.includes("no ldap config")) return null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveTenantLDAPConfig(cfg: Partial<TenantLDAPConfig>): Promise<void> {
|
||||
await request<void>("/api/tenant/ldap", { method: "PUT", body: JSON.stringify(cfg) });
|
||||
}
|
||||
|
||||
export async function deleteTenantLDAPConfig(): Promise<void> {
|
||||
await request<void>("/api/tenant/ldap", { method: "DELETE" });
|
||||
}
|
||||
|
||||
export async function testTenantLDAPConfig(
|
||||
payload: { use_saved: boolean } & Partial<TenantLDAPConfig>
|
||||
): Promise<LDAPTestResult> {
|
||||
return request<LDAPTestResult>("/api/tenant/ldap/test", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
// ── Per-Tenant LDAP (superadmin: arbitrary tenant) ────────────────────────────
|
||||
|
||||
export async function getAdminTenantLDAPConfig(tenantID: number): Promise<TenantLDAPConfig | null> {
|
||||
try {
|
||||
return await request<TenantLDAPConfig>(`/api/admin/tenants/${tenantID}/ldap`);
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error && e.message.includes("404")) return null;
|
||||
if (e instanceof Error && e.message.includes("no ldap config")) return null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveAdminTenantLDAPConfig(tenantID: number, cfg: Partial<TenantLDAPConfig>): Promise<void> {
|
||||
await request<void>(`/api/admin/tenants/${tenantID}/ldap`, { method: "PUT", body: JSON.stringify(cfg) });
|
||||
}
|
||||
|
||||
export async function deleteAdminTenantLDAPConfig(tenantID: number): Promise<void> {
|
||||
await request<void>(`/api/admin/tenants/${tenantID}/ldap`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
export async function testAdminTenantLDAPConfig(
|
||||
tenantID: number,
|
||||
payload: { use_saved: boolean } & Partial<TenantLDAPConfig>
|
||||
): Promise<LDAPTestResult> {
|
||||
return request<LDAPTestResult>(`/api/admin/tenants/${tenantID}/ldap/test`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function syncAdminTenantLDAP(tenantID: number): Promise<LDAPSyncResult> {
|
||||
return request<LDAPSyncResult>(`/api/admin/tenants/${tenantID}/ldap/sync`, { method: "POST", body: "{}" });
|
||||
}
|
||||
Reference in New Issue
Block a user