mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-14 05:05:09 +08:00
feat: add account editing functionality with UI modal and backend handler
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user