mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-06 13:15:01 +03:00
e4935be861
Keep omitted client fields and per-inbound flows unchanged while honoring explicit clears. Support the query aliases used to recover legacy dot-name clients and regenerate the API reference. Add an HTTP regression covering partial updates through those aliases.
75 lines
2.9 KiB
Go
75 lines
2.9 KiB
Go
package controller
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
|
|
)
|
|
|
|
// A handler that binds the body straight into model.Client turns every omitted
|
|
// field into its zero: this expiry-only body would disable the client.
|
|
func TestUpdateHandlerKeepsFieldsTheBodyOmits(t *testing.T) {
|
|
const email = "partial-body@example.com"
|
|
dbDir := t.TempDir()
|
|
t.Setenv("XUI_DB_FOLDER", dbDir)
|
|
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
|
db := database.GetDB()
|
|
ib := &model.Inbound{
|
|
UserId: 1, Enable: true, Port: 43350, Tag: "in-partial-body",
|
|
Protocol: model.VLESS, Settings: `{"clients": []}`,
|
|
StreamSettings: `{"network":"tcp","security":"none"}`,
|
|
}
|
|
if err := db.Create(ib).Error; err != nil {
|
|
t.Fatalf("create inbound: %v", err)
|
|
}
|
|
if _, err := (&service.ClientService{}).Create(&service.InboundService{}, &service.ClientCreatePayload{
|
|
Client: model.Client{
|
|
Email: email, ID: "11111111-2222-3333-4444-555555555555", Enable: true,
|
|
LimitIP: 2, TotalGB: 10 << 30, TgID: 42, Comment: "phone",
|
|
},
|
|
InboundIds: []int{ib.Id},
|
|
}); err != nil {
|
|
t.Fatalf("seed client: %v", err)
|
|
}
|
|
|
|
a := &ClientController{}
|
|
c, w := postCtx(t, email, map[string]any{"email": email, "expiryTime": 1893456000000})
|
|
a.update(c)
|
|
|
|
var rec model.ClientRecord
|
|
if err := db.Where("email = ?", email).First(&rec).Error; err != nil {
|
|
t.Fatalf("reload client: %v (response %s)", err, w.Body.String())
|
|
}
|
|
if rec.ExpiryTime != 1893456000000 {
|
|
t.Fatalf("expiry not applied: %d (response %s)", rec.ExpiryTime, w.Body.String())
|
|
}
|
|
if !rec.Enable || rec.LimitIP != 2 || rec.TotalGB != 10<<30 || rec.TgID != 42 || rec.Comment != "phone" {
|
|
t.Fatalf("handler reset fields the body omitted: %+v", rec)
|
|
}
|
|
}
|
|
|
|
func TestClientQueryAliasPartialUpdateKeepsOmittedFields(t *testing.T) {
|
|
for _, email := range []string{".", ".."} {
|
|
t.Run(email, func(t *testing.T) {
|
|
router, rec, _ := seedLegacyDotClient(t, email)
|
|
db := database.GetDB()
|
|
if err := db.Model(&model.ClientRecord{}).Where("id = ?", rec.Id).Updates(map[string]any{"limit_ip": 2, "total_gb": int64(10 << 30), "comment": "retained"}).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w := dotClientRequest(t, router, "POST", "update?email="+email, map[string]any{"email": "recovered-partial", "expiryTime": int64(1893456000000)})
|
|
assertDotClientSuccess(t, w)
|
|
var after model.ClientRecord
|
|
if err := db.First(&after, rec.Id).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if after.Email != "recovered-partial" || after.ExpiryTime != 1893456000000 || !after.Enable || after.UUID != rec.UUID || after.SubID != rec.SubID || after.LimitIP != 2 || after.TotalGB != 10<<30 || after.Comment != "retained" {
|
|
t.Fatalf("query alias partial update lost client state: %+v", after)
|
|
}
|
|
})
|
|
}
|
|
}
|