feat: expose auth identity migration reports
This commit is contained in:
@@ -2,6 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -16,6 +18,8 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/logger"
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
|
||||
"github.com/Wei-Shaw/sub2api/internal/util/httputil"
|
||||
|
||||
entsql "entgo.io/ent/dialect/sql"
|
||||
)
|
||||
|
||||
// AdminService interface defines admin management operations
|
||||
@@ -33,6 +37,8 @@ type AdminService interface {
|
||||
// codeType is optional - pass empty string to return all types.
|
||||
// Also returns totalRecharged (sum of all positive balance top-ups).
|
||||
GetUserBalanceHistory(ctx context.Context, userID int64, page, pageSize int, codeType string) ([]RedeemCode, int64, float64, error)
|
||||
ListAuthIdentityMigrationReports(ctx context.Context, reportType string, page, pageSize int) ([]AuthIdentityMigrationReport, int64, error)
|
||||
GetAuthIdentityMigrationReportSummary(ctx context.Context) (*AuthIdentityMigrationReportSummary, error)
|
||||
|
||||
// Group management
|
||||
ListGroups(ctx context.Context, page, pageSize int, platform, status, search string, isExclusive *bool, sortBy, sortOrder string) ([]Group, int64, error)
|
||||
@@ -127,6 +133,19 @@ type UpdateUserInput struct {
|
||||
GroupRates map[int64]*float64
|
||||
}
|
||||
|
||||
type AuthIdentityMigrationReport struct {
|
||||
ID int64 `json:"id"`
|
||||
ReportType string `json:"report_type"`
|
||||
ReportKey string `json:"report_key"`
|
||||
Details map[string]any `json:"details"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type AuthIdentityMigrationReportSummary struct {
|
||||
Total int64 `json:"total"`
|
||||
ByType map[string]int64 `json:"by_type"`
|
||||
}
|
||||
|
||||
type CreateGroupInput struct {
|
||||
Name string
|
||||
Description string
|
||||
@@ -788,6 +807,122 @@ func (s *adminServiceImpl) GetUserBalanceHistory(ctx context.Context, userID int
|
||||
return codes, result.Total, totalRecharged, nil
|
||||
}
|
||||
|
||||
func (s *adminServiceImpl) ListAuthIdentityMigrationReports(ctx context.Context, reportType string, page, pageSize int) ([]AuthIdentityMigrationReport, int64, error) {
|
||||
db, err := s.adminSQLDB()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
reportType = strings.TrimSpace(reportType)
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
var total int64
|
||||
if err := db.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*)
|
||||
FROM auth_identity_migration_reports
|
||||
WHERE ($1 = '' OR report_type = $1)`,
|
||||
reportType,
|
||||
).Scan(&total); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
rows, err := db.QueryContext(ctx, `
|
||||
SELECT id, report_type, report_key, details, created_at
|
||||
FROM auth_identity_migration_reports
|
||||
WHERE ($1 = '' OR report_type = $1)
|
||||
ORDER BY created_at DESC, id DESC
|
||||
LIMIT $2 OFFSET $3`,
|
||||
reportType,
|
||||
pageSize,
|
||||
offset,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
reports := make([]AuthIdentityMigrationReport, 0)
|
||||
for rows.Next() {
|
||||
report, scanErr := scanAuthIdentityMigrationReport(rows)
|
||||
if scanErr != nil {
|
||||
return nil, 0, scanErr
|
||||
}
|
||||
reports = append(reports, report)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return reports, total, nil
|
||||
}
|
||||
|
||||
func (s *adminServiceImpl) GetAuthIdentityMigrationReportSummary(ctx context.Context) (*AuthIdentityMigrationReportSummary, error) {
|
||||
db, err := s.adminSQLDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := db.QueryContext(ctx, `
|
||||
SELECT report_type, COUNT(*)
|
||||
FROM auth_identity_migration_reports
|
||||
GROUP BY report_type
|
||||
ORDER BY report_type ASC`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
summary := &AuthIdentityMigrationReportSummary{
|
||||
ByType: make(map[string]int64),
|
||||
}
|
||||
for rows.Next() {
|
||||
var reportType string
|
||||
var count int64
|
||||
if err := rows.Scan(&reportType, &count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
summary.ByType[reportType] = count
|
||||
summary.Total += count
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return summary, nil
|
||||
}
|
||||
|
||||
func (s *adminServiceImpl) adminSQLDB() (*sql.DB, error) {
|
||||
if s == nil || s.entClient == nil {
|
||||
return nil, infraerrors.ServiceUnavailable("ADMIN_SQL_NOT_READY", "admin sql access is not ready")
|
||||
}
|
||||
driver, ok := s.entClient.Driver().(*entsql.Driver)
|
||||
if !ok || driver.DB() == nil {
|
||||
return nil, infraerrors.ServiceUnavailable("ADMIN_SQL_NOT_READY", "admin sql access is not ready")
|
||||
}
|
||||
return driver.DB(), nil
|
||||
}
|
||||
|
||||
func scanAuthIdentityMigrationReport(scanner interface{ Scan(dest ...any) error }) (AuthIdentityMigrationReport, error) {
|
||||
var (
|
||||
report AuthIdentityMigrationReport
|
||||
details []byte
|
||||
)
|
||||
if err := scanner.Scan(&report.ID, &report.ReportType, &report.ReportKey, &details, &report.CreatedAt); err != nil {
|
||||
return AuthIdentityMigrationReport{}, err
|
||||
}
|
||||
report.Details = map[string]any{}
|
||||
if len(details) > 0 {
|
||||
if err := json.Unmarshal(details, &report.Details); err != nil {
|
||||
return AuthIdentityMigrationReport{}, err
|
||||
}
|
||||
}
|
||||
return report, nil
|
||||
}
|
||||
|
||||
// Group management implementations
|
||||
func (s *adminServiceImpl) ListGroups(ctx context.Context, page, pageSize int, platform, status, search string, isExclusive *bool, sortBy, sortOrder string) ([]Group, int64, error) {
|
||||
params := pagination.PaginationParams{Page: page, PageSize: pageSize, SortBy: sortBy, SortOrder: sortOrder}
|
||||
|
||||
Reference in New Issue
Block a user