Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
eeaff85e
Commit
eeaff85e
authored
Dec 25, 2025
by
Forest
Browse files
refactor: 自定义业务错误
parent
f51ad2e1
Changes
60
Hide whitespace changes
Inline
Side-by-side
backend/.golangci.yml
View file @
eeaff85e
...
...
@@ -19,14 +19,16 @@ linters:
files
:
-
"
**/internal/service/**"
deny
:
-
pkg
:
sub2api/internal/repository
-
pkg
:
github.com/Wei-Shaw/
sub2api/internal/repository
desc
:
"
service
must
not
import
repository"
-
pkg
:
gorm.io/gorm
desc
:
"
service
must
not
import
gorm"
handler-no-repository
:
list-mode
:
original
files
:
-
"
**/internal/handler/**"
deny
:
-
pkg
:
sub2api/internal/repository
-
pkg
:
github.com/Wei-Shaw/
sub2api/internal/repository
desc
:
"
handler
must
not
import
repository"
errcheck
:
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
...
...
backend/internal/handler/admin/account_handler.go
View file @
eeaff85e
...
...
@@ -117,7 +117,7 @@ func (h *AccountHandler) List(c *gin.Context) {
accounts
,
total
,
err
:=
h
.
adminService
.
ListAccounts
(
c
.
Request
.
Context
(),
page
,
pageSize
,
platform
,
accountType
,
status
,
search
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list accounts: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -156,7 +156,7 @@ func (h *AccountHandler) GetByID(c *gin.Context) {
account
,
err
:=
h
.
adminService
.
GetAccount
(
c
.
Request
.
Context
(),
accountID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"Account not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -184,7 +184,7 @@ func (h *AccountHandler) Create(c *gin.Context) {
GroupIDs
:
req
.
GroupIDs
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to create account: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -218,7 +218,7 @@ func (h *AccountHandler) Update(c *gin.Context) {
GroupIDs
:
req
.
GroupIDs
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update account: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -236,7 +236,7 @@ func (h *AccountHandler) Delete(c *gin.Context) {
err
=
h
.
adminService
.
DeleteAccount
(
c
.
Request
.
Context
(),
accountID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to delete account: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -297,7 +297,7 @@ func (h *AccountHandler) SyncFromCRS(c *gin.Context) {
SyncProxies
:
syncProxies
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Sync failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -332,7 +332,7 @@ func (h *AccountHandler) Refresh(c *gin.Context) {
// Use OpenAI OAuth service to refresh token
tokenInfo
,
err
:=
h
.
openaiOAuthService
.
RefreshAccountToken
(
c
.
Request
.
Context
(),
account
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to refresh credentials: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -349,7 +349,7 @@ func (h *AccountHandler) Refresh(c *gin.Context) {
// Use Anthropic/Claude OAuth service to refresh token
tokenInfo
,
err
:=
h
.
oauthService
.
RefreshAccountToken
(
c
.
Request
.
Context
(),
account
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to refresh credentials: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -372,7 +372,7 @@ func (h *AccountHandler) Refresh(c *gin.Context) {
Credentials
:
newCredentials
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update account credentials: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -403,7 +403,7 @@ func (h *AccountHandler) GetStats(c *gin.Context) {
stats
,
err
:=
h
.
accountUsageService
.
GetAccountUsageStats
(
c
.
Request
.
Context
(),
accountID
,
startTime
,
endTime
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get account stats: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -421,7 +421,7 @@ func (h *AccountHandler) ClearError(c *gin.Context) {
account
,
err
:=
h
.
adminService
.
ClearAccountError
(
c
.
Request
.
Context
(),
accountID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to clear error: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -570,7 +570,7 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
Extra
:
req
.
Extra
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to bulk update accounts: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -595,7 +595,7 @@ func (h *OAuthHandler) GenerateAuthURL(c *gin.Context) {
result
,
err
:=
h
.
oauthService
.
GenerateAuthURL
(
c
.
Request
.
Context
(),
req
.
ProxyID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to generate auth URL: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -613,7 +613,7 @@ func (h *OAuthHandler) GenerateSetupTokenURL(c *gin.Context) {
result
,
err
:=
h
.
oauthService
.
GenerateSetupTokenURL
(
c
.
Request
.
Context
(),
req
.
ProxyID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to generate setup token URL: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -642,7 +642,7 @@ func (h *OAuthHandler) ExchangeCode(c *gin.Context) {
ProxyID
:
req
.
ProxyID
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to exchange code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -664,7 +664,7 @@ func (h *OAuthHandler) ExchangeSetupTokenCode(c *gin.Context) {
ProxyID
:
req
.
ProxyID
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to exchange code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -692,7 +692,7 @@ func (h *OAuthHandler) CookieAuth(c *gin.Context) {
Scope
:
"full"
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Cookie auth failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -714,7 +714,7 @@ func (h *OAuthHandler) SetupTokenCookieAuth(c *gin.Context) {
Scope
:
"inference"
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Cookie auth failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -732,7 +732,7 @@ func (h *AccountHandler) GetUsage(c *gin.Context) {
usage
,
err
:=
h
.
accountUsageService
.
GetUsage
(
c
.
Request
.
Context
(),
accountID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get usage: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -750,7 +750,7 @@ func (h *AccountHandler) ClearRateLimit(c *gin.Context) {
err
=
h
.
rateLimitService
.
ClearRateLimit
(
c
.
Request
.
Context
(),
accountID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to clear rate limit: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -768,7 +768,7 @@ func (h *AccountHandler) GetTodayStats(c *gin.Context) {
stats
,
err
:=
h
.
accountUsageService
.
GetTodayStats
(
c
.
Request
.
Context
(),
accountID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get today stats: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -797,7 +797,7 @@ func (h *AccountHandler) SetSchedulable(c *gin.Context) {
account
,
err
:=
h
.
adminService
.
SetAccountSchedulable
(
c
.
Request
.
Context
(),
accountID
,
req
.
Schedulable
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update schedulable status: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/group_handler.go
View file @
eeaff85e
...
...
@@ -65,7 +65,7 @@ func (h *GroupHandler) List(c *gin.Context) {
groups
,
total
,
err
:=
h
.
adminService
.
ListGroups
(
c
.
Request
.
Context
(),
page
,
pageSize
,
platform
,
status
,
isExclusive
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list groups: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -87,7 +87,7 @@ func (h *GroupHandler) GetAll(c *gin.Context) {
}
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get groups: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -105,7 +105,7 @@ func (h *GroupHandler) GetByID(c *gin.Context) {
group
,
err
:=
h
.
adminService
.
GetGroup
(
c
.
Request
.
Context
(),
groupID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"Group not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -133,7 +133,7 @@ func (h *GroupHandler) Create(c *gin.Context) {
MonthlyLimitUSD
:
req
.
MonthlyLimitUSD
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to create group: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -168,7 +168,7 @@ func (h *GroupHandler) Update(c *gin.Context) {
MonthlyLimitUSD
:
req
.
MonthlyLimitUSD
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update group: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -186,7 +186,7 @@ func (h *GroupHandler) Delete(c *gin.Context) {
err
=
h
.
adminService
.
DeleteGroup
(
c
.
Request
.
Context
(),
groupID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to delete group: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -225,7 +225,7 @@ func (h *GroupHandler) GetGroupAPIKeys(c *gin.Context) {
keys
,
total
,
err
:=
h
.
adminService
.
GetGroupAPIKeys
(
c
.
Request
.
Context
(),
groupID
,
page
,
pageSize
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get group API keys: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/openai_oauth_handler.go
View file @
eeaff85e
...
...
@@ -40,7 +40,7 @@ func (h *OpenAIOAuthHandler) GenerateAuthURL(c *gin.Context) {
result
,
err
:=
h
.
openaiOAuthService
.
GenerateAuthURL
(
c
.
Request
.
Context
(),
req
.
ProxyID
,
req
.
RedirectURI
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to generate auth URL: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -71,7 +71,7 @@ func (h *OpenAIOAuthHandler) ExchangeCode(c *gin.Context) {
ProxyID
:
req
.
ProxyID
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to exchange code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -103,7 +103,7 @@ func (h *OpenAIOAuthHandler) RefreshToken(c *gin.Context) {
tokenInfo
,
err
:=
h
.
openaiOAuthService
.
RefreshToken
(
c
.
Request
.
Context
(),
req
.
RefreshToken
,
proxyURL
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to refresh token: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -122,7 +122,7 @@ func (h *OpenAIOAuthHandler) RefreshAccountToken(c *gin.Context) {
// Get account
account
,
err
:=
h
.
adminService
.
GetAccount
(
c
.
Request
.
Context
(),
accountID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"Account not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -141,7 +141,7 @@ func (h *OpenAIOAuthHandler) RefreshAccountToken(c *gin.Context) {
// Use OpenAI OAuth service to refresh token
tokenInfo
,
err
:=
h
.
openaiOAuthService
.
RefreshAccountToken
(
c
.
Request
.
Context
(),
account
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to refresh credentials: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -159,7 +159,7 @@ func (h *OpenAIOAuthHandler) RefreshAccountToken(c *gin.Context) {
Credentials
:
newCredentials
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update account credentials: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -192,7 +192,7 @@ func (h *OpenAIOAuthHandler) CreateAccountFromOAuth(c *gin.Context) {
ProxyID
:
req
.
ProxyID
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to exchange code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -220,7 +220,7 @@ func (h *OpenAIOAuthHandler) CreateAccountFromOAuth(c *gin.Context) {
GroupIDs
:
req
.
GroupIDs
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to create account: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/proxy_handler.go
View file @
eeaff85e
...
...
@@ -53,7 +53,7 @@ func (h *ProxyHandler) List(c *gin.Context) {
proxies
,
total
,
err
:=
h
.
adminService
.
ListProxies
(
c
.
Request
.
Context
(),
page
,
pageSize
,
protocol
,
status
,
search
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list proxies: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -69,7 +69,7 @@ func (h *ProxyHandler) GetAll(c *gin.Context) {
if
withCount
{
proxies
,
err
:=
h
.
adminService
.
GetAllProxiesWithAccountCount
(
c
.
Request
.
Context
())
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get proxies: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
proxies
)
...
...
@@ -78,7 +78,7 @@ func (h *ProxyHandler) GetAll(c *gin.Context) {
proxies
,
err
:=
h
.
adminService
.
GetAllProxies
(
c
.
Request
.
Context
())
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get proxies: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -96,7 +96,7 @@ func (h *ProxyHandler) GetByID(c *gin.Context) {
proxy
,
err
:=
h
.
adminService
.
GetProxy
(
c
.
Request
.
Context
(),
proxyID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"Proxy not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -121,7 +121,7 @@ func (h *ProxyHandler) Create(c *gin.Context) {
Password
:
strings
.
TrimSpace
(
req
.
Password
),
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to create proxy: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -153,7 +153,7 @@ func (h *ProxyHandler) Update(c *gin.Context) {
Status
:
strings
.
TrimSpace
(
req
.
Status
),
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update proxy: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -171,7 +171,7 @@ func (h *ProxyHandler) Delete(c *gin.Context) {
err
=
h
.
adminService
.
DeleteProxy
(
c
.
Request
.
Context
(),
proxyID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to delete proxy: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -189,7 +189,7 @@ func (h *ProxyHandler) Test(c *gin.Context) {
result
,
err
:=
h
.
adminService
.
TestProxy
(
c
.
Request
.
Context
(),
proxyID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to test proxy: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -229,7 +229,7 @@ func (h *ProxyHandler) GetProxyAccounts(c *gin.Context) {
accounts
,
total
,
err
:=
h
.
adminService
.
GetProxyAccounts
(
c
.
Request
.
Context
(),
proxyID
,
page
,
pageSize
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get proxy accounts: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -272,7 +272,7 @@ func (h *ProxyHandler) BatchCreate(c *gin.Context) {
// Check for duplicates (same host, port, username, password)
exists
,
err
:=
h
.
adminService
.
CheckProxyExists
(
c
.
Request
.
Context
(),
host
,
item
.
Port
,
username
,
password
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to check proxy existence: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/redeem_handler.go
View file @
eeaff85e
...
...
@@ -43,7 +43,7 @@ func (h *RedeemHandler) List(c *gin.Context) {
codes
,
total
,
err
:=
h
.
adminService
.
ListRedeemCodes
(
c
.
Request
.
Context
(),
page
,
pageSize
,
codeType
,
status
,
search
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list redeem codes: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -61,7 +61,7 @@ func (h *RedeemHandler) GetByID(c *gin.Context) {
code
,
err
:=
h
.
adminService
.
GetRedeemCode
(
c
.
Request
.
Context
(),
codeID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"Redeem code not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -85,7 +85,7 @@ func (h *RedeemHandler) Generate(c *gin.Context) {
ValidityDays
:
req
.
ValidityDays
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to generate redeem codes: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -103,7 +103,7 @@ func (h *RedeemHandler) Delete(c *gin.Context) {
err
=
h
.
adminService
.
DeleteRedeemCode
(
c
.
Request
.
Context
(),
codeID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to delete redeem code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -123,7 +123,7 @@ func (h *RedeemHandler) BatchDelete(c *gin.Context) {
deleted
,
err
:=
h
.
adminService
.
BatchDeleteRedeemCodes
(
c
.
Request
.
Context
(),
req
.
IDs
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to batch delete redeem codes: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -144,7 +144,7 @@ func (h *RedeemHandler) Expire(c *gin.Context) {
code
,
err
:=
h
.
adminService
.
ExpireRedeemCode
(
c
.
Request
.
Context
(),
codeID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to expire redeem code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -178,7 +178,7 @@ func (h *RedeemHandler) Export(c *gin.Context) {
// Get all codes without pagination (use large page size)
codes
,
_
,
err
:=
h
.
adminService
.
ListRedeemCodes
(
c
.
Request
.
Context
(),
1
,
10000
,
codeType
,
status
,
""
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to export redeem codes: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/setting_handler.go
View file @
eeaff85e
...
...
@@ -27,7 +27,7 @@ func NewSettingHandler(settingService *service.SettingService, emailService *ser
func
(
h
*
SettingHandler
)
GetSettings
(
c
*
gin
.
Context
)
{
settings
,
err
:=
h
.
settingService
.
GetAllSettings
(
c
.
Request
.
Context
())
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get settings: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -111,14 +111,14 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
}
if
err
:=
h
.
settingService
.
UpdateSettings
(
c
.
Request
.
Context
(),
settings
);
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update settings: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
// 重新获取设置返回
updatedSettings
,
err
:=
h
.
settingService
.
GetAllSettings
(
c
.
Request
.
Context
())
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get updated settings: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -166,7 +166,7 @@ func (h *SettingHandler) TestSmtpConnection(c *gin.Context) {
err
:=
h
.
emailService
.
TestSmtpConnectionWithConfig
(
config
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"SMTP connection test failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -252,7 +252,7 @@ func (h *SettingHandler) SendTestEmail(c *gin.Context) {
`
if
err
:=
h
.
emailService
.
SendEmailWithConfig
(
config
,
req
.
Email
,
subject
,
body
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to send test email: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -264,7 +264,7 @@ func (h *SettingHandler) SendTestEmail(c *gin.Context) {
func
(
h
*
SettingHandler
)
GetAdminApiKey
(
c
*
gin
.
Context
)
{
maskedKey
,
exists
,
err
:=
h
.
settingService
.
GetAdminApiKeyStatus
(
c
.
Request
.
Context
())
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get admin API key status: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -279,7 +279,7 @@ func (h *SettingHandler) GetAdminApiKey(c *gin.Context) {
func
(
h
*
SettingHandler
)
RegenerateAdminApiKey
(
c
*
gin
.
Context
)
{
key
,
err
:=
h
.
settingService
.
GenerateAdminApiKey
(
c
.
Request
.
Context
())
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to generate admin API key: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -292,7 +292,7 @@ func (h *SettingHandler) RegenerateAdminApiKey(c *gin.Context) {
// DELETE /api/v1/admin/settings/admin-api-key
func
(
h
*
SettingHandler
)
DeleteAdminApiKey
(
c
*
gin
.
Context
)
{
if
err
:=
h
.
settingService
.
DeleteAdminApiKey
(
c
.
Request
.
Context
());
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to delete admin API key: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/subscription_handler.go
View file @
eeaff85e
...
...
@@ -78,7 +78,7 @@ func (h *SubscriptionHandler) List(c *gin.Context) {
subscriptions
,
pagination
,
err
:=
h
.
subscriptionService
.
List
(
c
.
Request
.
Context
(),
page
,
pageSize
,
userID
,
groupID
,
status
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -96,7 +96,7 @@ func (h *SubscriptionHandler) GetByID(c *gin.Context) {
subscription
,
err
:=
h
.
subscriptionService
.
GetByID
(
c
.
Request
.
Context
(),
subscriptionID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"Subscription not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -141,7 +141,7 @@ func (h *SubscriptionHandler) Assign(c *gin.Context) {
Notes
:
req
.
Notes
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to assign subscription: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -168,7 +168,7 @@ func (h *SubscriptionHandler) BulkAssign(c *gin.Context) {
Notes
:
req
.
Notes
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to bulk assign subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -192,7 +192,7 @@ func (h *SubscriptionHandler) Extend(c *gin.Context) {
subscription
,
err
:=
h
.
subscriptionService
.
ExtendSubscription
(
c
.
Request
.
Context
(),
subscriptionID
,
req
.
Days
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to extend subscription: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -210,7 +210,7 @@ func (h *SubscriptionHandler) Revoke(c *gin.Context) {
err
=
h
.
subscriptionService
.
RevokeSubscription
(
c
.
Request
.
Context
(),
subscriptionID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to revoke subscription: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -230,7 +230,7 @@ func (h *SubscriptionHandler) ListByGroup(c *gin.Context) {
subscriptions
,
pagination
,
err
:=
h
.
subscriptionService
.
ListGroupSubscriptions
(
c
.
Request
.
Context
(),
groupID
,
page
,
pageSize
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list group subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -248,7 +248,7 @@ func (h *SubscriptionHandler) ListByUser(c *gin.Context) {
subscriptions
,
err
:=
h
.
subscriptionService
.
ListUserSubscriptions
(
c
.
Request
.
Context
(),
userID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list user subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/usage_handler.go
View file @
eeaff85e
...
...
@@ -90,7 +90,7 @@ func (h *UsageHandler) List(c *gin.Context) {
records
,
result
,
err
:=
h
.
usageService
.
ListWithFilters
(
c
.
Request
.
Context
(),
params
,
filters
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list usage records: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -158,7 +158,7 @@ func (h *UsageHandler) Stats(c *gin.Context) {
if
apiKeyID
>
0
{
stats
,
err
:=
h
.
usageService
.
GetStatsByApiKey
(
c
.
Request
.
Context
(),
apiKeyID
,
startTime
,
endTime
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get usage statistics: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
stats
)
...
...
@@ -168,7 +168,7 @@ func (h *UsageHandler) Stats(c *gin.Context) {
if
userID
>
0
{
stats
,
err
:=
h
.
usageService
.
GetStatsByUser
(
c
.
Request
.
Context
(),
userID
,
startTime
,
endTime
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get usage statistics: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
stats
)
...
...
@@ -178,7 +178,7 @@ func (h *UsageHandler) Stats(c *gin.Context) {
// Get global stats
stats
,
err
:=
h
.
usageService
.
GetGlobalStats
(
c
.
Request
.
Context
(),
startTime
,
endTime
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get usage statistics: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -197,7 +197,7 @@ func (h *UsageHandler) SearchUsers(c *gin.Context) {
// Limit to 30 results
users
,
_
,
err
:=
h
.
adminService
.
ListUsers
(
c
.
Request
.
Context
(),
1
,
30
,
""
,
""
,
keyword
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to search users: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -236,7 +236,7 @@ func (h *UsageHandler) SearchApiKeys(c *gin.Context) {
keys
,
err
:=
h
.
apiKeyService
.
SearchApiKeys
(
c
.
Request
.
Context
(),
userID
,
keyword
,
30
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to search API keys: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/user_handler.go
View file @
eeaff85e
...
...
@@ -64,7 +64,7 @@ func (h *UserHandler) List(c *gin.Context) {
users
,
total
,
err
:=
h
.
adminService
.
ListUsers
(
c
.
Request
.
Context
(),
page
,
pageSize
,
status
,
role
,
search
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list users: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -82,7 +82,7 @@ func (h *UserHandler) GetByID(c *gin.Context) {
user
,
err
:=
h
.
adminService
.
GetUser
(
c
.
Request
.
Context
(),
userID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"User not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -109,7 +109,7 @@ func (h *UserHandler) Create(c *gin.Context) {
AllowedGroups
:
req
.
AllowedGroups
,
})
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to create user: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -144,7 +144,7 @@ func (h *UserHandler) Update(c *gin.Context) {
AllowedGroups
:
req
.
AllowedGroups
,
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update user: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -162,7 +162,7 @@ func (h *UserHandler) Delete(c *gin.Context) {
err
=
h
.
adminService
.
DeleteUser
(
c
.
Request
.
Context
(),
userID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to delete user: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -186,7 +186,7 @@ func (h *UserHandler) UpdateBalance(c *gin.Context) {
user
,
err
:=
h
.
adminService
.
UpdateUserBalance
(
c
.
Request
.
Context
(),
userID
,
req
.
Balance
,
req
.
Operation
,
req
.
Notes
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update balance: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -206,7 +206,7 @@ func (h *UserHandler) GetUserAPIKeys(c *gin.Context) {
keys
,
total
,
err
:=
h
.
adminService
.
GetUserAPIKeys
(
c
.
Request
.
Context
(),
userID
,
page
,
pageSize
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get user API keys: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -226,7 +226,7 @@ func (h *UserHandler) GetUserUsage(c *gin.Context) {
stats
,
err
:=
h
.
adminService
.
GetUserUsageStats
(
c
.
Request
.
Context
(),
userID
,
period
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get user usage: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/api_key_handler.go
View file @
eeaff85e
...
...
@@ -57,7 +57,7 @@ func (h *APIKeyHandler) List(c *gin.Context) {
keys
,
result
,
err
:=
h
.
apiKeyService
.
List
(
c
.
Request
.
Context
(),
user
.
ID
,
params
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list API keys: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -87,7 +87,7 @@ func (h *APIKeyHandler) GetByID(c *gin.Context) {
key
,
err
:=
h
.
apiKeyService
.
GetByID
(
c
.
Request
.
Context
(),
keyID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"API key not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -128,7 +128,7 @@ func (h *APIKeyHandler) Create(c *gin.Context) {
}
key
,
err
:=
h
.
apiKeyService
.
Create
(
c
.
Request
.
Context
(),
user
.
ID
,
svcReq
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to create API key: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -173,7 +173,7 @@ func (h *APIKeyHandler) Update(c *gin.Context) {
key
,
err
:=
h
.
apiKeyService
.
Update
(
c
.
Request
.
Context
(),
keyID
,
user
.
ID
,
svcReq
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to update API key: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -203,7 +203,7 @@ func (h *APIKeyHandler) Delete(c *gin.Context) {
err
=
h
.
apiKeyService
.
Delete
(
c
.
Request
.
Context
(),
keyID
,
user
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to delete API key: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -227,7 +227,7 @@ func (h *APIKeyHandler) GetAvailableGroups(c *gin.Context) {
groups
,
err
:=
h
.
apiKeyService
.
GetAvailableGroups
(
c
.
Request
.
Context
(),
user
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get available groups: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/auth_handler.go
View file @
eeaff85e
...
...
@@ -66,14 +66,14 @@ func (h *AuthHandler) Register(c *gin.Context) {
// Turnstile 验证(当提供了邮箱验证码时跳过,因为发送验证码时已验证过)
if
req
.
VerifyCode
==
""
{
if
err
:=
h
.
authService
.
VerifyTurnstile
(
c
.
Request
.
Context
(),
req
.
TurnstileToken
,
c
.
ClientIP
());
err
!=
nil
{
response
.
BadRequest
(
c
,
"Turnstile verification failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
}
token
,
user
,
err
:=
h
.
authService
.
RegisterWithVerification
(
c
.
Request
.
Context
(),
req
.
Email
,
req
.
Password
,
req
.
VerifyCode
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Registration failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -95,13 +95,13 @@ func (h *AuthHandler) SendVerifyCode(c *gin.Context) {
// Turnstile 验证
if
err
:=
h
.
authService
.
VerifyTurnstile
(
c
.
Request
.
Context
(),
req
.
TurnstileToken
,
c
.
ClientIP
());
err
!=
nil
{
response
.
BadRequest
(
c
,
"Turnstile verification failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
result
,
err
:=
h
.
authService
.
SendVerifyCodeAsync
(
c
.
Request
.
Context
(),
req
.
Email
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to send verification code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -122,13 +122,13 @@ func (h *AuthHandler) Login(c *gin.Context) {
// Turnstile 验证
if
err
:=
h
.
authService
.
VerifyTurnstile
(
c
.
Request
.
Context
(),
req
.
TurnstileToken
,
c
.
ClientIP
());
err
!=
nil
{
response
.
BadRequest
(
c
,
"Turnstile verification failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
token
,
user
,
err
:=
h
.
authService
.
Login
(
c
.
Request
.
Context
(),
req
.
Email
,
req
.
Password
)
if
err
!=
nil
{
response
.
Unauthorized
(
c
,
"Login failed: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/redeem_handler.go
View file @
eeaff85e
...
...
@@ -57,7 +57,7 @@ func (h *RedeemHandler) Redeem(c *gin.Context) {
result
,
err
:=
h
.
redeemService
.
Redeem
(
c
.
Request
.
Context
(),
user
.
ID
,
req
.
Code
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to redeem code: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -84,7 +84,7 @@ func (h *RedeemHandler) GetHistory(c *gin.Context) {
codes
,
err
:=
h
.
redeemService
.
GetUserHistory
(
c
.
Request
.
Context
(),
user
.
ID
,
limit
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get history: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/setting_handler.go
View file @
eeaff85e
...
...
@@ -26,7 +26,7 @@ func NewSettingHandler(settingService *service.SettingService, version string) *
func
(
h
*
SettingHandler
)
GetPublicSettings
(
c
*
gin
.
Context
)
{
settings
,
err
:=
h
.
settingService
.
GetPublicSettings
(
c
.
Request
.
Context
())
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get settings: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/subscription_handler.go
View file @
eeaff85e
...
...
@@ -58,7 +58,7 @@ func (h *SubscriptionHandler) List(c *gin.Context) {
subscriptions
,
err
:=
h
.
subscriptionService
.
ListUserSubscriptions
(
c
.
Request
.
Context
(),
u
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -82,7 +82,7 @@ func (h *SubscriptionHandler) GetActive(c *gin.Context) {
subscriptions
,
err
:=
h
.
subscriptionService
.
ListActiveUserSubscriptions
(
c
.
Request
.
Context
(),
u
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get active subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -107,7 +107,7 @@ func (h *SubscriptionHandler) GetProgress(c *gin.Context) {
// Get all active subscriptions with progress
subscriptions
,
err
:=
h
.
subscriptionService
.
ListActiveUserSubscriptions
(
c
.
Request
.
Context
(),
u
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -146,7 +146,7 @@ func (h *SubscriptionHandler) GetSummary(c *gin.Context) {
// Get all active subscriptions
subscriptions
,
err
:=
h
.
subscriptionService
.
ListActiveUserSubscriptions
(
c
.
Request
.
Context
(),
u
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get subscriptions: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/usage_handler.go
View file @
eeaff85e
...
...
@@ -55,7 +55,7 @@ func (h *UsageHandler) List(c *gin.Context) {
// [Security Fix] Verify API Key ownership to prevent horizontal privilege escalation
apiKey
,
err
:=
h
.
apiKeyService
.
GetByID
(
c
.
Request
.
Context
(),
id
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"API key not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
if
apiKey
.
UserID
!=
user
.
ID
{
...
...
@@ -77,7 +77,7 @@ func (h *UsageHandler) List(c *gin.Context) {
records
,
result
,
err
=
h
.
usageService
.
ListByUser
(
c
.
Request
.
Context
(),
user
.
ID
,
params
)
}
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to list usage records: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -107,7 +107,7 @@ func (h *UsageHandler) GetByID(c *gin.Context) {
record
,
err
:=
h
.
usageService
.
GetByID
(
c
.
Request
.
Context
(),
usageID
)
if
err
!=
nil
{
response
.
NotFound
(
c
,
"Usage record not found"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -204,7 +204,7 @@ func (h *UsageHandler) Stats(c *gin.Context) {
stats
,
err
=
h
.
usageService
.
GetStatsByUser
(
c
.
Request
.
Context
(),
user
.
ID
,
startTime
,
endTime
)
}
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get usage statistics: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -259,7 +259,7 @@ func (h *UsageHandler) DashboardStats(c *gin.Context) {
stats
,
err
:=
h
.
usageService
.
GetUserDashboardStats
(
c
.
Request
.
Context
(),
user
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get dashboard statistics"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -286,7 +286,7 @@ func (h *UsageHandler) DashboardTrend(c *gin.Context) {
trend
,
err
:=
h
.
usageService
.
GetUserUsageTrendByUserID
(
c
.
Request
.
Context
(),
user
.
ID
,
startTime
,
endTime
,
granularity
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get usage trend"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -317,7 +317,7 @@ func (h *UsageHandler) DashboardModels(c *gin.Context) {
stats
,
err
:=
h
.
usageService
.
GetUserModelStats
(
c
.
Request
.
Context
(),
user
.
ID
,
startTime
,
endTime
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get model statistics"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -362,7 +362,7 @@ func (h *UsageHandler) DashboardApiKeysUsage(c *gin.Context) {
// Verify ownership of all requested API keys
userApiKeys
,
_
,
err
:=
h
.
apiKeyService
.
List
(
c
.
Request
.
Context
(),
user
.
ID
,
pagination
.
PaginationParams
{
Page
:
1
,
PageSize
:
1000
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to verify API key ownership"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -386,7 +386,7 @@ func (h *UsageHandler) DashboardApiKeysUsage(c *gin.Context) {
stats
,
err
:=
h
.
usageService
.
GetBatchApiKeyUsageStats
(
c
.
Request
.
Context
(),
validApiKeyIDs
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get API key usage stats"
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/user_handler.go
View file @
eeaff85e
...
...
@@ -49,7 +49,7 @@ func (h *UserHandler) GetProfile(c *gin.Context) {
userData
,
err
:=
h
.
userService
.
GetByID
(
c
.
Request
.
Context
(),
user
.
ID
)
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to get user profile: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -86,7 +86,7 @@ func (h *UserHandler) ChangePassword(c *gin.Context) {
}
err
:=
h
.
userService
.
ChangePassword
(
c
.
Request
.
Context
(),
user
.
ID
,
svcReq
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to change password: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
@@ -120,7 +120,7 @@ func (h *UserHandler) UpdateProfile(c *gin.Context) {
}
updatedUser
,
err
:=
h
.
userService
.
UpdateProfile
(
c
.
Request
.
Context
(),
user
.
ID
,
svcReq
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Failed to update profile: "
+
err
.
Error
()
)
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/infrastructure/errors/errors.go
0 → 100644
View file @
eeaff85e
package
errors
import
(
"errors"
"fmt"
"net/http"
)
const
(
UnknownCode
=
http
.
StatusInternalServerError
UnknownReason
=
""
)
type
Status
struct
{
Code
int32
`json:"code"`
Reason
string
`json:"reason,omitempty"`
Message
string
`json:"message"`
Metadata
map
[
string
]
string
`json:"metadata,omitempty"`
}
// ApplicationError is the standard error type used to control HTTP responses.
//
// Code is expected to be an HTTP status code (e.g. 400/401/403/404/409/500).
type
ApplicationError
struct
{
Status
cause
error
}
// Error is kept for backwards compatibility within this package.
type
Error
=
ApplicationError
func
(
e
*
ApplicationError
)
Error
()
string
{
if
e
==
nil
{
return
"<nil>"
}
if
e
.
cause
==
nil
{
return
fmt
.
Sprintf
(
"error: code=%d reason=%q message=%q metadata=%v"
,
e
.
Code
,
e
.
Reason
,
e
.
Message
,
e
.
Metadata
)
}
return
fmt
.
Sprintf
(
"error: code=%d reason=%q message=%q metadata=%v cause=%v"
,
e
.
Code
,
e
.
Reason
,
e
.
Message
,
e
.
Metadata
,
e
.
cause
)
}
// Unwrap provides compatibility for Go 1.13 error chains.
func
(
e
*
ApplicationError
)
Unwrap
()
error
{
return
e
.
cause
}
// Is matches each error in the chain with the target value.
func
(
e
*
ApplicationError
)
Is
(
err
error
)
bool
{
if
se
:=
new
(
ApplicationError
);
errors
.
As
(
err
,
&
se
)
{
return
se
.
Code
==
e
.
Code
&&
se
.
Reason
==
e
.
Reason
}
return
false
}
// WithCause attaches the underlying cause of the error.
func
(
e
*
ApplicationError
)
WithCause
(
cause
error
)
*
ApplicationError
{
err
:=
Clone
(
e
)
err
.
cause
=
cause
return
err
}
// WithMetadata deep-copies the given metadata map.
func
(
e
*
ApplicationError
)
WithMetadata
(
md
map
[
string
]
string
)
*
ApplicationError
{
err
:=
Clone
(
e
)
if
md
==
nil
{
err
.
Metadata
=
nil
return
err
}
err
.
Metadata
=
make
(
map
[
string
]
string
,
len
(
md
))
for
k
,
v
:=
range
md
{
err
.
Metadata
[
k
]
=
v
}
return
err
}
// New returns an error object for the code, message.
func
New
(
code
int
,
reason
,
message
string
)
*
ApplicationError
{
return
&
ApplicationError
{
Status
:
Status
{
Code
:
int32
(
code
),
Message
:
message
,
Reason
:
reason
,
},
}
}
// Newf New(code fmt.Sprintf(format, a...))
func
Newf
(
code
int
,
reason
,
format
string
,
a
...
any
)
*
ApplicationError
{
return
New
(
code
,
reason
,
fmt
.
Sprintf
(
format
,
a
...
))
}
// Errorf returns an error object for the code, message and error info.
func
Errorf
(
code
int
,
reason
,
format
string
,
a
...
any
)
error
{
return
New
(
code
,
reason
,
fmt
.
Sprintf
(
format
,
a
...
))
}
// Code returns the http code for an error.
// It supports wrapped errors.
func
Code
(
err
error
)
int
{
if
err
==
nil
{
return
http
.
StatusOK
}
return
int
(
FromError
(
err
)
.
Code
)
}
// Reason returns the reason for a particular error.
// It supports wrapped errors.
func
Reason
(
err
error
)
string
{
if
err
==
nil
{
return
UnknownReason
}
return
FromError
(
err
)
.
Reason
}
// Message returns the message for a particular error.
// It supports wrapped errors.
func
Message
(
err
error
)
string
{
if
err
==
nil
{
return
""
}
return
FromError
(
err
)
.
Message
}
// Clone deep clone error to a new error.
func
Clone
(
err
*
ApplicationError
)
*
ApplicationError
{
if
err
==
nil
{
return
nil
}
var
metadata
map
[
string
]
string
if
err
.
Metadata
!=
nil
{
metadata
=
make
(
map
[
string
]
string
,
len
(
err
.
Metadata
))
for
k
,
v
:=
range
err
.
Metadata
{
metadata
[
k
]
=
v
}
}
return
&
ApplicationError
{
cause
:
err
.
cause
,
Status
:
Status
{
Code
:
err
.
Code
,
Reason
:
err
.
Reason
,
Message
:
err
.
Message
,
Metadata
:
metadata
,
},
}
}
// FromError tries to convert an error to *ApplicationError.
// It supports wrapped errors.
func
FromError
(
err
error
)
*
ApplicationError
{
if
err
==
nil
{
return
nil
}
if
se
:=
new
(
ApplicationError
);
errors
.
As
(
err
,
&
se
)
{
return
se
}
// Fall back to a generic internal error.
return
New
(
UnknownCode
,
UnknownReason
,
err
.
Error
())
.
WithCause
(
err
)
}
backend/internal/infrastructure/errors/errors_test.go
0 → 100644
View file @
eeaff85e
//go:build unit
package
errors
import
(
stderrors
"errors"
"fmt"
"io"
"net/http"
"testing"
"github.com/stretchr/testify/require"
)
func
TestApplicationError_Basics
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
err
*
ApplicationError
want
Status
wantIs
bool
target
error
wrapped
error
}{
{
name
:
"new"
,
err
:
New
(
400
,
"BAD_REQUEST"
,
"invalid input"
),
want
:
Status
{
Code
:
400
,
Reason
:
"BAD_REQUEST"
,
Message
:
"invalid input"
,
},
},
{
name
:
"is_matches_code_and_reason"
,
err
:
New
(
401
,
"UNAUTHORIZED"
,
"nope"
),
want
:
Status
{
Code
:
401
,
Reason
:
"UNAUTHORIZED"
,
Message
:
"nope"
},
target
:
New
(
401
,
"UNAUTHORIZED"
,
"ignored message"
),
wantIs
:
true
,
},
{
name
:
"is_does_not_match_reason"
,
err
:
New
(
401
,
"UNAUTHORIZED"
,
"nope"
),
want
:
Status
{
Code
:
401
,
Reason
:
"UNAUTHORIZED"
,
Message
:
"nope"
},
target
:
New
(
401
,
"DIFFERENT"
,
"ignored message"
),
wantIs
:
false
,
},
{
name
:
"from_error_unwraps_wrapped_application_error"
,
err
:
New
(
404
,
"NOT_FOUND"
,
"missing"
),
wrapped
:
fmt
.
Errorf
(
"wrap: %w"
,
New
(
404
,
"NOT_FOUND"
,
"missing"
)),
want
:
Status
{
Code
:
404
,
Reason
:
"NOT_FOUND"
,
Message
:
"missing"
,
},
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
if
tt
.
err
!=
nil
{
require
.
Equal
(
t
,
tt
.
want
,
tt
.
err
.
Status
)
}
if
tt
.
target
!=
nil
{
require
.
Equal
(
t
,
tt
.
wantIs
,
stderrors
.
Is
(
tt
.
err
,
tt
.
target
))
}
if
tt
.
wrapped
!=
nil
{
got
:=
FromError
(
tt
.
wrapped
)
require
.
Equal
(
t
,
tt
.
want
,
got
.
Status
)
}
})
}
}
func
TestApplicationError_WithMetadataDeepCopy
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
md
map
[
string
]
string
}{
{
name
:
"non_nil"
,
md
:
map
[
string
]
string
{
"a"
:
"1"
}},
{
name
:
"nil"
,
md
:
nil
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
appErr
:=
BadRequest
(
"BAD_REQUEST"
,
"invalid input"
)
.
WithMetadata
(
tt
.
md
)
if
tt
.
md
==
nil
{
require
.
Nil
(
t
,
appErr
.
Metadata
)
return
}
tt
.
md
[
"a"
]
=
"changed"
require
.
Equal
(
t
,
"1"
,
appErr
.
Metadata
[
"a"
])
})
}
}
func
TestFromError_Generic
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
err
error
wantCode
int32
wantReason
string
wantMsg
string
}{
{
name
:
"plain_error"
,
err
:
stderrors
.
New
(
"boom"
),
wantCode
:
UnknownCode
,
wantReason
:
UnknownReason
,
wantMsg
:
"boom"
,
},
{
name
:
"wrapped_plain_error"
,
err
:
fmt
.
Errorf
(
"wrap: %w"
,
io
.
EOF
),
wantCode
:
UnknownCode
,
wantReason
:
UnknownReason
,
wantMsg
:
"wrap: EOF"
,
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
got
:=
FromError
(
tt
.
err
)
require
.
Equal
(
t
,
tt
.
wantCode
,
got
.
Code
)
require
.
Equal
(
t
,
tt
.
wantReason
,
got
.
Reason
)
require
.
Equal
(
t
,
tt
.
wantMsg
,
got
.
Message
)
require
.
Equal
(
t
,
tt
.
err
,
got
.
Unwrap
())
})
}
}
func
TestToHTTP
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
err
error
wantStatusCode
int
wantBody
Status
}{
{
name
:
"nil_error"
,
err
:
nil
,
wantStatusCode
:
http
.
StatusOK
,
wantBody
:
Status
{
Code
:
int32
(
http
.
StatusOK
)},
},
{
name
:
"application_error"
,
err
:
Forbidden
(
"FORBIDDEN"
,
"no access"
),
wantStatusCode
:
http
.
StatusForbidden
,
wantBody
:
Status
{
Code
:
int32
(
http
.
StatusForbidden
),
Reason
:
"FORBIDDEN"
,
Message
:
"no access"
,
},
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
code
,
body
:=
ToHTTP
(
tt
.
err
)
require
.
Equal
(
t
,
tt
.
wantStatusCode
,
code
)
require
.
Equal
(
t
,
tt
.
wantBody
,
body
)
})
}
}
backend/internal/infrastructure/errors/http.go
0 → 100644
View file @
eeaff85e
package
errors
import
"net/http"
// ToHTTP converts an error into an HTTP status code and a JSON-serializable body.
//
// The returned body matches the project's Status shape:
// { code, reason, message, metadata }.
func
ToHTTP
(
err
error
)
(
statusCode
int
,
body
Status
)
{
if
err
==
nil
{
return
http
.
StatusOK
,
Status
{
Code
:
int32
(
http
.
StatusOK
)}
}
appErr
:=
FromError
(
err
)
if
appErr
==
nil
{
return
http
.
StatusOK
,
Status
{
Code
:
int32
(
http
.
StatusOK
)}
}
cloned
:=
Clone
(
appErr
)
return
int
(
cloned
.
Code
),
cloned
.
Status
}
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment