From b1d395eac62625930752a2d37af02b21408d9730 Mon Sep 17 00:00:00 2001 From: nyne Date: Wed, 9 Jul 2025 17:17:54 +0800 Subject: [PATCH] Add user file statistic. --- frontend/src/network/models.ts | 3 +- frontend/src/pages/user_page.tsx | 2 +- server/dao/file.go | 32 +++++++++++++---- server/model/user.go | 60 +++++++++++++++++--------------- 4 files changed, 61 insertions(+), 36 deletions(-) diff --git a/frontend/src/network/models.ts b/frontend/src/network/models.ts index 5365465..64d0379 100644 --- a/frontend/src/network/models.ts +++ b/frontend/src/network/models.ts @@ -5,7 +5,8 @@ export interface User { avatar_path: string; is_admin: boolean; can_upload: boolean; - uploads_count: number; + resources_count: number; + files_count: number; comments_count: number; bio: string; } diff --git a/frontend/src/pages/user_page.tsx b/frontend/src/pages/user_page.tsx index 79044d0..48bae74 100644 --- a/frontend/src/pages/user_page.tsx +++ b/frontend/src/pages/user_page.tsx @@ -89,7 +89,7 @@ function UserCard({ user }: { user: User }) {

{" "} - {user.uploads_count} + {user.resources_count} Resources diff --git a/server/dao/file.go b/server/dao/file.go index 204280f..a547d57 100644 --- a/server/dao/file.go +++ b/server/dao/file.go @@ -77,6 +77,7 @@ func CreateFile(filename string, description string, resourceID uint, storageID if storageID == nil && redirectUrl == "" { return nil, errors.New("storageID and redirectUrl cannot be both empty") } + f := &model.File{ UUID: uuid.NewString(), Filename: filename, @@ -88,9 +89,23 @@ func CreateFile(filename string, description string, resourceID uint, storageID Size: size, UserID: userID, } - if err := db.Create(f).Error; err != nil { + + err := db.Transaction(func(tx *gorm.DB) error { + if err := tx.Create(f).Error; err != nil { + return err + } + err := tx.Model(&model.User{}).Where("id = ?", userID). + UpdateColumn("FilesCount", gorm.Expr("FilesCount + ?", 1)).Error + if err != nil { + return err + } + return nil + }) + + if err != nil { return nil, err } + return f, nil } @@ -108,14 +123,19 @@ func GetFile(id string) (*model.File, error) { func DeleteFile(id string) error { f := &model.File{} if err := db.Where("uuid = ?", id).First(f).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return model.NewNotFoundError("file not found") + return err + } + + if err := db.Transaction(func(tx *gorm.DB) error { + if err := tx.Delete(f).Error; err != nil { + return err } + return tx.Model(&model.User{}).Where("id = ?", f.UserID). + UpdateColumn("FilesCount", gorm.Expr("FilesCount - ?", 1)).Error + }); err != nil { return err } - if err := db.Delete(f).Error; err != nil { - return err - } + return nil } diff --git a/server/model/user.go b/server/model/user.go index de80ddf..8d9cf69 100644 --- a/server/model/user.go +++ b/server/model/user.go @@ -2,33 +2,36 @@ package model import ( "fmt" - "gorm.io/gorm" "time" + + "gorm.io/gorm" ) type User struct { gorm.Model - Username string `gorm:"uniqueIndex;not null"` - PasswordHash []byte - IsAdmin bool - CanUpload bool - AvatarVersion int - UploadsCount int - CommentsCount int - Resources []Resource `gorm:"foreignKey:UserID"` - Bio string + Username string `gorm:"uniqueIndex;not null"` + PasswordHash []byte + IsAdmin bool + CanUpload bool + AvatarVersion int + ResourcesCount int + FilesCount int + CommentsCount int + Resources []Resource `gorm:"foreignKey:UserID"` + Bio string } type UserView struct { - ID uint `json:"id"` - Username string `json:"username"` - CreatedAt time.Time `json:"created_at"` - AvatarPath string `json:"avatar_path"` - IsAdmin bool `json:"is_admin"` - CanUpload bool `json:"can_upload"` - UploadsCount int `json:"uploads_count"` - CommentsCount int `json:"comments_count"` - Bio string `json:"bio"` + ID uint `json:"id"` + Username string `json:"username"` + CreatedAt time.Time `json:"created_at"` + AvatarPath string `json:"avatar_path"` + IsAdmin bool `json:"is_admin"` + CanUpload bool `json:"can_upload"` + ResourcesCount int `json:"resources_count"` + FilesCount int `json:"files_count"` + CommentsCount int `json:"comments_count"` + Bio string `json:"bio"` } type UserViewWithToken struct { @@ -38,15 +41,16 @@ type UserViewWithToken struct { func (u User) ToView() UserView { return UserView{ - ID: u.ID, - Username: u.Username, - CreatedAt: u.CreatedAt, - AvatarPath: fmt.Sprintf("/api/user/avatar/%d?v=%d", u.ID, u.AvatarVersion), - IsAdmin: u.IsAdmin, - CanUpload: u.CanUpload || u.IsAdmin, - UploadsCount: u.UploadsCount, - CommentsCount: u.CommentsCount, - Bio: u.Bio, + ID: u.ID, + Username: u.Username, + CreatedAt: u.CreatedAt, + AvatarPath: fmt.Sprintf("/api/user/avatar/%d?v=%d", u.ID, u.AvatarVersion), + IsAdmin: u.IsAdmin, + CanUpload: u.CanUpload || u.IsAdmin, + ResourcesCount: u.ResourcesCount, + FilesCount: u.FilesCount, + CommentsCount: u.CommentsCount, + Bio: u.Bio, } }