Files
jiang13-forum/service/user.go
freefire 060b7707cb 支持公开用户主页、帖子图缩略图与编辑器图组排版。
新增用户签名与活动统计、图片灯箱;正文按需生成缩略图;TipTap 支持多图分组与环绕排版,并注入站点标题避免刷新闪烁。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-01 12:29:50 +08:00

154 lines
4.5 KiB
Go

package service
import (
"errors"
"fmt"
"mime/multipart"
"strings"
"time"
"git.iioio.com/freefire/jiang13-forum/model"
)
type UserService struct {
filter *SensitiveFilter
settings *ForumSettingsService
}
func NewUserService(filter *SensitiveFilter, settings *ForumSettingsService) *UserService {
return &UserService{filter: filter, settings: settings}
}
// GetByID 获取用户信息
func (s *UserService) GetByID(id uint) (*model.User, error) {
var user model.User
if err := model.DB.First(&user, id).Error; err != nil {
return nil, err
}
return &user, nil
}
// UserActivityStats 个人主页活动统计
type UserActivityStats struct {
PostCount int64 `json:"post_count"`
CommentCount int64 `json:"comment_count"`
FavoriteCount int64 `json:"favorite_count"`
LikeReceived int64 `json:"like_received"`
}
// ActivityStats 统计用户发帖、评论、收藏与帖子获赞
func (s *UserService) ActivityStats(userID uint) (UserActivityStats, error) {
var st UserActivityStats
if userID == 0 {
return st, errors.New("无效用户")
}
if err := model.DB.Model(&model.Post{}).Where("user_id = ?", userID).Count(&st.PostCount).Error; err != nil {
return st, err
}
if err := model.DB.Model(&model.Comment{}).Where("user_id = ?", userID).Count(&st.CommentCount).Error; err != nil {
return st, err
}
if err := model.DB.Model(&model.PostFavorite{}).Where("user_id = ?", userID).Count(&st.FavoriteCount).Error; err != nil {
return st, err
}
var likeSum int64
if err := model.DB.Model(&model.Post{}).
Select("COALESCE(SUM(like_count), 0)").
Where("user_id = ?", userID).
Scan(&likeSum).Error; err != nil {
return st, err
}
st.LikeReceived = likeSum
return st, nil
}
// GetByUsername 按用户名查询
func (s *UserService) GetByUsername(username string) (*model.User, error) {
var user model.User
if err := model.DB.Where("username = ?", username).First(&user).Error; err != nil {
return nil, err
}
return &user, nil
}
// UpdateNickname 修改昵称
func (s *UserService) UpdateNickname(userID uint, nickname string) error {
nickname = strings.TrimSpace(nickname)
if nickname == "" {
return errors.New("昵称不能为空")
}
nickname = s.filter.Filter(nickname)
return model.DB.Model(&model.User{}).Where("id = ?", userID).Update("nickname", nickname).Error
}
// UpdateSignature 修改个人签名
func (s *UserService) UpdateSignature(userID uint, signature string) error {
signature = strings.TrimSpace(signature)
maxLen := s.settings.SignatureMax()
if maxLen > 0 {
runes := []rune(signature)
if len(runes) > maxLen {
return fmt.Errorf("签名不能超过 %d 字", maxLen)
}
}
if signature != "" {
signature = s.filter.Filter(signature)
}
return model.DB.Model(&model.User{}).Where("id = ?", userID).Update("signature", signature).Error
}
// UpdatePassword 修改密码
func (s *UserService) UpdatePassword(userID uint, oldPass, newPass string) error {
if err := ValidatePassword(newPass, s.settings.PasswordMinLen()); err != nil {
return err
}
var user model.User
if err := model.DB.First(&user, userID).Error; err != nil {
return err
}
if !CheckPassword(user.Password, oldPass) {
return errors.New("原密码错误")
}
hash, err := HashPassword(newPass)
if err != nil {
return err
}
return model.DB.Model(&user).Update("password", hash).Error
}
// UploadAvatar 上传头像到本地目录
func (s *UserService) UploadAvatar(userID uint, file *multipart.FileHeader, uploadDir string) (string, error) {
url, err := SaveUploadedImage(file, uploadDir, "/uploads/avatars", fmt.Sprintf("%d", userID))
if err != nil {
return "", err
}
return url, model.DB.Model(&model.User{}).Where("id = ?", userID).Update("avatar", url).Error
}
// ListUsers 管理员列出用户
func (s *UserService) ListUsers(page, size int) ([]model.User, int64, error) {
var users []model.User
var total int64
model.DB.Model(&model.User{}).Count(&total)
offset := (page - 1) * size
err := model.DB.Order("id desc").Offset(offset).Limit(size).Find(&users).Error
return users, total, err
}
// BanUser 禁言用户
func (s *UserService) BanUser(userID uint, banned bool) error {
var user model.User
if err := model.DB.First(&user, userID).Error; err != nil {
return errors.New("用户不存在")
}
if user.Role == model.RoleAdmin {
return errors.New("不能禁言管理员账号")
}
now := time.Now()
updates := map[string]interface{}{"banned": banned}
if banned {
updates["banned_at"] = &now
}
return model.DB.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error
}