mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-03 16:05:26 +08:00
127 lines
3.9 KiB
Go
127 lines
3.9 KiB
Go
package admin
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
authn "ds2api/internal/auth"
|
|
"ds2api/internal/config"
|
|
)
|
|
|
|
func (h *Handler) updateSettings(w http.ResponseWriter, r *http.Request) {
|
|
var req map[string]any
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": "invalid json"})
|
|
return
|
|
}
|
|
|
|
adminCfg, runtimeCfg, compatCfg, responsesCfg, embeddingsCfg, autoDeleteCfg, claudeMap, aliasMap, err := parseSettingsUpdateRequest(req)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": err.Error()})
|
|
return
|
|
}
|
|
if runtimeCfg != nil {
|
|
if err := validateMergedRuntimeSettings(h.Store.Snapshot().Runtime, runtimeCfg); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": err.Error()})
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := h.Store.Update(func(c *config.Config) error {
|
|
if adminCfg != nil {
|
|
if adminCfg.JWTExpireHours > 0 {
|
|
c.Admin.JWTExpireHours = adminCfg.JWTExpireHours
|
|
}
|
|
}
|
|
if runtimeCfg != nil {
|
|
if runtimeCfg.AccountMaxInflight > 0 {
|
|
c.Runtime.AccountMaxInflight = runtimeCfg.AccountMaxInflight
|
|
}
|
|
if runtimeCfg.AccountMaxQueue > 0 {
|
|
c.Runtime.AccountMaxQueue = runtimeCfg.AccountMaxQueue
|
|
}
|
|
if runtimeCfg.GlobalMaxInflight > 0 {
|
|
c.Runtime.GlobalMaxInflight = runtimeCfg.GlobalMaxInflight
|
|
}
|
|
if runtimeCfg.TokenRefreshIntervalHours > 0 {
|
|
c.Runtime.TokenRefreshIntervalHours = runtimeCfg.TokenRefreshIntervalHours
|
|
}
|
|
}
|
|
if compatCfg != nil {
|
|
if compatCfg.WideInputStrictOutput != nil {
|
|
c.Compat.WideInputStrictOutput = compatCfg.WideInputStrictOutput
|
|
}
|
|
if compatCfg.StripReferenceMarkers != nil {
|
|
c.Compat.StripReferenceMarkers = compatCfg.StripReferenceMarkers
|
|
}
|
|
}
|
|
if responsesCfg != nil && responsesCfg.StoreTTLSeconds > 0 {
|
|
c.Responses.StoreTTLSeconds = responsesCfg.StoreTTLSeconds
|
|
}
|
|
if embeddingsCfg != nil && strings.TrimSpace(embeddingsCfg.Provider) != "" {
|
|
c.Embeddings.Provider = strings.TrimSpace(embeddingsCfg.Provider)
|
|
}
|
|
if autoDeleteCfg != nil {
|
|
c.AutoDelete.Mode = autoDeleteCfg.Mode
|
|
c.AutoDelete.Sessions = autoDeleteCfg.Sessions
|
|
}
|
|
if claudeMap != nil {
|
|
c.ClaudeMapping = claudeMap
|
|
c.ClaudeModelMap = nil
|
|
}
|
|
if aliasMap != nil {
|
|
c.ModelAliases = aliasMap
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]any{"detail": err.Error()})
|
|
return
|
|
}
|
|
|
|
h.applyRuntimeSettings()
|
|
needsSync := config.IsVercel() || h.Store.IsEnvBacked()
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"success": true,
|
|
"message": "settings updated and hot reloaded",
|
|
"env_backed": h.Store.IsEnvBacked(),
|
|
"needs_vercel_sync": needsSync,
|
|
"manual_sync_message": "配置已保存。Vercel 部署请在 Vercel Sync 页面手动同步。",
|
|
})
|
|
}
|
|
|
|
func (h *Handler) updateSettingsPassword(w http.ResponseWriter, r *http.Request) {
|
|
var req map[string]any
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": "invalid json"})
|
|
return
|
|
}
|
|
newPassword := strings.TrimSpace(fieldString(req, "new_password"))
|
|
if newPassword == "" {
|
|
newPassword = strings.TrimSpace(fieldString(req, "password"))
|
|
}
|
|
if len(newPassword) < 4 {
|
|
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": "new password must be at least 4 characters"})
|
|
return
|
|
}
|
|
|
|
now := time.Now().Unix()
|
|
hash := authn.HashAdminPassword(newPassword)
|
|
if err := h.Store.Update(func(c *config.Config) error {
|
|
c.Admin.PasswordHash = hash
|
|
c.Admin.JWTValidAfterUnix = now
|
|
return nil
|
|
}); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]any{"detail": err.Error()})
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"success": true,
|
|
"message": "password updated",
|
|
"force_relogin": true,
|
|
"jwt_valid_after_unix": now,
|
|
})
|
|
}
|