From b3f112005e80cb188c7c842ead9ca9636d219f41 Mon Sep 17 00:00:00 2001 From: pham Date: Mon, 20 Apr 2026 13:05:44 +0800 Subject: [PATCH] remove deprecated mock admin endpoints --- .../admin/admin_basic_handlers_test.go | 43 ++++++++++++------- .../handler/admin/admin_service_stub_test.go | 4 -- .../handler/admin/dashboard_handler.go | 12 ------ .../internal/handler/admin/proxy_handler.go | 20 --------- .../internal/handler/admin/redeem_handler.go | 18 -------- .../internal/handler/admin/user_handler.go | 20 --------- backend/internal/server/routes/admin.go | 4 -- .../server/routes/admin_routes_test.go | 41 ++++++++++++++++++ backend/internal/service/admin_service.go | 12 ------ frontend/src/api/admin/dashboard.ts | 20 --------- frontend/src/api/admin/proxies.ts | 23 ---------- frontend/src/api/admin/redeem.ts | 24 ----------- frontend/src/api/admin/users.ts | 25 ----------- 13 files changed, 68 insertions(+), 198 deletions(-) create mode 100644 backend/internal/server/routes/admin_routes_test.go diff --git a/backend/internal/handler/admin/admin_basic_handlers_test.go b/backend/internal/handler/admin/admin_basic_handlers_test.go index 73d10190..6edf35a3 100644 --- a/backend/internal/handler/admin/admin_basic_handlers_test.go +++ b/backend/internal/handler/admin/admin_basic_handlers_test.go @@ -29,7 +29,6 @@ func setupAdminRouter() (*gin.Engine, *stubAdminService) { router.DELETE("/api/v1/admin/users/:id", userHandler.Delete) router.POST("/api/v1/admin/users/:id/balance", userHandler.UpdateBalance) router.GET("/api/v1/admin/users/:id/api-keys", userHandler.GetUserAPIKeys) - router.GET("/api/v1/admin/users/:id/usage", userHandler.GetUserUsage) router.GET("/api/v1/admin/groups", groupHandler.List) router.GET("/api/v1/admin/groups/all", groupHandler.GetAll) @@ -49,7 +48,6 @@ func setupAdminRouter() (*gin.Engine, *stubAdminService) { router.POST("/api/v1/admin/proxies/batch-delete", proxyHandler.BatchDelete) router.POST("/api/v1/admin/proxies/:id/test", proxyHandler.Test) router.POST("/api/v1/admin/proxies/:id/quality-check", proxyHandler.CheckQuality) - router.GET("/api/v1/admin/proxies/:id/stats", proxyHandler.GetStats) router.GET("/api/v1/admin/proxies/:id/accounts", proxyHandler.GetProxyAccounts) router.GET("/api/v1/admin/redeem-codes", redeemHandler.List) @@ -58,7 +56,6 @@ func setupAdminRouter() (*gin.Engine, *stubAdminService) { router.DELETE("/api/v1/admin/redeem-codes/:id", redeemHandler.Delete) router.POST("/api/v1/admin/redeem-codes/batch-delete", redeemHandler.BatchDelete) router.POST("/api/v1/admin/redeem-codes/:id/expire", redeemHandler.Expire) - router.GET("/api/v1/admin/redeem-codes/:id/stats", redeemHandler.GetStats) return router, adminSvc } @@ -108,10 +105,6 @@ func TestUserHandlerEndpoints(t *testing.T) { router.ServeHTTP(rec, req) require.Equal(t, http.StatusOK, rec.Code) - rec = httptest.NewRecorder() - req = httptest.NewRequest(http.MethodGet, "/api/v1/admin/users/1/usage?period=today", nil) - router.ServeHTTP(rec, req) - require.Equal(t, http.StatusOK, rec.Code) } func TestGroupHandlerEndpoints(t *testing.T) { @@ -215,11 +208,6 @@ func TestProxyHandlerEndpoints(t *testing.T) { router.ServeHTTP(rec, req) require.Equal(t, http.StatusOK, rec.Code) - rec = httptest.NewRecorder() - req = httptest.NewRequest(http.MethodGet, "/api/v1/admin/proxies/4/stats", nil) - router.ServeHTTP(rec, req) - require.Equal(t, http.StatusOK, rec.Code) - rec = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/api/v1/admin/proxies/4/accounts", nil) router.ServeHTTP(rec, req) @@ -282,8 +270,31 @@ func TestRedeemHandlerEndpoints(t *testing.T) { router.ServeHTTP(rec, req) require.Equal(t, http.StatusOK, rec.Code) - rec = httptest.NewRecorder() - req = httptest.NewRequest(http.MethodGet, "/api/v1/admin/redeem-codes/5/stats", nil) - router.ServeHTTP(rec, req) - require.Equal(t, http.StatusOK, rec.Code) +} + +func TestDeprecatedMockAdminEndpointsNotRegistered(t *testing.T) { + router, _ := setupAdminRouter() + + testCases := []struct { + name string + url string + }{ + { + name: "user usage", + url: "/api/v1/admin/users/1/usage?period=today", + }, + { + name: "proxy stats", + url: "/api/v1/admin/proxies/4/stats", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + rec := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodGet, tc.url, nil) + router.ServeHTTP(rec, req) + require.Equal(t, http.StatusNotFound, rec.Code) + }) + } } diff --git a/backend/internal/handler/admin/admin_service_stub_test.go b/backend/internal/handler/admin/admin_service_stub_test.go index 47e269e4..d4fdd620 100644 --- a/backend/internal/handler/admin/admin_service_stub_test.go +++ b/backend/internal/handler/admin/admin_service_stub_test.go @@ -164,10 +164,6 @@ func (s *stubAdminService) GetUserAPIKeys(ctx context.Context, userID int64, pag return s.apiKeys, int64(len(s.apiKeys)), nil } -func (s *stubAdminService) GetUserUsageStats(ctx context.Context, userID int64, period string) (any, error) { - return map[string]any{"user_id": userID}, nil -} - func (s *stubAdminService) ListGroups(ctx context.Context, page, pageSize int, platform, status, search string, isExclusive *bool, sortBy, sortOrder string) ([]service.Group, int64, error) { return s.groups, int64(len(s.groups)), nil } diff --git a/backend/internal/handler/admin/dashboard_handler.go b/backend/internal/handler/admin/dashboard_handler.go index 460f6357..01fba58e 100644 --- a/backend/internal/handler/admin/dashboard_handler.go +++ b/backend/internal/handler/admin/dashboard_handler.go @@ -175,18 +175,6 @@ func (h *DashboardHandler) BackfillAggregation(c *gin.Context) { }) } -// GetRealtimeMetrics handles getting real-time system metrics -// GET /api/v1/admin/dashboard/realtime -func (h *DashboardHandler) GetRealtimeMetrics(c *gin.Context) { - // Return mock data for now - response.Success(c, gin.H{ - "active_requests": 0, - "requests_per_minute": 0, - "average_response_time": 0, - "error_rate": 0.0, - }) -} - // GetUsageTrend handles getting usage trend data // GET /api/v1/admin/dashboard/trend // Query params: start_date, end_date (YYYY-MM-DD), granularity (day/hour), user_id, api_key_id, model, account_id, group_id, request_type, stream, billing_type diff --git a/backend/internal/handler/admin/proxy_handler.go b/backend/internal/handler/admin/proxy_handler.go index f97fcb0a..3b4202c0 100644 --- a/backend/internal/handler/admin/proxy_handler.go +++ b/backend/internal/handler/admin/proxy_handler.go @@ -257,26 +257,6 @@ func (h *ProxyHandler) CheckQuality(c *gin.Context) { response.Success(c, result) } -// GetStats handles getting proxy statistics -// GET /api/v1/admin/proxies/:id/stats -func (h *ProxyHandler) GetStats(c *gin.Context) { - proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) - if err != nil { - response.BadRequest(c, "Invalid proxy ID") - return - } - - // Return mock data for now - _ = proxyID - response.Success(c, gin.H{ - "total_accounts": 0, - "active_accounts": 0, - "total_requests": 0, - "success_rate": 100.0, - "average_latency": 0, - }) -} - // GetProxyAccounts handles getting accounts using a proxy // GET /api/v1/admin/proxies/:id/accounts func (h *ProxyHandler) GetProxyAccounts(c *gin.Context) { diff --git a/backend/internal/handler/admin/redeem_handler.go b/backend/internal/handler/admin/redeem_handler.go index 901a0904..75f5d478 100644 --- a/backend/internal/handler/admin/redeem_handler.go +++ b/backend/internal/handler/admin/redeem_handler.go @@ -276,24 +276,6 @@ func (h *RedeemHandler) Expire(c *gin.Context) { response.Success(c, dto.RedeemCodeFromServiceAdmin(code)) } -// GetStats handles getting redeem code statistics -// GET /api/v1/admin/redeem-codes/stats -func (h *RedeemHandler) GetStats(c *gin.Context) { - // Return mock data for now - response.Success(c, gin.H{ - "total_codes": 0, - "active_codes": 0, - "used_codes": 0, - "expired_codes": 0, - "total_value_distributed": 0.0, - "by_type": gin.H{ - "balance": 0, - "concurrency": 0, - "trial": 0, - }, - }) -} - // Export handles exporting redeem codes to CSV // GET /api/v1/admin/redeem-codes/export func (h *RedeemHandler) Export(c *gin.Context) { diff --git a/backend/internal/handler/admin/user_handler.go b/backend/internal/handler/admin/user_handler.go index deeaaceb..2ab17411 100644 --- a/backend/internal/handler/admin/user_handler.go +++ b/backend/internal/handler/admin/user_handler.go @@ -308,26 +308,6 @@ func (h *UserHandler) GetUserAPIKeys(c *gin.Context) { response.Paginated(c, out, total, page, pageSize) } -// GetUserUsage handles getting user's usage statistics -// GET /api/v1/admin/users/:id/usage -func (h *UserHandler) GetUserUsage(c *gin.Context) { - userID, err := strconv.ParseInt(c.Param("id"), 10, 64) - if err != nil { - response.BadRequest(c, "Invalid user ID") - return - } - - period := c.DefaultQuery("period", "month") - - stats, err := h.adminService.GetUserUsageStats(c.Request.Context(), userID, period) - if err != nil { - response.ErrorFrom(c, err) - return - } - - response.Success(c, stats) -} - // GetBalanceHistory handles getting user's balance/concurrency change history // GET /api/v1/admin/users/:id/balance-history // Query params: diff --git a/backend/internal/server/routes/admin.go b/backend/internal/server/routes/admin.go index cd374c84..b80ff5d8 100644 --- a/backend/internal/server/routes/admin.go +++ b/backend/internal/server/routes/admin.go @@ -213,7 +213,6 @@ func registerDashboardRoutes(admin *gin.RouterGroup, h *handler.Handlers) { { dashboard.GET("/snapshot-v2", h.Admin.Dashboard.GetSnapshotV2) dashboard.GET("/stats", h.Admin.Dashboard.GetStats) - dashboard.GET("/realtime", h.Admin.Dashboard.GetRealtimeMetrics) dashboard.GET("/trend", h.Admin.Dashboard.GetUsageTrend) dashboard.GET("/models", h.Admin.Dashboard.GetModelStats) dashboard.GET("/groups", h.Admin.Dashboard.GetGroupStats) @@ -237,7 +236,6 @@ func registerUserManagementRoutes(admin *gin.RouterGroup, h *handler.Handlers) { users.DELETE("/:id", h.Admin.User.Delete) users.POST("/:id/balance", h.Admin.User.UpdateBalance) users.GET("/:id/api-keys", h.Admin.User.GetUserAPIKeys) - users.GET("/:id/usage", h.Admin.User.GetUserUsage) users.GET("/:id/balance-history", h.Admin.User.GetBalanceHistory) users.POST("/:id/replace-group", h.Admin.User.ReplaceGroup) @@ -370,7 +368,6 @@ func registerProxyRoutes(admin *gin.RouterGroup, h *handler.Handlers) { proxies.DELETE("/:id", h.Admin.Proxy.Delete) proxies.POST("/:id/test", h.Admin.Proxy.Test) proxies.POST("/:id/quality-check", h.Admin.Proxy.CheckQuality) - proxies.GET("/:id/stats", h.Admin.Proxy.GetStats) proxies.GET("/:id/accounts", h.Admin.Proxy.GetProxyAccounts) proxies.POST("/batch-delete", h.Admin.Proxy.BatchDelete) proxies.POST("/batch", h.Admin.Proxy.BatchCreate) @@ -381,7 +378,6 @@ func registerRedeemCodeRoutes(admin *gin.RouterGroup, h *handler.Handlers) { codes := admin.Group("/redeem-codes") { codes.GET("", h.Admin.Redeem.List) - codes.GET("/stats", h.Admin.Redeem.GetStats) codes.GET("/export", h.Admin.Redeem.Export) codes.GET("/:id", h.Admin.Redeem.GetByID) codes.POST("/create-and-redeem", h.Admin.Redeem.CreateAndRedeem) diff --git a/backend/internal/server/routes/admin_routes_test.go b/backend/internal/server/routes/admin_routes_test.go new file mode 100644 index 00000000..e141391a --- /dev/null +++ b/backend/internal/server/routes/admin_routes_test.go @@ -0,0 +1,41 @@ +package routes + +import ( + "testing" + + "github.com/Wei-Shaw/sub2api/internal/handler" + "github.com/Wei-Shaw/sub2api/internal/server/middleware" + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/require" +) + +func TestRegisterAdminRoutes_OmitsDeprecatedMockEndpoints(t *testing.T) { + gin.SetMode(gin.TestMode) + + engine := gin.New() + v1 := engine.Group("/api/v1") + adminAuth := middleware.AdminAuthMiddleware(func(c *gin.Context) { + c.Next() + }) + + RegisterAdminRoutes(v1, &handler.Handlers{ + Admin: &handler.AdminHandlers{}, + }, adminAuth) + + routesByMethodAndPath := make(map[string]struct{}) + for _, route := range engine.Routes() { + routesByMethodAndPath[route.Method+" "+route.Path] = struct{}{} + } + + deprecatedRoutes := []string{ + "GET /api/v1/admin/dashboard/realtime", + "GET /api/v1/admin/users/:id/usage", + "GET /api/v1/admin/proxies/:id/stats", + "GET /api/v1/admin/redeem-codes/stats", + } + + for _, route := range deprecatedRoutes { + _, exists := routesByMethodAndPath[route] + require.Falsef(t, exists, "deprecated mock route should not be registered: %s", route) + } +} diff --git a/backend/internal/service/admin_service.go b/backend/internal/service/admin_service.go index b9810e95..b3fb4fde 100644 --- a/backend/internal/service/admin_service.go +++ b/backend/internal/service/admin_service.go @@ -28,7 +28,6 @@ type AdminService interface { DeleteUser(ctx context.Context, id int64) error UpdateUserBalance(ctx context.Context, userID int64, balance float64, operation string, notes string) (*User, error) GetUserAPIKeys(ctx context.Context, userID int64, page, pageSize int, sortBy, sortOrder string) ([]APIKey, int64, error) - GetUserUsageStats(ctx context.Context, userID int64, period string) (any, error) // GetUserBalanceHistory returns paginated balance/concurrency change records for a user. // codeType is optional - pass empty string to return all types. // Also returns totalRecharged (sum of all positive balance top-ups). @@ -772,17 +771,6 @@ func (s *adminServiceImpl) GetUserAPIKeys(ctx context.Context, userID int64, pag return keys, result.Total, nil } -func (s *adminServiceImpl) GetUserUsageStats(ctx context.Context, userID int64, period string) (any, error) { - // Return mock data for now - return map[string]any{ - "period": period, - "total_requests": 0, - "total_cost": 0.0, - "total_tokens": 0, - "avg_duration_ms": 0, - }, nil -} - // GetUserBalanceHistory returns paginated balance/concurrency change records for a user. func (s *adminServiceImpl) GetUserBalanceHistory(ctx context.Context, userID int64, page, pageSize int, codeType string) ([]RedeemCode, int64, float64, error) { params := pagination.PaginationParams{Page: page, PageSize: pageSize} diff --git a/frontend/src/api/admin/dashboard.ts b/frontend/src/api/admin/dashboard.ts index 49e487b7..fd0a6fd6 100644 --- a/frontend/src/api/admin/dashboard.ts +++ b/frontend/src/api/admin/dashboard.ts @@ -25,25 +25,6 @@ export async function getStats(): Promise { return data } -/** - * Get real-time metrics - * @returns Real-time system metrics - */ -export async function getRealtimeMetrics(): Promise<{ - active_requests: number - requests_per_minute: number - average_response_time: number - error_rate: number -}> { - const { data } = await apiClient.get<{ - active_requests: number - requests_per_minute: number - average_response_time: number - error_rate: number - }>('/admin/dashboard/realtime') - return data -} - export interface TrendParams { start_date?: string end_date?: string @@ -317,7 +298,6 @@ export async function getBatchApiKeysUsage( export const dashboardAPI = { getStats, - getRealtimeMetrics, getUsageTrend, getModelStats, getGroupStats, diff --git a/frontend/src/api/admin/proxies.ts b/frontend/src/api/admin/proxies.ts index 3e041ba9..a594db18 100644 --- a/frontend/src/api/admin/proxies.ts +++ b/frontend/src/api/admin/proxies.ts @@ -156,28 +156,6 @@ export async function checkProxyQuality(id: number): Promise { - const { data } = await apiClient.get<{ - total_accounts: number - active_accounts: number - total_requests: number - success_rate: number - average_latency: number - }>(`/admin/proxies/${id}/stats`) - return data -} - /** * Get accounts using a proxy * @param id - Proxy ID @@ -266,7 +244,6 @@ export const proxiesAPI = { toggleStatus, testProxy, checkProxyQuality, - getStats, getProxyAccounts, batchCreate, batchDelete, diff --git a/frontend/src/api/admin/redeem.ts b/frontend/src/api/admin/redeem.ts index df46279f..f02c3cce 100644 --- a/frontend/src/api/admin/redeem.ts +++ b/frontend/src/api/admin/redeem.ts @@ -127,29 +127,6 @@ export async function expire(id: number): Promise { return data } -/** - * Get redeem code statistics - * @returns Statistics about redeem codes - */ -export async function getStats(): Promise<{ - total_codes: number - active_codes: number - used_codes: number - expired_codes: number - total_value_distributed: number - by_type: Record -}> { - const { data } = await apiClient.get<{ - total_codes: number - active_codes: number - used_codes: number - expired_codes: number - total_value_distributed: number - by_type: Record - }>('/admin/redeem-codes/stats') - return data -} - /** * Export redeem codes to CSV * @param filters - Optional filters @@ -176,7 +153,6 @@ export const redeemAPI = { delete: deleteCode, batchDelete, expire, - getStats, exportCodes } diff --git a/frontend/src/api/admin/users.ts b/frontend/src/api/admin/users.ts index 39cb1dfa..c135b08b 100644 --- a/frontend/src/api/admin/users.ts +++ b/frontend/src/api/admin/users.ts @@ -158,30 +158,6 @@ export async function getUserApiKeys(id: number): Promise { - const { data } = await apiClient.get<{ - total_requests: number - total_cost: number - total_tokens: number - }>(`/admin/users/${id}/usage`, { - params: { period } - }) - return data -} - /** * Balance history item returned from the API */ @@ -258,7 +234,6 @@ export const usersAPI = { updateConcurrency, toggleStatus, getUserApiKeys, - getUserUsageStats, getUserBalanceHistory, replaceGroup }