142 lines
4.5 KiB
Go
142 lines
4.5 KiB
Go
package app
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"time"
|
|
|
|
"infinite-canvas/backend/internal/model"
|
|
"infinite-canvas/backend/internal/repository"
|
|
)
|
|
|
|
type AdminUserDetail struct {
|
|
User model.User `json:"user"`
|
|
Account model.CreditAccount `json:"account"`
|
|
Counts repository.AdminUserCounts `json:"counts"`
|
|
StorageUsage repository.UserStorageUsage `json:"storageUsage"`
|
|
StoredFileBytes int64 `json:"storedFileBytes"`
|
|
DailyUploadBytes int64 `json:"dailyUploadBytes"`
|
|
Quota RuntimeResourcePolicy `json:"quota"`
|
|
}
|
|
|
|
type AdminTaskPage struct {
|
|
Tasks []model.Task `json:"tasks"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
Limit int `json:"pageSize"`
|
|
}
|
|
|
|
type AdminAuditPage struct {
|
|
Events []model.AdminAuditEvent `json:"events"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
Limit int `json:"pageSize"`
|
|
}
|
|
|
|
func (s *Service) appendAdminAudit(actor *model.User, action string, targetType string, targetID string, summary string, metadata any) error {
|
|
event, err := newAdminAuditEvent(actor, action, targetType, targetID, summary, metadata)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.repo.AppendAdminAudit(event)
|
|
}
|
|
|
|
func newAdminAuditEvent(actor *model.User, action string, targetType string, targetID string, summary string, metadata any) (*model.AdminAuditEvent, error) {
|
|
if actor == nil {
|
|
return nil, Unauthorized("请先登录")
|
|
}
|
|
encoded := ""
|
|
if metadata != nil {
|
|
data, err := json.Marshal(metadata)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
encoded = string(data)
|
|
}
|
|
return &model.AdminAuditEvent{
|
|
ID: newID(), ActorUserID: actor.ID, Action: strings.TrimSpace(action), TargetType: strings.TrimSpace(targetType),
|
|
TargetID: strings.TrimSpace(targetID), Summary: truncateRunes(strings.TrimSpace(summary), 500), MetadataJSON: encoded, CreatedAt: time.Now(),
|
|
}, nil
|
|
}
|
|
|
|
func (s *Service) AdminUserDetail(actor *model.User, userID string) (*AdminUserDetail, error) {
|
|
if err := s.RequireAdmin(actor); err != nil {
|
|
return nil, err
|
|
}
|
|
user, err := s.repo.User(strings.TrimSpace(userID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
account, err := s.repo.CreditAccount(user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
counts, err := s.repo.AdminUserCounts(user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
usage, err := s.repo.UserStorageUsage(user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
storedFileBytes, err := s.repo.UserStoredFileBytes(user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dailyUploadBytes, err := s.repo.DailyUploadBytes(user.ID, time.Now().UTC().Format("2006-01-02"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
policy, err := s.RuntimePolicy()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &AdminUserDetail{
|
|
User: *user, Account: *account, Counts: counts, StorageUsage: usage,
|
|
StoredFileBytes: storedFileBytes, DailyUploadBytes: dailyUploadBytes, Quota: policy.Resource,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Service) AdminUserLedger(actor *model.User, userID string, entryType string, page int, limit int) (*WalletSummary, error) {
|
|
if err := s.RequireAdmin(actor); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := s.repo.User(userID); err != nil {
|
|
return nil, err
|
|
}
|
|
page, limit = normalizeAdminPage(page, limit)
|
|
account, err := s.repo.CreditAccount(userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
entries, total, err := s.repo.CreditLedger(userID, entryType, limit, (page-1)*limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &WalletSummary{Account: *account, Entries: entries, Total: total, Page: page, Limit: limit}, nil
|
|
}
|
|
|
|
func (s *Service) AdminUserTasks(actor *model.User, userID string, page int, limit int) (*AdminTaskPage, error) {
|
|
if err := s.RequireAdmin(actor); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := s.repo.User(userID); err != nil {
|
|
return nil, err
|
|
}
|
|
page, limit = normalizeAdminPage(page, limit)
|
|
tasks, total, err := s.repo.AdminUserTasks(userID, limit, (page-1)*limit)
|
|
return &AdminTaskPage{Tasks: tasks, Total: total, Page: page, Limit: limit}, err
|
|
}
|
|
|
|
func (s *Service) AdminUserAuditEvents(actor *model.User, userID string, page int, limit int) (*AdminAuditPage, error) {
|
|
if err := s.RequireAdmin(actor); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := s.repo.User(userID); err != nil {
|
|
return nil, err
|
|
}
|
|
page, limit = normalizeAdminPage(page, limit)
|
|
events, total, err := s.repo.AdminAuditEvents("user", userID, limit, (page-1)*limit)
|
|
return &AdminAuditPage{Events: events, Total: total, Page: page, Limit: limit}, err
|
|
}
|