108 lines
3.4 KiB
Go
108 lines
3.4 KiB
Go
package service
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"nl-pms-api/internal/commonservice"
|
|
"nl-pms-api/internal/model"
|
|
)
|
|
|
|
const avatarHistoryLimit = 12
|
|
|
|
// AvatarHistoryService 用户头像历史(与账号关联,多端可回选)。
|
|
type AvatarHistoryService struct {
|
|
DB *gorm.DB
|
|
}
|
|
|
|
// AvatarHistoryItem 对外一条历史。
|
|
type AvatarHistoryItem struct {
|
|
ID int64 `json:"id"`
|
|
Mode string `json:"mode"`
|
|
Value string `json:"value"`
|
|
CreatedAt string `json:"createdAt"`
|
|
}
|
|
|
|
// List 按时间倒序返回本人历史(最多 avatarHistoryLimit 条)。
|
|
func (s *AvatarHistoryService) List(userID int64) ([]AvatarHistoryItem, error) {
|
|
var rows []model.UserAvatarHistory
|
|
if err := s.DB.Where("user_id = ?", userID).Order("id DESC").Limit(avatarHistoryLimit).Find(&rows).Error; err != nil {
|
|
return nil, commonservice.Internal("QUERY_FAILED")
|
|
}
|
|
out := make([]AvatarHistoryItem, 0, len(rows))
|
|
for _, r := range rows {
|
|
out = append(out, AvatarHistoryItem{ID: r.ID, Mode: r.Mode, Value: r.Value, CreatedAt: r.CreatedAt})
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// Push 追加一条;同 value 去重后置顶;超出上限删最旧。
|
|
func (s *AvatarHistoryService) Push(userID int64, mode, value string) ([]AvatarHistoryItem, error) {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return nil, commonservice.BadRequest("AVATAR_VALUE_REQUIRED")
|
|
}
|
|
mode = strings.TrimSpace(strings.ToLower(mode))
|
|
if mode != "url" && mode != "base64" && mode != "path" {
|
|
if strings.HasPrefix(value, "http://") || strings.HasPrefix(value, "https://") {
|
|
mode = "url"
|
|
} else {
|
|
mode = "base64"
|
|
}
|
|
}
|
|
// path 仅本机有效,不入库线上历史
|
|
if mode == "path" {
|
|
return s.List(userID)
|
|
}
|
|
// 防爆:单条过大拒绝(约 1.5MB 文本)
|
|
if len(value) > 1_500_000 {
|
|
return nil, commonservice.BadRequest("AVATAR_VALUE_TOO_LARGE")
|
|
}
|
|
now := commonservice.NowRFC()
|
|
tx := s.DB.Begin()
|
|
if tx.Error != nil {
|
|
return nil, commonservice.Internal("SAVE_FAILED")
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
if err := tx.Where("user_id = ? AND value = ?", userID, value).Delete(&model.UserAvatarHistory{}).Error; err != nil {
|
|
return nil, commonservice.Internal("SAVE_FAILED")
|
|
}
|
|
row := model.UserAvatarHistory{UserID: userID, Mode: mode, Value: value, CreatedAt: now}
|
|
if err := tx.Create(&row).Error; err != nil {
|
|
return nil, commonservice.Internal("SAVE_FAILED")
|
|
}
|
|
// 超出上限:删掉最旧的多余行
|
|
var ids []int64
|
|
if err := tx.Model(&model.UserAvatarHistory{}).Where("user_id = ?", userID).
|
|
Order("id DESC").Limit(500).Pluck("id", &ids).Error; err != nil {
|
|
return nil, commonservice.Internal("SAVE_FAILED")
|
|
}
|
|
if len(ids) > avatarHistoryLimit {
|
|
drop := ids[avatarHistoryLimit:]
|
|
if err := tx.Where("user_id = ? AND id IN ?", userID, drop).Delete(&model.UserAvatarHistory{}).Error; err != nil {
|
|
return nil, commonservice.Internal("SAVE_FAILED")
|
|
}
|
|
}
|
|
if err := tx.Commit().Error; err != nil {
|
|
return nil, commonservice.Internal("SAVE_FAILED")
|
|
}
|
|
return s.List(userID)
|
|
}
|
|
|
|
// Delete 删除本人一条历史。
|
|
func (s *AvatarHistoryService) Delete(userID, id int64) error {
|
|
if id <= 0 {
|
|
return commonservice.BadRequest("ID_REQUIRED")
|
|
}
|
|
res := s.DB.Where("user_id = ? AND id = ?", userID, id).Delete(&model.UserAvatarHistory{})
|
|
if res.Error != nil {
|
|
return commonservice.Internal("DELETE_FAILED")
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return commonservice.NotFound("NOT_FOUND")
|
|
}
|
|
return nil
|
|
}
|