mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 20:12:39 +08:00
102 lines
3.5 KiB
Go
102 lines
3.5 KiB
Go
package admin
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
|
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type openAIReferralService interface {
|
|
QueryReferralEligibility(context.Context, int64) (*service.OpenAIReferralEligibility, error)
|
|
CacheReferralSnapshot(context.Context, int64, *service.OpenAIReferralEligibility) error
|
|
SendReferralInvite(context.Context, int64, service.OpenAIReferralSendRequest) (*service.OpenAIReferralSendResult, error)
|
|
}
|
|
|
|
type openAIReferralRefreshResponse struct {
|
|
Eligibility *service.OpenAIReferralEligibility `json:"eligibility"`
|
|
CachePersisted bool `json:"cache_persisted"`
|
|
}
|
|
|
|
type openAIReferralSendResponse struct {
|
|
service.OpenAIReferralSendResult
|
|
openAIReferralRefreshResponse
|
|
RefreshFailed bool `json:"refresh_failed"`
|
|
}
|
|
|
|
func (h *OpenAIOAuthHandler) referralAccountID(c *gin.Context) (int64, bool) {
|
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
|
if err != nil || id <= 0 {
|
|
response.BadRequest(c, "Invalid account ID")
|
|
return 0, false
|
|
}
|
|
if h.referralService == nil {
|
|
response.BadRequest(c, "OpenAI referral service is not enabled")
|
|
return 0, false
|
|
}
|
|
return id, true
|
|
}
|
|
|
|
// RefreshReferrals persists a display snapshot, hence POST and admin audit.
|
|
func (h *OpenAIOAuthHandler) RefreshReferrals(c *gin.Context) {
|
|
id, ok := h.referralAccountID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
eligibility, err := h.referralService.QueryReferralEligibility(c.Request.Context(), id)
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
if eligibility == nil {
|
|
response.Error(c, http.StatusBadGateway, "Empty invitation eligibility response")
|
|
return
|
|
}
|
|
cacheErr := h.referralService.CacheReferralSnapshot(c.Request.Context(), id, eligibility)
|
|
response.Success(c, openAIReferralRefreshResponse{Eligibility: eligibility, CachePersisted: cacheErr == nil})
|
|
}
|
|
|
|
func (h *OpenAIOAuthHandler) SendReferralInvite(c *gin.Context) {
|
|
id, ok := h.referralAccountID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var input service.OpenAIReferralSendRequest
|
|
if err := c.ShouldBindJSON(&input); err != nil {
|
|
response.BadRequest(c, "Invalid invitation request")
|
|
return
|
|
}
|
|
result, err := h.referralService.SendReferralInvite(c.Request.Context(), id, input)
|
|
if err != nil {
|
|
response.ErrorFrom(c, err)
|
|
return
|
|
}
|
|
if result == nil || !result.Sent {
|
|
response.Error(c, http.StatusBadGateway, "Invitation outcome is unknown; check Codex before sending again")
|
|
return
|
|
}
|
|
// The email is already sent. Refresh failure must not turn it into a failed
|
|
// submission and encourage a duplicate send, even if the browser disconnects.
|
|
baseCtx := context.WithoutCancel(c.Request.Context())
|
|
refreshCtx, cancelRefresh := context.WithTimeout(baseCtx, 8*time.Second)
|
|
eligibility, refreshErr := h.referralService.QueryReferralEligibility(refreshCtx, id)
|
|
cancelRefresh()
|
|
if refreshErr != nil {
|
|
eligibility = nil
|
|
}
|
|
// Refresh may exhaust its entire deadline. Give persistence (including
|
|
// invalidating a stale snapshot) a fresh, independent deadline.
|
|
cacheCtx, cancelCache := context.WithTimeout(baseCtx, 3*time.Second)
|
|
defer cancelCache()
|
|
cacheErr := h.referralService.CacheReferralSnapshot(cacheCtx, id, eligibility)
|
|
response.Success(c, openAIReferralSendResponse{
|
|
OpenAIReferralSendResult: *result,
|
|
openAIReferralRefreshResponse: openAIReferralRefreshResponse{Eligibility: eligibility, CachePersisted: cacheErr == nil},
|
|
RefreshFailed: eligibility == nil,
|
|
})
|
|
}
|