209 lines
5.2 KiB
Go
209 lines
5.2 KiB
Go
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)
|
|
}
|