release: prepare v0.1.132

This commit is contained in:
kone
2026-05-15 22:33:43 +08:00
parent 41e60b20d6
commit b430cd4aa9
47 changed files with 1107 additions and 213 deletions
@@ -175,6 +175,11 @@ func (s *stubAdminService) UpdateUserBalance(ctx context.Context, userID int64,
return &user, nil
}
func (s *stubAdminService) RefreshUserRegistrationIPLocation(ctx context.Context, userID int64) (*service.User, error) {
user := service.User{ID: userID, Email: "user@example.com", Status: service.StatusActive, RegisterIPAddress: "8.8.8.8", RegisterIPLocation: "美国"}
return &user, nil
}
func (s *stubAdminService) BatchUpdateConcurrency(ctx context.Context, userIDs []int64, value int, mode string) (int, error) {
return len(userIDs), nil
}
@@ -204,6 +204,7 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
AffiliateRebateFreezeHours: settings.AffiliateRebateFreezeHours,
AffiliateRebateDurationDays: settings.AffiliateRebateDurationDays,
AffiliateRebatePerInviteeCap: settings.AffiliateRebatePerInviteeCap,
AffiliateInviteBalanceReward: settings.AffiliateInviteBalanceReward,
DefaultUserRPMLimit: settings.DefaultUserRPMLimit,
DefaultSubscriptions: defaultSubscriptions,
EnableModelFallback: settings.EnableModelFallback,
@@ -452,6 +453,7 @@ type UpdateSettingsRequest struct {
AffiliateRebateFreezeHours *int `json:"affiliate_rebate_freeze_hours"`
AffiliateRebateDurationDays *int `json:"affiliate_rebate_duration_days"`
AffiliateRebatePerInviteeCap *float64 `json:"affiliate_rebate_per_invitee_cap"`
AffiliateInviteBalanceReward *float64 `json:"affiliate_invite_balance_reward"`
DefaultUserRPMLimit int `json:"default_user_rpm_limit"`
DefaultSubscriptions []dto.DefaultSubscriptionSetting `json:"default_subscriptions"`
AuthSourceDefaultEmailBalance *float64 `json:"auth_source_default_email_balance"`
@@ -641,6 +643,13 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
if affiliateRebatePerInviteeCap < 0 {
affiliateRebatePerInviteeCap = service.AffiliateRebatePerInviteeCapDefault
}
affiliateInviteBalanceReward := previousSettings.AffiliateInviteBalanceReward
if req.AffiliateInviteBalanceReward != nil {
affiliateInviteBalanceReward = *req.AffiliateInviteBalanceReward
}
if affiliateInviteBalanceReward < 0 {
affiliateInviteBalanceReward = service.AffiliateInviteBalanceRewardDefault
}
// 通用表格配置:兼容旧客户端未传字段时保留当前值。
if req.TableDefaultPageSize <= 0 {
req.TableDefaultPageSize = previousSettings.TableDefaultPageSize
@@ -1374,6 +1383,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
AffiliateRebateFreezeHours: affiliateRebateFreezeHours,
AffiliateRebateDurationDays: affiliateRebateDurationDays,
AffiliateRebatePerInviteeCap: affiliateRebatePerInviteeCap,
AffiliateInviteBalanceReward: affiliateInviteBalanceReward,
DefaultUserRPMLimit: req.DefaultUserRPMLimit,
DefaultSubscriptions: defaultSubscriptions,
EnableModelFallback: req.EnableModelFallback,
@@ -1758,6 +1768,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
AffiliateRebateFreezeHours: updatedSettings.AffiliateRebateFreezeHours,
AffiliateRebateDurationDays: updatedSettings.AffiliateRebateDurationDays,
AffiliateRebatePerInviteeCap: updatedSettings.AffiliateRebatePerInviteeCap,
AffiliateInviteBalanceReward: updatedSettings.AffiliateInviteBalanceReward,
DefaultUserRPMLimit: updatedSettings.DefaultUserRPMLimit,
DefaultSubscriptions: updatedDefaultSubscriptions,
EnableModelFallback: updatedSettings.EnableModelFallback,
@@ -2099,6 +2110,9 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings,
if before.AffiliateRebatePerInviteeCap != after.AffiliateRebatePerInviteeCap {
changed = append(changed, "affiliate_rebate_per_invitee_cap")
}
if before.AffiliateInviteBalanceReward != after.AffiliateInviteBalanceReward {
changed = append(changed, "affiliate_invite_balance_reward")
}
if !equalDefaultSubscriptions(before.DefaultSubscriptions, after.DefaultSubscriptions) {
changed = append(changed, "default_subscriptions")
}
@@ -341,6 +341,24 @@ func (h *UserHandler) UpdateBalance(c *gin.Context) {
})
}
// RefreshRegistrationIPLocation handles refreshing signup IP location.
// POST /api/v1/admin/users/:id/register-ip-location
func (h *UserHandler) RefreshRegistrationIPLocation(c *gin.Context) {
userID, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequest(c, "Invalid user ID")
return
}
user, err := h.adminService.RefreshUserRegistrationIPLocation(c.Request.Context(), userID)
if err != nil {
response.ErrorFrom(c, err)
return
}
response.Success(c, dto.UserFromServiceAdmin(user))
}
// GetUserAPIKeys handles getting user's API keys
// GET /api/v1/admin/users/:id/api-keys
func (h *UserHandler) GetUserAPIKeys(c *gin.Context) {
+1 -1
View File
@@ -362,7 +362,7 @@ func (h *AuthHandler) completeEmailOAuthRegistration(c *gin.Context, provider st
}
tokenPair, user, err := h.authService.RegisterVerifiedOAuthEmailAccount(
c.Request.Context(),
registrationIPContext(c),
strings.TrimSpace(session.ResolvedEmail),
req.Password,
strings.TrimSpace(req.InvitationCode),
@@ -352,6 +352,10 @@ func (r *oauthEmailAffiliateRepoStub) AccrueQuota(context.Context, int64, int64,
panic("unexpected AccrueQuota call")
}
func (r *oauthEmailAffiliateRepoStub) CreditInviteBalanceReward(context.Context, int64, int64, float64) (float64, error) {
panic("unexpected CreditInviteBalanceReward call")
}
func (r *oauthEmailAffiliateRepoStub) GetAccruedRebateFromInvitee(context.Context, int64, int64) (float64, error) {
panic("unexpected GetAccruedRebateFromInvitee call")
}
+10 -1
View File
@@ -150,6 +150,15 @@ func (h *AuthHandler) isBackendModeEnabled(ctx context.Context) bool {
return h.settingSvc.IsBackendModeEnabled(ctx)
}
func registrationIPContext(c *gin.Context) context.Context {
base := c.Request.Context()
clientIP := strings.TrimSpace(ip.GetClientIP(c))
if clientIP == "" {
return base
}
return service.WithRegistrationIPInfo(base, service.RegistrationIPInfo{IPAddress: clientIP})
}
// Register handles user registration
// POST /api/v1/auth/register
func (h *AuthHandler) Register(c *gin.Context) {
@@ -166,7 +175,7 @@ func (h *AuthHandler) Register(c *gin.Context) {
}
_, user, err := h.authService.RegisterWithVerification(
c.Request.Context(),
registrationIPContext(c),
req.Email,
req.Password,
req.VerifyCode,
@@ -519,7 +519,7 @@ func (h *AuthHandler) CompleteLinuxDoOAuthRegistration(c *gin.Context) {
response.ErrorFrom(c, err)
return
}
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(c.Request.Context(), email, username, req.InvitationCode, req.AffCode)
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(registrationIPContext(c), email, username, req.InvitationCode, req.AffCode)
if err != nil {
response.ErrorFrom(c, err)
return
@@ -1673,7 +1673,7 @@ func (h *AuthHandler) createPendingOAuthAccount(c *gin.Context, provider string)
}
tokenPair, user, err := h.authService.RegisterOAuthEmailAccount(
c.Request.Context(),
registrationIPContext(c),
email,
req.Password,
strings.TrimSpace(req.VerifyCode),
+1 -1
View File
@@ -666,7 +666,7 @@ func (h *AuthHandler) CompleteOIDCOAuthRegistration(c *gin.Context) {
response.ErrorFrom(c, err)
return
}
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(c.Request.Context(), email, username, req.InvitationCode, req.AffCode)
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(registrationIPContext(c), email, username, req.InvitationCode, req.AffCode)
if err != nil {
response.ErrorFrom(c, err)
return
@@ -548,7 +548,7 @@ func (h *AuthHandler) CompleteWeChatOAuthRegistration(c *gin.Context) {
return
}
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(c.Request.Context(), email, username, req.InvitationCode, req.AffCode)
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(registrationIPContext(c), email, username, req.InvitationCode, req.AffCode)
if err != nil {
response.ErrorFrom(c, err)
return
+6
View File
@@ -21,6 +21,12 @@ func UserFromServiceShallow(u *service.User) *User {
Concurrency: u.Concurrency,
Status: u.Status,
AllowedGroups: u.AllowedGroups,
RegisterIPAddress: u.RegisterIPAddress,
RegisterIPCountry: u.RegisterIPCountry,
RegisterIPCountryCode: u.RegisterIPCountryCode,
RegisterIPRegion: u.RegisterIPRegion,
RegisterIPCity: u.RegisterIPCity,
RegisterIPLocation: u.RegisterIPLocation,
LastActiveAt: u.LastActiveAt,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
+1
View File
@@ -129,6 +129,7 @@ type SystemSettings struct {
AffiliateRebateFreezeHours int `json:"affiliate_rebate_freeze_hours"`
AffiliateRebateDurationDays int `json:"affiliate_rebate_duration_days"`
AffiliateRebatePerInviteeCap float64 `json:"affiliate_rebate_per_invitee_cap"`
AffiliateInviteBalanceReward float64 `json:"affiliate_invite_balance_reward"`
DefaultUserRPMLimit int `json:"default_user_rpm_limit"`
DefaultSubscriptions []DefaultSubscriptionSetting `json:"default_subscriptions"`
+17 -11
View File
@@ -7,17 +7,23 @@ import (
)
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
Role string `json:"role"`
Balance float64 `json:"balance"`
Concurrency int `json:"concurrency"`
Status string `json:"status"`
AllowedGroups []int64 `json:"allowed_groups"`
LastActiveAt *time.Time `json:"last_active_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ID int64 `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
Role string `json:"role"`
Balance float64 `json:"balance"`
Concurrency int `json:"concurrency"`
Status string `json:"status"`
AllowedGroups []int64 `json:"allowed_groups"`
RegisterIPAddress string `json:"register_ip_address,omitempty"`
RegisterIPCountry string `json:"register_ip_country,omitempty"`
RegisterIPCountryCode string `json:"register_ip_country_code,omitempty"`
RegisterIPRegion string `json:"register_ip_region,omitempty"`
RegisterIPCity string `json:"register_ip_city,omitempty"`
RegisterIPLocation string `json:"register_ip_location,omitempty"`
LastActiveAt *time.Time `json:"last_active_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// 余额不足通知
BalanceNotifyEnabled bool `json:"balance_notify_enabled"`