package handler import ( "strconv" "github.com/Wei-Shaw/sub2api/internal/handler/dto" "github.com/Wei-Shaw/sub2api/internal/pkg/pagination" "github.com/Wei-Shaw/sub2api/internal/pkg/response" middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware" "github.com/Wei-Shaw/sub2api/internal/service" "github.com/gin-gonic/gin" ) // APIKeyHandler handles API key-related requests type APIKeyHandler struct { apiKeyService *service.APIKeyService } // NewAPIKeyHandler creates a new APIKeyHandler func NewAPIKeyHandler(apiKeyService *service.APIKeyService) *APIKeyHandler { return &APIKeyHandler{ apiKeyService: apiKeyService, } } // CreateAPIKeyRequest represents the create API key request payload type CreateAPIKeyRequest struct { Name string `json:"name" binding:"required"` GroupID *int64 `json:"group_id"` // nullable CustomKey *string `json:"custom_key"` // 可选的自定义key } // UpdateAPIKeyRequest represents the update API key request payload type UpdateAPIKeyRequest struct { Name string `json:"name"` GroupID *int64 `json:"group_id"` Status string `json:"status" binding:"omitempty,oneof=active inactive"` } // List handles listing user's API keys with pagination // GET /api/v1/api-keys func (h *APIKeyHandler) List(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not authenticated") return } page, pageSize := response.ParsePagination(c) params := pagination.PaginationParams{Page: page, PageSize: pageSize} keys, result, err := h.apiKeyService.List(c.Request.Context(), subject.UserID, params) if err != nil { response.ErrorFrom(c, err) return } out := make([]dto.APIKey, 0, len(keys)) for i := range keys { out = append(out, *dto.APIKeyFromService(&keys[i])) } response.Paginated(c, out, result.Total, page, pageSize) } // GetByID handles getting a single API key // GET /api/v1/api-keys/:id func (h *APIKeyHandler) GetByID(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not authenticated") return } keyID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { response.BadRequest(c, "Invalid key ID") return } key, err := h.apiKeyService.GetByID(c.Request.Context(), keyID) if err != nil { response.ErrorFrom(c, err) return } // 验证所有权 if key.UserID != subject.UserID { response.Forbidden(c, "Not authorized to access this key") return } response.Success(c, dto.APIKeyFromService(key)) } // Create handles creating a new API key // POST /api/v1/api-keys func (h *APIKeyHandler) Create(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not authenticated") return } var req CreateAPIKeyRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "Invalid request: "+err.Error()) return } svcReq := service.CreateAPIKeyRequest{ Name: req.Name, GroupID: req.GroupID, CustomKey: req.CustomKey, } key, err := h.apiKeyService.Create(c.Request.Context(), subject.UserID, svcReq) if err != nil { response.ErrorFrom(c, err) return } response.Success(c, dto.APIKeyFromService(key)) } // Update handles updating an API key // PUT /api/v1/api-keys/:id func (h *APIKeyHandler) Update(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not authenticated") return } keyID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { response.BadRequest(c, "Invalid key ID") return } var req UpdateAPIKeyRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "Invalid request: "+err.Error()) return } svcReq := service.UpdateAPIKeyRequest{} if req.Name != "" { svcReq.Name = &req.Name } svcReq.GroupID = req.GroupID if req.Status != "" { svcReq.Status = &req.Status } key, err := h.apiKeyService.Update(c.Request.Context(), keyID, subject.UserID, svcReq) if err != nil { response.ErrorFrom(c, err) return } response.Success(c, dto.APIKeyFromService(key)) } // Delete handles deleting an API key // DELETE /api/v1/api-keys/:id func (h *APIKeyHandler) Delete(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not authenticated") return } keyID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { response.BadRequest(c, "Invalid key ID") return } err = h.apiKeyService.Delete(c.Request.Context(), keyID, subject.UserID) if err != nil { response.ErrorFrom(c, err) return } response.Success(c, gin.H{"message": "API key deleted successfully"}) } // GetAvailableGroups 获取用户可以绑定的分组列表 // GET /api/v1/groups/available func (h *APIKeyHandler) GetAvailableGroups(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not authenticated") return } groups, err := h.apiKeyService.GetAvailableGroups(c.Request.Context(), subject.UserID) if err != nil { response.ErrorFrom(c, err) return } out := make([]dto.Group, 0, len(groups)) for i := range groups { out = append(out, *dto.GroupFromService(&groups[i])) } response.Success(c, out) }