mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-05-04 21:20:51 +08:00
feat: support filter-target account bulk update
This commit is contained in:
@@ -134,7 +134,8 @@ type UpdateAccountRequest struct {
|
|||||||
|
|
||||||
// BulkUpdateAccountsRequest represents the payload for bulk editing accounts
|
// BulkUpdateAccountsRequest represents the payload for bulk editing accounts
|
||||||
type BulkUpdateAccountsRequest struct {
|
type BulkUpdateAccountsRequest struct {
|
||||||
AccountIDs []int64 `json:"account_ids" binding:"required,min=1"`
|
AccountIDs []int64 `json:"account_ids"`
|
||||||
|
Filters *BulkUpdateAccountFilters `json:"filters"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ProxyID *int64 `json:"proxy_id"`
|
ProxyID *int64 `json:"proxy_id"`
|
||||||
Concurrency *int `json:"concurrency"`
|
Concurrency *int `json:"concurrency"`
|
||||||
@@ -149,6 +150,15 @@ type BulkUpdateAccountsRequest struct {
|
|||||||
ConfirmMixedChannelRisk *bool `json:"confirm_mixed_channel_risk"` // 用户确认混合渠道风险
|
ConfirmMixedChannelRisk *bool `json:"confirm_mixed_channel_risk"` // 用户确认混合渠道风险
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BulkUpdateAccountFilters struct {
|
||||||
|
Platform string `json:"platform"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Group string `json:"group"`
|
||||||
|
Search string `json:"search"`
|
||||||
|
PrivacyMode string `json:"privacy_mode"`
|
||||||
|
}
|
||||||
|
|
||||||
// CheckMixedChannelRequest represents check mixed channel risk request
|
// CheckMixedChannelRequest represents check mixed channel risk request
|
||||||
type CheckMixedChannelRequest struct {
|
type CheckMixedChannelRequest struct {
|
||||||
Platform string `json:"platform" binding:"required"`
|
Platform string `json:"platform" binding:"required"`
|
||||||
@@ -1369,6 +1379,10 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
|
|||||||
response.BadRequest(c, "rate_multiplier must be >= 0")
|
response.BadRequest(c, "rate_multiplier must be >= 0")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(req.AccountIDs) == 0 && req.Filters == nil {
|
||||||
|
response.BadRequest(c, "account_ids or filters is required")
|
||||||
|
return
|
||||||
|
}
|
||||||
// base_rpm 输入校验:负值归零,超过 10000 截断
|
// base_rpm 输入校验:负值归零,超过 10000 截断
|
||||||
sanitizeExtraBaseRPM(req.Extra)
|
sanitizeExtraBaseRPM(req.Extra)
|
||||||
|
|
||||||
@@ -1394,6 +1408,7 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
|
|||||||
|
|
||||||
result, err := h.adminService.BulkUpdateAccounts(c.Request.Context(), &service.BulkUpdateAccountsInput{
|
result, err := h.adminService.BulkUpdateAccounts(c.Request.Context(), &service.BulkUpdateAccountsInput{
|
||||||
AccountIDs: req.AccountIDs,
|
AccountIDs: req.AccountIDs,
|
||||||
|
Filters: toServiceBulkUpdateAccountFilters(req.Filters),
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
ProxyID: req.ProxyID,
|
ProxyID: req.ProxyID,
|
||||||
Concurrency: req.Concurrency,
|
Concurrency: req.Concurrency,
|
||||||
@@ -1429,6 +1444,20 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
|
|||||||
response.Success(c, result)
|
response.Success(c, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toServiceBulkUpdateAccountFilters(filters *BulkUpdateAccountFilters) *service.BulkUpdateAccountFilters {
|
||||||
|
if filters == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &service.BulkUpdateAccountFilters{
|
||||||
|
Platform: filters.Platform,
|
||||||
|
Type: filters.Type,
|
||||||
|
Status: filters.Status,
|
||||||
|
Group: filters.Group,
|
||||||
|
Search: filters.Search,
|
||||||
|
PrivacyMode: filters.PrivacyMode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ========== OAuth Handlers ==========
|
// ========== OAuth Handlers ==========
|
||||||
|
|
||||||
// GenerateAuthURLRequest represents the request for generating auth URL
|
// GenerateAuthURLRequest represents the request for generating auth URL
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -291,6 +292,7 @@ type UpdateAccountInput struct {
|
|||||||
// BulkUpdateAccountsInput describes the payload for bulk updating accounts.
|
// BulkUpdateAccountsInput describes the payload for bulk updating accounts.
|
||||||
type BulkUpdateAccountsInput struct {
|
type BulkUpdateAccountsInput struct {
|
||||||
AccountIDs []int64
|
AccountIDs []int64
|
||||||
|
Filters *BulkUpdateAccountFilters
|
||||||
Name string
|
Name string
|
||||||
ProxyID *int64
|
ProxyID *int64
|
||||||
Concurrency *int
|
Concurrency *int
|
||||||
@@ -307,6 +309,15 @@ type BulkUpdateAccountsInput struct {
|
|||||||
SkipMixedChannelCheck bool
|
SkipMixedChannelCheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BulkUpdateAccountFilters struct {
|
||||||
|
Platform string
|
||||||
|
Type string
|
||||||
|
Status string
|
||||||
|
Group string
|
||||||
|
Search string
|
||||||
|
PrivacyMode string
|
||||||
|
}
|
||||||
|
|
||||||
// BulkUpdateAccountResult captures the result for a single account update.
|
// BulkUpdateAccountResult captures the result for a single account update.
|
||||||
type BulkUpdateAccountResult struct {
|
type BulkUpdateAccountResult struct {
|
||||||
AccountID int64 `json:"account_id"`
|
AccountID int64 `json:"account_id"`
|
||||||
@@ -2286,6 +2297,14 @@ func (s *adminServiceImpl) UpdateAccount(ctx context.Context, id int64, input *U
|
|||||||
// BulkUpdateAccounts updates multiple accounts in one request.
|
// BulkUpdateAccounts updates multiple accounts in one request.
|
||||||
// It merges credentials/extra keys instead of overwriting the whole object.
|
// It merges credentials/extra keys instead of overwriting the whole object.
|
||||||
func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUpdateAccountsInput) (*BulkUpdateAccountsResult, error) {
|
func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUpdateAccountsInput) (*BulkUpdateAccountsResult, error) {
|
||||||
|
if len(input.AccountIDs) == 0 && input.Filters != nil {
|
||||||
|
accountIDs, err := s.resolveBulkUpdateTargetIDs(ctx, input.Filters)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
input.AccountIDs = accountIDs
|
||||||
|
}
|
||||||
|
|
||||||
result := &BulkUpdateAccountsResult{
|
result := &BulkUpdateAccountsResult{
|
||||||
SuccessIDs: make([]int64, 0, len(input.AccountIDs)),
|
SuccessIDs: make([]int64, 0, len(input.AccountIDs)),
|
||||||
FailedIDs: make([]int64, 0, len(input.AccountIDs)),
|
FailedIDs: make([]int64, 0, len(input.AccountIDs)),
|
||||||
@@ -2401,6 +2420,55 @@ func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUp
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *adminServiceImpl) resolveBulkUpdateTargetIDs(ctx context.Context, filters *BulkUpdateAccountFilters) ([]int64, error) {
|
||||||
|
if filters == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
groupID := int64(0)
|
||||||
|
switch strings.TrimSpace(filters.Group) {
|
||||||
|
case "":
|
||||||
|
case "ungrouped":
|
||||||
|
groupID = AccountListGroupUngrouped
|
||||||
|
default:
|
||||||
|
parsedGroupID, err := strconv.ParseInt(strings.TrimSpace(filters.Group), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid group filter: %w", err)
|
||||||
|
}
|
||||||
|
groupID = parsedGroupID
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageSize = 500
|
||||||
|
page := 1
|
||||||
|
accountIDs := make([]int64, 0, pageSize)
|
||||||
|
|
||||||
|
for {
|
||||||
|
accounts, total, err := s.ListAccounts(
|
||||||
|
ctx,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
filters.Platform,
|
||||||
|
filters.Type,
|
||||||
|
filters.Status,
|
||||||
|
filters.Search,
|
||||||
|
groupID,
|
||||||
|
filters.PrivacyMode,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, account := range accounts {
|
||||||
|
accountIDs = append(accountIDs, account.ID)
|
||||||
|
}
|
||||||
|
if int64(len(accountIDs)) >= total || len(accounts) == 0 {
|
||||||
|
return accountIDs, nil
|
||||||
|
}
|
||||||
|
page++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *adminServiceImpl) DeleteAccount(ctx context.Context, id int64) error {
|
func (s *adminServiceImpl) DeleteAccount(ctx context.Context, id int64) error {
|
||||||
if err := s.accountRepo.Delete(ctx, id); err != nil {
|
if err := s.accountRepo.Delete(ctx, id); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user