feat(PROJ-24): Mandanten-Logo Upload
- DB: logo_data (BYTEA) + logo_content_type Spalten in tenants-Tabelle - Backend: SetLogo/GetLogo/DeleteLogo im tenantstore - API: Logo-Endpunkte für superadmin (beliebiger Mandant) und domain_admin (eigener Mandant), max. 2 MB, PNG/JPEG/GIF/WebP/SVG - Frontend: Logo-Dialog in Mandantentabelle (superadmin), Logo-Upload-Sektion im LDAP-Tab (domain_admin) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+56
-2
@@ -693,6 +693,7 @@ export interface Tenant {
|
||||
user_count?: number;
|
||||
ldap_enabled?: boolean;
|
||||
ldap_url?: string;
|
||||
has_logo?: boolean;
|
||||
}
|
||||
|
||||
export interface TenantDomain {
|
||||
@@ -710,8 +711,18 @@ export async function getTenantUsers(tenantId: number): Promise<User[]> {
|
||||
return request<User[]>(`/api/tenants/${tenantId}/users`);
|
||||
}
|
||||
|
||||
export async function createTenant(name: string, slug: string): Promise<Tenant> {
|
||||
return request<Tenant>("/api/tenants", {
|
||||
export interface TenantDefaultUser {
|
||||
username: string;
|
||||
password: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
export interface CreateTenantResponse extends Tenant {
|
||||
default_users: TenantDefaultUser[];
|
||||
}
|
||||
|
||||
export async function createTenant(name: string, slug: string): Promise<CreateTenantResponse> {
|
||||
return request<CreateTenantResponse>("/api/tenants", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name, slug }),
|
||||
});
|
||||
@@ -754,6 +765,49 @@ export async function removeTenantDomain(
|
||||
});
|
||||
}
|
||||
|
||||
// ── 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" });
|
||||
}
|
||||
|
||||
// ── PROJ-23: Pro-Mandant LDAP (tenant_ldap) ──────────────────────────────
|
||||
|
||||
export interface TenantLDAPConfig extends LDAPConfig {
|
||||
|
||||
Reference in New Issue
Block a user