Files
gott/Endpoints/ServerSettingsEndpoint.cs
T
Meleki 122000487c Refactor: Server-Settings von appsettings.json in DB-Tabelle (server_settings)
- Neuer ServerSettingsService: zentrale Settings in SQLite mit In-Memory-Cache
- Auto-Migration: bestehende appsettings.Production.json wird einmalig in DB übernommen
- Alle Services umgestellt: IConfiguration → ServerSettingsService (dynamisch, kein Neustart)
- Port bleibt als einziges Setting in appsettings.Production.json (erfordert Neustart)
- ServerSettingsEndpoint: liest/schreibt DB statt JSON-Datei, Port als Sonder-Setting
- IConfiguration komplett entfernt aus allen Services (ChatService, ToolService, AnthropicService,
  OpenAiService, KreaService, TelegramService, KeyScannerService, GitHubEventScannerService)
- AuthMiddleware: KreaApiKey dynamisch aus DB
- appsettings.json bereinigt: nur noch Port und Logging
- Dokumentation aktualisiert (ARCHITECTURE.md, ARCHITECTURE_QUICK.md, README.md)
2026-03-14 13:06:44 +01:00

125 lines
4.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Gott.Extensions;
using Gott.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
namespace Gott.Endpoints;
public static class ServerSettingsEndpoint
{
public static void MapServerSettingsEndpoints(this WebApplication app)
{
app.MapGet("/api/admin/server-settings", HandleGet);
app.MapPut("/api/admin/server-settings", HandleUpdate);
}
private static async Task HandleGet(HttpContext ctx, ServerSettingsService settings, IConfiguration config)
{
if (!ctx.IsAdmin())
{
ctx.Response.StatusCode = 403;
await ctx.Response.WriteAsJsonAsync(new { error = "Admin access required" });
return;
}
// Port aus appsettings (nicht DB) – als erstes Feld
var port = config.GetValue<int>("Port", 19000);
var allSettings = new List<object>
{
new
{
key = "Port",
type = "int",
value = (object)port,
label = "Server-Port (erfordert Neustart)",
inputType = "number",
}
};
allSettings.AddRange(settings.GetAll());
await ctx.Response.WriteAsJsonAsync(new { settings = allSettings });
}
private static async Task HandleUpdate(HttpContext ctx, ServerSettingsService settings, IConfiguration config)
{
if (!ctx.IsAdmin())
{
ctx.Response.StatusCode = 403;
await ctx.Response.WriteAsJsonAsync(new { error = "Admin access required" });
return;
}
var body = await JsonSerializer.DeserializeAsync<JsonElement>(ctx.Request.Body);
var hint = "";
// Port separat behandeln – in appsettings.Production.json speichern
if (body.TryGetProperty("Port", out var portProp) && portProp.TryGetInt32(out var newPort))
{
var currentPort = config.GetValue<int>("Port", 19000);
if (newPort != currentPort && newPort > 0 && newPort <= 65535)
{
SavePortToAppSettings(ctx, newPort);
hint = "Port geändert – Neustart erforderlich!";
}
}
// Alle anderen Settings in DB speichern
foreach (var def in ServerSettingsService.Definitions)
{
if (!body.TryGetProperty(def.Key, out var prop)) continue;
switch (def.Type)
{
case "string":
settings.Set(def.Key, prop.GetString() ?? "");
break;
case "int":
settings.SetInt(def.Key, prop.TryGetInt32(out var i) ? i : 0);
break;
case "bool":
settings.SetBool(def.Key, prop.ValueKind == JsonValueKind.True);
break;
}
}
await ctx.Response.WriteAsJsonAsync(new { ok = true, hint = string.IsNullOrEmpty(hint) ? "Einstellungen gespeichert" : hint });
}
private static void SavePortToAppSettings(HttpContext ctx, int port)
{
// appsettings.Production.json im ContentRootPath (= publish-Verzeichnis)
var contentRoot = ctx.RequestServices.GetService(typeof(Microsoft.AspNetCore.Hosting.IWebHostEnvironment)) as Microsoft.AspNetCore.Hosting.IWebHostEnvironment;
var path = Path.Combine(contentRoot?.ContentRootPath ?? AppContext.BaseDirectory, "appsettings.Production.json");
JsonObject obj;
if (File.Exists(path))
{
try
{
var existing = File.ReadAllText(path);
obj = JsonNode.Parse(existing) as JsonObject ?? new JsonObject();
}
catch
{
obj = new JsonObject();
}
}
else
{
obj = new JsonObject();
}
obj["Port"] = port;
var options = new JsonSerializerOptions { WriteIndented = true };
File.WriteAllText(path, obj.ToJsonString(options));
}
}