diff --git a/.gitignore b/.gitignore index ed218a5..ffc5866 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ logs/ /test/ *_test.go !tests/acceptance/*_test.go +!internal/handler/subscribe_test.go *_test_config.go **/logtest/ *_test.yaml diff --git a/internal/handler/subscribe.go b/internal/handler/subscribe.go index 2db3297..1fd0b9a 100644 --- a/internal/handler/subscribe.go +++ b/internal/handler/subscribe.go @@ -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) diff --git a/internal/handler/subscribe_test.go b/internal/handler/subscribe_test.go new file mode 100644 index 0000000..1956d9d --- /dev/null +++ b/internal/handler/subscribe_test.go @@ -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 +} diff --git a/internal/middleware/panDomainMiddleware.go b/internal/middleware/panDomainMiddleware.go index 518c787..1e20f9d 100644 --- a/internal/middleware/panDomainMiddleware.go +++ b/internal/middleware/panDomainMiddleware.go @@ -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)