修复(#51): 修正封禁用户订阅返回码

封禁用户拉订阅时返回纯文本 500 退化为业务码 20004,统一走 result.HttpResult。覆盖 /api/subscribe 和泛域名两条入口,补回归测试。
This commit is contained in:
2026-06-16 07:53:37 -07:00
committed by GitHub
parent 77fa0cadd2
commit f0a5288e20
4 changed files with 338 additions and 1 deletions
+1
View File
@@ -43,6 +43,7 @@ logs/
/test/
*_test.go
!tests/acceptance/*_test.go
!internal/handler/subscribe_test.go
*_test_config.go
**/logtest/
*_test.yaml
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/tool"
)
@@ -84,7 +85,7 @@ func SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
l := subscribe.NewSubscribeLogic(c, svcCtx)
resp, err := l.Handler(&req)
if err != nil {
c.String(http.StatusInternalServerError, "Internal Server")
result.HttpResult(c, nil, err)
return
}
c.Header("subscription-userinfo", resp.Header)
+332
View File
@@ -0,0 +1,332 @@
package handler
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/config"
logiccommon "github.com/perfect-panel/server/internal/logic/common"
"github.com/perfect-panel/server/internal/model/client"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
func TestSubscribeHandlerReturnsBusinessErrorForDisabledUser(t *testing.T) {
gin.SetMode(gin.TestMode)
redisServer, err := miniredis.Run()
if err != nil {
t.Fatalf("miniredis.Run() error = %v", err)
}
defer redisServer.Close()
rdb := redis.NewClient(&redis.Options{Addr: redisServer.Addr()})
defer func() {
_ = rdb.Close()
}()
if err := rdb.Set(context.Background(), logiccommon.UserEnableCacheKey(83696), "false", 0).Err(); err != nil {
t.Fatalf("seed user enable cache: %v", err)
}
router := gin.New()
router.GET("/api/subscribe", SubscribeHandler(&svc.ServiceContext{
Config: config.Config{
Subscribe: config.SubscribeConfig{
SubscribePath: "/api/subscribe",
},
},
ClientModel: subscribeClientModelStub{
list: []*client.SubscribeApplication{
{
Id: 1,
UserAgent: "clashmeta",
IsDefault: true,
OutputFormat: "yaml",
},
},
},
Redis: rdb,
UserModel: subscribeUserModelStub{
subscribe: &user.Subscribe{Id: 35446, UserId: 83696, SubscribeId: 1, Token: "disabled-token"},
},
}))
req := httptest.NewRequest(http.MethodGet, "/api/subscribe?token=disabled-token", nil)
req.Header.Set("User-Agent", "ClashMetaForAndroid/2.11.7.Meta")
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected HTTP 200, got %d", rec.Code)
}
var resp struct {
Code uint32 `json:"code"`
Msg string `json:"msg"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
t.Fatalf("unmarshal response: %v", err)
}
if resp.Code != xerr.UserDisabled {
t.Fatalf("expected code %d, got %d (%s)", xerr.UserDisabled, resp.Code, resp.Msg)
}
}
type subscribeClientModelStub struct {
list []*client.SubscribeApplication
err error
}
func (s subscribeClientModelStub) Insert(context.Context, *client.SubscribeApplication) error {
return nil
}
func (s subscribeClientModelStub) FindOne(context.Context, int64) (*client.SubscribeApplication, error) {
return nil, nil
}
func (s subscribeClientModelStub) Update(context.Context, *client.SubscribeApplication) error {
return nil
}
func (s subscribeClientModelStub) Delete(context.Context, int64) error {
return nil
}
func (s subscribeClientModelStub) List(context.Context) ([]*client.SubscribeApplication, error) {
return s.list, s.err
}
func (s subscribeClientModelStub) Transaction(context.Context, func(*gorm.DB) error) error {
return nil
}
type subscribeUserModelStub struct {
subscribe *user.Subscribe
subErr error
findOne *user.User
findOneErr error
}
func (s subscribeUserModelStub) Insert(context.Context, *user.User, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) FindOne(context.Context, int64) (*user.User, error) {
if s.findOneErr != nil {
return nil, s.findOneErr
}
return s.findOne, nil
}
func (s subscribeUserModelStub) Update(context.Context, *user.User, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) UpdateCommission(context.Context, int64, int64, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) Delete(context.Context, int64, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) Transaction(context.Context, func(*gorm.DB) error) error {
return nil
}
func (s subscribeUserModelStub) QueryPageList(context.Context, int, int, *user.UserFilterParams) ([]*user.User, int64, error) {
return nil, 0, nil
}
func (s subscribeUserModelStub) FindOneByReferCode(context.Context, string) (*user.User, error) {
return nil, nil
}
func (s subscribeUserModelStub) BatchDeleteUser(context.Context, []int64, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) InsertSubscribe(context.Context, *user.Subscribe, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) FindOneSubscribeByToken(context.Context, string) (*user.Subscribe, error) {
if s.subErr != nil {
return nil, s.subErr
}
return s.subscribe, nil
}
func (s subscribeUserModelStub) FindSingleModeAnchorSubscribe(context.Context, int64) (*user.Subscribe, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindOneSubscribeByOrderId(context.Context, int64) (*user.Subscribe, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindOneSubscribe(context.Context, int64) (*user.Subscribe, error) {
return nil, nil
}
func (s subscribeUserModelStub) UpdateSubscribe(context.Context, *user.Subscribe, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) DeleteSubscribe(context.Context, string, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) DeleteSubscribeById(context.Context, int64, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) QueryUserSubscribe(context.Context, int64, ...int64) ([]*user.SubscribeDetails, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindOneSubscribeDetailsById(context.Context, int64) (*user.SubscribeDetails, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindOneUserSubscribe(context.Context, int64) (*user.SubscribeDetails, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindUsersSubscribeBySubscribeId(context.Context, int64) ([]*user.Subscribe, error) {
return nil, nil
}
func (s subscribeUserModelStub) UpdateUserSubscribeWithTraffic(context.Context, int64, int64, int64, bool, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) QueryResisterUserTotalByDate(context.Context, time.Time) (int64, error) {
return 0, nil
}
func (s subscribeUserModelStub) QueryResisterUserTotalByMonthly(context.Context, time.Time) (int64, error) {
return 0, nil
}
func (s subscribeUserModelStub) QueryResisterUserTotal(context.Context) (int64, error) {
return 0, nil
}
func (s subscribeUserModelStub) QueryAdminUsers(context.Context) ([]*user.User, error) {
return nil, nil
}
func (s subscribeUserModelStub) UpdateUserCache(context.Context, *user.User) error {
return nil
}
func (s subscribeUserModelStub) UpdateUserSubscribeCache(context.Context, *user.Subscribe) error {
return nil
}
func (s subscribeUserModelStub) QueryActiveSubscriptions(context.Context, ...int64) (map[int64]int64, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindUserAuthMethods(context.Context, int64) ([]*user.AuthMethods, error) {
return nil, nil
}
func (s subscribeUserModelStub) InsertUserAuthMethods(context.Context, *user.AuthMethods, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) UpdateUserAuthMethods(context.Context, *user.AuthMethods, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) DeleteUserAuthMethods(context.Context, int64, string, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) FindUserAuthMethodByOpenID(context.Context, string, string) (*user.AuthMethods, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindUserAuthMethodByUserId(context.Context, string, int64) (*user.AuthMethods, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindUserAuthMethodByPlatform(context.Context, int64, string) (*user.AuthMethods, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindOneByEmail(context.Context, string) (*user.User, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindOneDevice(context.Context, int64) (*user.Device, error) {
return nil, nil
}
func (s subscribeUserModelStub) QueryDeviceList(context.Context, int64) ([]*user.Device, int64, error) {
return nil, 0, nil
}
func (s subscribeUserModelStub) QueryDeviceListByUserIds(context.Context, []int64) ([]*user.Device, int64, error) {
return nil, 0, nil
}
func (s subscribeUserModelStub) QueryDevicePageList(context.Context, int64, int64, int, int) ([]*user.Device, int64, error) {
return nil, 0, nil
}
func (s subscribeUserModelStub) UpdateDevice(context.Context, *user.Device, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) FindOneDeviceByIdentifier(context.Context, string) (*user.Device, error) {
return nil, nil
}
func (s subscribeUserModelStub) DeleteDevice(context.Context, int64, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) InsertDevice(context.Context, *user.Device, ...*gorm.DB) error {
return nil
}
func (s subscribeUserModelStub) ClearSubscribeCache(context.Context, ...*user.Subscribe) error {
return nil
}
func (s subscribeUserModelStub) ClearUserCache(context.Context, ...*user.User) error {
return nil
}
func (s subscribeUserModelStub) ClearDeviceCache(context.Context, ...*user.Device) error {
return nil
}
func (s subscribeUserModelStub) QueryDailyUserStatisticsList(context.Context, time.Time) ([]user.UserStatisticsWithDate, error) {
return nil, nil
}
func (s subscribeUserModelStub) QueryMonthlyUserStatisticsList(context.Context, time.Time) ([]user.UserStatisticsWithDate, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindActiveSubscribe(context.Context, int64) (*user.Subscribe, error) {
return nil, nil
}
func (s subscribeUserModelStub) FindActiveSubscribesByUserIds(context.Context, []int64) (map[int64]*user.UserStatusInfo, error) {
return nil, nil
}
@@ -9,6 +9,7 @@ import (
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/tool"
)
@@ -66,6 +67,8 @@ func PanDomainMiddleware(svc *svc.ServiceContext) func(c *gin.Context) {
l := subscribe.NewSubscribeLogic(c, svc)
resp, err := l.Handler(&request)
if err != nil {
result.HttpResult(c, nil, err)
c.Abort()
return
}
c.Header("subscription-userinfo", resp.Header)