fix: IMAP-Serveradresse dynamisch aus Backend laden
Hardcodierte 192.168.1.131 in settings/page.tsx ersetzt durch
dynamischen API-Call GET /api/system/info → {fqdn, imap_port}.
Fallback auf window.location.hostname wenn API nicht antwortet.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -191,6 +191,7 @@ func (s *Server) routes() {
|
|||||||
s.mux.HandleFunc("GET /api/health", s.handleHealth)
|
s.mux.HandleFunc("GET /api/health", s.handleHealth)
|
||||||
s.mux.HandleFunc("GET /metrics", s.handleMetrics)
|
s.mux.HandleFunc("GET /metrics", s.handleMetrics)
|
||||||
s.mux.HandleFunc("GET /api/version", s.handleVersion)
|
s.mux.HandleFunc("GET /api/version", s.handleVersion)
|
||||||
|
s.mux.HandleFunc("GET /api/system/info", s.auth(s.handleSystemInfo))
|
||||||
s.mux.HandleFunc("POST /api/auth/login", s.handleLogin)
|
s.mux.HandleFunc("POST /api/auth/login", s.handleLogin)
|
||||||
s.mux.HandleFunc("GET /api/auth/me", s.auth(s.handleMe))
|
s.mux.HandleFunc("GET /api/auth/me", s.auth(s.handleMe))
|
||||||
s.mux.HandleFunc("POST /api/auth/logout", s.auth(s.handleLogout))
|
s.mux.HandleFunc("POST /api/auth/logout", s.auth(s.handleLogout))
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// handleSystemInfo liefert öffentliche System-Verbindungsdaten
|
||||||
|
// (FQDN, IMAP-Port). Wird im Frontend für die IMAP-Zugang-Karte
|
||||||
|
// auf der Settings-Seite verwendet.
|
||||||
|
//
|
||||||
|
// GET /api/system/info — auth required (Endpoint zeigt nur generische,
|
||||||
|
// nicht-sensitive Verbindungsdaten an, ist aber an Login gebunden, um
|
||||||
|
// öffentliches Profiling der Installation zu vermeiden).
|
||||||
|
func (s *Server) handleSystemInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||||
|
"fqdn": s.fqdn,
|
||||||
|
"imap_port": 9993,
|
||||||
|
"imap_port_alt": 993,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useAuth } from "@/hooks/useAuth";
|
import { useAuth } from "@/hooks/useAuth";
|
||||||
import { Navbar } from "@/components/navbar";
|
import { Navbar } from "@/components/navbar";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
getTOTPSetup,
|
getTOTPSetup,
|
||||||
confirmTOTPSetup,
|
confirmTOTPSetup,
|
||||||
disableTOTP,
|
disableTOTP,
|
||||||
|
getSystemInfo,
|
||||||
|
type SystemInfo,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
@@ -57,6 +59,28 @@ export default function SettingsPage() {
|
|||||||
const [disableError, setDisableError] = useState("");
|
const [disableError, setDisableError] = useState("");
|
||||||
const [disableLoading, setDisableLoading] = useState(false);
|
const [disableLoading, setDisableLoading] = useState(false);
|
||||||
|
|
||||||
|
// ── System info (FQDN + IMAP-Ports) ───────────────────────────────────
|
||||||
|
const [systemInfo, setSystemInfo] = useState<SystemInfo | null>(null);
|
||||||
|
const [systemInfoLoading, setSystemInfoLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
setSystemInfoLoading(true);
|
||||||
|
getSystemInfo()
|
||||||
|
.then((info) => {
|
||||||
|
if (!cancelled) setSystemInfo(info);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!cancelled) setSystemInfo(null);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (!cancelled) setSystemInfoLoading(false);
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Initialize email from user data once available
|
// Initialize email from user data once available
|
||||||
if (user && !emailInitialized) {
|
if (user && !emailInitialized) {
|
||||||
setEmail(user.email || "");
|
setEmail(user.email || "");
|
||||||
@@ -488,19 +512,30 @@ export default function SettingsPage() {
|
|||||||
<Server className="h-3.5 w-3.5" aria-hidden="true" />
|
<Server className="h-3.5 w-3.5" aria-hidden="true" />
|
||||||
Server
|
Server
|
||||||
</span>
|
</span>
|
||||||
<span className="font-mono">192.168.1.131</span>
|
<span className="font-mono">
|
||||||
|
{systemInfoLoading
|
||||||
|
? "Laden..."
|
||||||
|
: systemInfo?.fqdn ||
|
||||||
|
(typeof window !== "undefined"
|
||||||
|
? window.location.hostname
|
||||||
|
: "")}
|
||||||
|
</span>
|
||||||
|
|
||||||
<span className="text-muted-foreground flex items-center gap-1.5">
|
<span className="text-muted-foreground flex items-center gap-1.5">
|
||||||
<Lock className="h-3.5 w-3.5" aria-hidden="true" />
|
<Lock className="h-3.5 w-3.5" aria-hidden="true" />
|
||||||
IMAP-Port
|
IMAP-Port
|
||||||
</span>
|
</span>
|
||||||
<span className="font-mono">9993 (SSL/TLS)</span>
|
<span className="font-mono">
|
||||||
|
{systemInfo?.imap_port ?? 9993} (SSL/TLS)
|
||||||
|
</span>
|
||||||
|
|
||||||
<span className="text-muted-foreground flex items-center gap-1.5">
|
<span className="text-muted-foreground flex items-center gap-1.5">
|
||||||
<Lock className="h-3.5 w-3.5" aria-hidden="true" />
|
<Lock className="h-3.5 w-3.5" aria-hidden="true" />
|
||||||
Alternativ-Port
|
Alternativ-Port
|
||||||
</span>
|
</span>
|
||||||
<span className="font-mono">993 (SSL/TLS)</span>
|
<span className="font-mono">
|
||||||
|
{systemInfo?.imap_port_alt ?? 993} (SSL/TLS)
|
||||||
|
</span>
|
||||||
|
|
||||||
<span className="text-muted-foreground flex items-center gap-1.5">
|
<span className="text-muted-foreground flex items-center gap-1.5">
|
||||||
<Lock className="h-3.5 w-3.5" aria-hidden="true" />
|
<Lock className="h-3.5 w-3.5" aria-hidden="true" />
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export {
|
|||||||
|
|
||||||
export type {
|
export type {
|
||||||
HealthResponse,
|
HealthResponse,
|
||||||
|
SystemInfo,
|
||||||
SMTPStatus,
|
SMTPStatus,
|
||||||
StorageStats,
|
StorageStats,
|
||||||
ServiceStatus,
|
ServiceStatus,
|
||||||
@@ -142,6 +143,7 @@ export type {
|
|||||||
} from "./system";
|
} from "./system";
|
||||||
export {
|
export {
|
||||||
getHealth,
|
getHealth,
|
||||||
|
getSystemInfo,
|
||||||
getSMTPStatus,
|
getSMTPStatus,
|
||||||
getStorageStats,
|
getStorageStats,
|
||||||
getSystemStats,
|
getSystemStats,
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ export interface HealthResponse {
|
|||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SystemInfo {
|
||||||
|
fqdn: string;
|
||||||
|
imap_port: number;
|
||||||
|
imap_port_alt: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SMTPStatus {
|
export interface SMTPStatus {
|
||||||
// global daemon fields (superadmin)
|
// global daemon fields (superadmin)
|
||||||
running?: boolean;
|
running?: boolean;
|
||||||
@@ -157,6 +163,10 @@ export async function getHealth(): Promise<HealthResponse> {
|
|||||||
return request<HealthResponse>("/api/health");
|
return request<HealthResponse>("/api/health");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getSystemInfo(): Promise<SystemInfo> {
|
||||||
|
return request<SystemInfo>("/api/system/info");
|
||||||
|
}
|
||||||
|
|
||||||
export async function getSMTPStatus(): Promise<SMTPStatus> {
|
export async function getSMTPStatus(): Promise<SMTPStatus> {
|
||||||
return request<SMTPStatus>("/api/admin/smtp/status");
|
return request<SMTPStatus>("/api/admin/smtp/status");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user