Files
ttstd-infinite-canvas/backend/internal/app/admin_audit.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
}