229 lines
6.3 KiB
Go
229 lines
6.3 KiB
Go
package admin
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
|
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// OpenAIOAuthHandler handles OpenAI OAuth-related operations
|
|
type OpenAIOAuthHandler struct {
|
|
openaiOAuthService *service.OpenAIOAuthService
|
|
adminService service.AdminService
|
|
}
|
|
|
|
// NewOpenAIOAuthHandler creates a new OpenAI OAuth handler
|
|
func NewOpenAIOAuthHandler(openaiOAuthService *service.OpenAIOAuthService, adminService service.AdminService) *OpenAIOAuthHandler {
|
|
return &OpenAIOAuthHandler{
|
|
openaiOAuthService: openaiOAuthService,
|
|
adminService: adminService,
|
|
}
|
|
}
|
|
|
|
// OpenAIGenerateAuthURLRequest represents the request for generating OpenAI auth URL
|
|
type OpenAIGenerateAuthURLRequest struct {
|
|
ProxyID *int64 `json:"proxy_id"`
|
|
RedirectURI string `json:"redirect_uri"`
|
|
}
|
|
|
|
// GenerateAuthURL generates OpenAI OAuth authorization URL
|
|
// POST /api/v1/admin/openai/generate-auth-url
|
|
func (h *OpenAIOAuthHandler) GenerateAuthURL(c *gin.Context) {
|
|
var req OpenAIGenerateAuthURLRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
// Allow empty body
|
|
req = OpenAIGenerateAuthURLRequest{}
|
|
}
|
|
|
|
result, err := h.openaiOAuthService.GenerateAuthURL(c.Request.Context(), req.ProxyID, req.RedirectURI)
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
response.Success(c, result)
|
|
}
|
|
|
|
// OpenAIExchangeCodeRequest represents the request for exchanging OpenAI auth code
|
|
type OpenAIExchangeCodeRequest struct {
|
|
SessionID string `json:"session_id" binding:"required"`
|
|
Code string `json:"code" binding:"required"`
|
|
RedirectURI string `json:"redirect_uri"`
|
|
ProxyID *int64 `json:"proxy_id"`
|
|
}
|
|
|
|
// ExchangeCode exchanges OpenAI authorization code for tokens
|
|
// POST /api/v1/admin/openai/exchange-code
|
|
func (h *OpenAIOAuthHandler) ExchangeCode(c *gin.Context) {
|
|
var req OpenAIExchangeCodeRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
tokenInfo, err := h.openaiOAuthService.ExchangeCode(c.Request.Context(), &service.OpenAIExchangeCodeInput{
|
|
SessionID: req.SessionID,
|
|
Code: req.Code,
|
|
RedirectURI: req.RedirectURI,
|
|
ProxyID: req.ProxyID,
|
|
})
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
response.Success(c, tokenInfo)
|
|
}
|
|
|
|
// OpenAIRefreshTokenRequest represents the request for refreshing OpenAI token
|
|
type OpenAIRefreshTokenRequest struct {
|
|
RefreshToken string `json:"refresh_token" binding:"required"`
|
|
ProxyID *int64 `json:"proxy_id"`
|
|
}
|
|
|
|
// RefreshToken refreshes an OpenAI OAuth token
|
|
// POST /api/v1/admin/openai/refresh-token
|
|
func (h *OpenAIOAuthHandler) RefreshToken(c *gin.Context) {
|
|
var req OpenAIRefreshTokenRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
var proxyURL string
|
|
if req.ProxyID != nil {
|
|
proxy, err := h.adminService.GetProxy(c.Request.Context(), *req.ProxyID)
|
|
if err == nil && proxy != nil {
|
|
proxyURL = proxy.URL()
|
|
}
|
|
}
|
|
|
|
tokenInfo, err := h.openaiOAuthService.RefreshToken(c.Request.Context(), req.RefreshToken, proxyURL)
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
response.Success(c, tokenInfo)
|
|
}
|
|
|
|
// RefreshAccountToken refreshes token for a specific OpenAI account
|
|
// POST /api/v1/admin/openai/accounts/:id/refresh
|
|
func (h *OpenAIOAuthHandler) RefreshAccountToken(c *gin.Context) {
|
|
accountID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
response.BadRequest(c, "Invalid account ID")
|
|
return
|
|
}
|
|
|
|
// Get account
|
|
account, err := h.adminService.GetAccount(c.Request.Context(), accountID)
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
// Ensure account is OpenAI platform
|
|
if !account.IsOpenAI() {
|
|
response.BadRequest(c, "Account is not an OpenAI account")
|
|
return
|
|
}
|
|
|
|
// Only refresh OAuth-based accounts
|
|
if !account.IsOAuth() {
|
|
response.BadRequest(c, "Cannot refresh non-OAuth account credentials")
|
|
return
|
|
}
|
|
|
|
// Use OpenAI OAuth service to refresh token
|
|
tokenInfo, err := h.openaiOAuthService.RefreshAccountToken(c.Request.Context(), account)
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
// Build new credentials from token info
|
|
newCredentials := h.openaiOAuthService.BuildAccountCredentials(tokenInfo)
|
|
|
|
// Preserve non-token settings from existing credentials
|
|
for k, v := range account.Credentials {
|
|
if _, exists := newCredentials[k]; !exists {
|
|
newCredentials[k] = v
|
|
}
|
|
}
|
|
|
|
updatedAccount, err := h.adminService.UpdateAccount(c.Request.Context(), accountID, &service.UpdateAccountInput{
|
|
Credentials: newCredentials,
|
|
})
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
response.Success(c, updatedAccount)
|
|
}
|
|
|
|
// CreateAccountFromOAuth creates a new OpenAI OAuth account from token info
|
|
// POST /api/v1/admin/openai/create-from-oauth
|
|
func (h *OpenAIOAuthHandler) CreateAccountFromOAuth(c *gin.Context) {
|
|
var req struct {
|
|
SessionID string `json:"session_id" binding:"required"`
|
|
Code string `json:"code" binding:"required"`
|
|
RedirectURI string `json:"redirect_uri"`
|
|
ProxyID *int64 `json:"proxy_id"`
|
|
Name string `json:"name"`
|
|
Concurrency int `json:"concurrency"`
|
|
Priority int `json:"priority"`
|
|
GroupIDs []int64 `json:"group_ids"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Exchange code for tokens
|
|
tokenInfo, err := h.openaiOAuthService.ExchangeCode(c.Request.Context(), &service.OpenAIExchangeCodeInput{
|
|
SessionID: req.SessionID,
|
|
Code: req.Code,
|
|
RedirectURI: req.RedirectURI,
|
|
ProxyID: req.ProxyID,
|
|
})
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
// Build credentials from token info
|
|
credentials := h.openaiOAuthService.BuildAccountCredentials(tokenInfo)
|
|
|
|
// Use email as default name if not provided
|
|
name := req.Name
|
|
if name == "" && tokenInfo.Email != "" {
|
|
name = tokenInfo.Email
|
|
}
|
|
if name == "" {
|
|
name = "OpenAI OAuth Account"
|
|
}
|
|
|
|
// Create account
|
|
account, err := h.adminService.CreateAccount(c.Request.Context(), &service.CreateAccountInput{
|
|
Name: name,
|
|
Platform: "openai",
|
|
Type: "oauth",
|
|
Credentials: credentials,
|
|
ProxyID: req.ProxyID,
|
|
Concurrency: req.Concurrency,
|
|
Priority: req.Priority,
|
|
GroupIDs: req.GroupIDs,
|
|
})
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
|
|
response.Success(c, account)
|
|
}
|