Files
go_blog/models/article_view.go
T
kevin f307781f58 docs: 全部 Go 代码注释汉化
- 48 个 Go 文件所有注释(行注释/块注释/行尾注释,含 _test.go)翻译为中文
- 保留技术标识符:SECURITY_TODO(n)、unsafe-inline、sqlite/mysql、路由参数等
- 代码、字符串字面量、日志消息保持英文原文,零逻辑改动
- go build/vet 通过,go test -count=1 ./... 全绿
2026-08-27 19:03:03 +08:00

49 lines
1.5 KiB
Go

package models
import (
"time"
"gorm.io/gorm"
)
// ArticleView 表示一条唯一的文章浏览记录。
// 每条记录跟踪一次(按 IP 或用户)对文章的唯一访问。
type ArticleView struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
ArticleID uint `gorm:"not null;index:idx_article_views_article" json:"article_id"`
UserID *uint `gorm:"index:idx_article_views_user" json:"user_id"` // 匿名用户为 NULL
IP string `gorm:"size:64;not null;index:idx_article_views_ip" json:"ip"`
UserAgent string `gorm:"size:512" json:"user_agent"`
IsBot bool `gorm:"default:false;index:idx_article_views_bot" json:"is_bot"`
Article Article `gorm:"foreignKey:ArticleID" json:"-"`
User *User `gorm:"foreignKey:UserID" json:"-"`
}
// TableName 覆盖 GORM 默认的表名。
func (ArticleView) TableName() string {
return "article_views"
}
// BeforeCreate 钩子确保不会创建重复记录。
// 这是在应用层去重之外的另一道安全校验。
func (av *ArticleView) BeforeCreate(tx *gorm.DB) error {
var count int64
query := tx.Model(&ArticleView{}).
Where("article_id = ? AND ip = ?", av.ArticleID, av.IP)
if av.UserID != nil {
query = query.Where("user_id = ?", *av.UserID)
} else {
query = query.Where("user_id IS NULL")
}
query.Count(&count)
if count > 0 {
// 记录已存在,跳过创建
return gorm.ErrDuplicatedKey
}
return nil
}