feat: add account editing functionality with UI modal and backend handler

This commit is contained in:
CJACK.
2026-04-22 17:20:44 +00:00
parent f14969eca5
commit 77484bf813
11 changed files with 293 additions and 11 deletions

View File

@@ -37,6 +37,7 @@ func RegisterRoutes(r chi.Router, h *Handler) {
pr.Post("/proxies/test", h.testProxy)
pr.Get("/accounts", h.listAccounts)
pr.Post("/accounts", h.addAccount)
pr.Put("/accounts/{identifier}", h.updateAccount)
pr.Delete("/accounts/{identifier}", h.deleteAccount)
pr.Put("/accounts/{identifier}/proxy", h.updateAccountProxy)
pr.Get("/queue/status", h.queueStatus)

View File

@@ -116,6 +116,46 @@ func (h *Handler) addAccount(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]any{"success": true, "total_accounts": len(h.Store.Snapshot().Accounts)})
}
func (h *Handler) updateAccount(w http.ResponseWriter, r *http.Request) {
identifier := chi.URLParam(r, "identifier")
if decoded, err := url.PathUnescape(identifier); err == nil {
identifier = decoded
}
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
}
name, nameOK := fieldStringOptional(req, "name")
remark, remarkOK := fieldStringOptional(req, "remark")
err := h.Store.Update(func(c *config.Config) error {
for i, acc := range c.Accounts {
if !accountMatchesIdentifier(acc, identifier) {
continue
}
if nameOK {
c.Accounts[i].Name = name
}
if remarkOK {
c.Accounts[i].Remark = remark
}
return nil
}
return newRequestError("账号不存在")
})
if err != nil {
if detail, ok := requestErrorDetail(err); ok {
writeJSON(w, http.StatusNotFound, map[string]any{"detail": detail})
return
}
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": err.Error()})
return
}
writeJSON(w, http.StatusOK, map[string]any{"success": true, "total_accounts": len(h.Store.Snapshot().Accounts)})
}
func (h *Handler) deleteAccount(w http.ResponseWriter, r *http.Request) {
identifier := chi.URLParam(r, "identifier")
if decoded, err := url.PathUnescape(identifier); err == nil {

View File

@@ -7,6 +7,8 @@ import (
"net/http/httptest"
"strings"
"testing"
"github.com/go-chi/chi/v5"
)
func TestListAccountsPageSizeCapIs5000(t *testing.T) {
@@ -51,3 +53,36 @@ func TestListAccountsPageSizeAbove5000ClampedTo5000(t *testing.T) {
t.Fatalf("expected page_size clamped to 5000, got %v", payload["page_size"])
}
}
func TestUpdateAccountMetadataPreservesCredentials(t *testing.T) {
h := newAdminTestHandler(t, `{
"accounts":[{"email":"u@example.com","name":"old name","remark":"old remark","password":"secret"}]
}`)
r := chi.NewRouter()
r.Put("/admin/accounts/{identifier}", h.updateAccount)
body := []byte(`{"name":"new name","remark":"new remark"}`)
req := httptest.NewRequest(http.MethodPut, "/admin/accounts/u@example.com", strings.NewReader(string(body)))
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("unexpected status: %d body=%s", rec.Code, rec.Body.String())
}
snap := h.Store.Snapshot()
if len(snap.Accounts) != 1 {
t.Fatalf("unexpected accounts after update: %#v", snap.Accounts)
}
acc := snap.Accounts[0]
if acc.Email != "u@example.com" {
t.Fatalf("identifier changed unexpectedly: %#v", acc)
}
if acc.Name != "new name" || acc.Remark != "new remark" {
t.Fatalf("metadata update did not persist: %#v", acc)
}
if acc.Password != "secret" {
t.Fatalf("password should be preserved, got %#v", acc)
}
}