Files
go_blog/models/file.go
T
dsh 942e3174b9 feat: 头像上传纳入统一上传引擎——files 表登记 type=avatars
- 提取共享上传引擎 saveUploadedFile(handlers/attachment.go):
  内容 SHA-256 寻址写入 + 磁盘去重 + files 表登记,供附件/头像共用
- UploadAvatar 改用该引擎:处理后 JPEG 以哈希命名存储,登记
  models.FileTypeAvatar('avatars')记录;用户 Avatar 字段 = 哈希,
  公开链接 /uploads/avatars/<哈希>(沿用原有 avatars/ 目录与路由)
- 更换头像时:旧登记行软删除;仅当无其他 files 记录或用户引用时
  删除旧磁盘文件(与附件一致的引用计数语义)
- 既有头像安全测试断言从 <uid>.jpg 改为 64 位哈希;
  新增 TestAvatarUploadRegistersFileRow 覆盖登记/磁盘/替换清理全流程
2026-08-28 20:13:13 +08:00

56 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package models
import (
"time"
"gorm.io/gorm"
)
// File 是全站统一的上传文件登记表,用于管理所有类型的上传文件
// (附件、头像、Logo 等)。字段与原 attachments 表对齐,额外通过
// Type 字段区分文件归属类型。
//
// 生命周期(方案 A——先上传后绑定):
// - 在文章创建页面上文章尚不存在,因此 ArticleID 为 0
// 该行暂时由 SessionToken(为页面会话生成的随机值)持有。
// - 保存文章时,ArticleCreate 通过 SessionToken 绑定待处理行,
// 设置它们的 ArticleID 并清除令牌。
// - 在编辑页面上,上传直接携带真实的 ArticleID。
//
// 磁盘去重:StoredName 是文件内容的 SHA-256。写入前,
// 处理器会检查磁盘上是否已存在同名文件;若已存在则复用(不重写)。
// 删除采用引用计数——仅当没有任何 File 行引用时,才删除磁盘文件。
type File struct {
ID uint `gorm:"primarykey" json:"id"`
Type string `gorm:"size:32;index;default:attachments" json:"type"` // 归属类型:attachment 等
ArticleID uint `gorm:"index" json:"article_id"` // 在创建页面上待绑定时为 0
SessionToken string `gorm:"size:64;index" json:"-"` // 创建页面上的临时归属令牌
UploaderID uint `gorm:"index" json:"uploader_id"`
Filename string `gorm:"size:255" json:"filename"` // 原始文件名
StoredName string `gorm:"size:64;index" json:"stored_name"` // SHA-256 十六进制字符串,磁盘文件名
Ext string `gorm:"size:32" json:"ext"`
MIME string `gorm:"size:128" json:"mime"`
Size int64 `gorm:"default:0" json:"size"`
Category string `gorm:"size:32" json:"category"` // image/document/archive/video/other
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
}
// TableName 覆盖 GORM 默认的表名。
func (File) TableName() string {
return "files"
}
// FileTypeAttachment 是文件归属类型常量:文章附件(原 attachments 表历史数据)。
const FileTypeAttachment = "attachments"
// FileTypeAvatar 是文件归属类型常量:用户头像(存储于 avatars/ 目录,
// 公开下载链接为 /uploads/avatars/<stored_name>)。
const FileTypeAvatar = "avatars"
// IsImage 报告该文件是否为图片(用于决定 Markdown 插入形式:![]() 还是 []())。
func (f *File) IsImage() bool {
return f.Category == CategoryImage
}