refactor: Controller 不直接读 Session Exp,新增 CanCreatePost 方法

- 新增 userExpReader 最小接口(ISP),PostService 通过它读取用户经验值
- PostService 新增 CanCreatePost(userID uint) bool,封装 LV0 投稿权限判断
- StudioController 替换内联 c.Get("exp") 检查为调用 ctrl.postService.CanCreatePost(uid)
- 更新 DI 注入链:NewPostService 增加 userRepo 参数
This commit is contained in:
2026-06-02 16:52:44 +08:00
parent 3df7b2e672
commit 3e0fed80ce
5 changed files with 23 additions and 8 deletions

View File

@ -40,7 +40,7 @@ type postUseCase interface {
IsPostAccessible(userID uint, role string, postUserID uint) bool IsPostAccessible(userID uint, role string, postUserID uint) bool
} }
// studioUseCase StudioController 对 PostService 的最小依赖ISP8 个方法) // studioUseCase StudioController 对 PostService 的最小依赖ISP9 个方法)
type studioUseCase interface { type studioUseCase interface {
Create(userID uint, title, body string) (*model.Post, error) Create(userID uint, title, body string) (*model.Post, error)
GetByID(id uint) (*model.Post, error) GetByID(id uint) (*model.Post, error)
@ -50,6 +50,7 @@ type studioUseCase interface {
ListByUser(userID uint, status string, page, pageSize int) ([]model.Post, int64, error) ListByUser(userID uint, status string, page, pageSize int) ([]model.Post, int64, error)
GetOverview(userID uint) (*service.StudioOverview, error) GetOverview(userID uint) (*service.StudioOverview, error)
IsPostAccessible(userID uint, role string, postUserID uint) bool IsPostAccessible(userID uint, role string, postUserID uint) bool
CanCreatePost(userID uint) bool
} }
// spaceUseCase SpaceController 对 SpaceService 的最小依赖ISP5 个方法) // spaceUseCase SpaceController 对 SpaceService 的最小依赖ISP5 个方法)

View File

@ -19,12 +19,10 @@ func (ctrl *StudioController) Create(c *gin.Context) {
} }
// LV0 用户不允许投稿 // LV0 用户不允许投稿
if expVal, exists := c.Get("exp"); exists { if !ctrl.postService.CanCreatePost(uid) {
if exp, ok := expVal.(int); ok && exp < 1 {
common.Error(c, http.StatusForbidden, "经验不足Lv1 解锁投稿") common.Error(c, http.StatusForbidden, "经验不足Lv1 解锁投稿")
return return
} }
}
var req model.PostCreateRequest var req model.PostCreateRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@ -51,7 +51,7 @@ func buildDeps(db *gorm.DB, cfg *config.Config, siteSettings *config.SiteSetting
) )
postRepo := repository.NewPostRepo(db) postRepo := repository.NewPostRepo(db)
postService := service.NewPostService(postRepo, siteSettings, notificationService) postService := service.NewPostService(postRepo, siteSettings, notificationService, userRepo)
shortcodeSvc := service.NewShortcodeService() shortcodeSvc := service.NewShortcodeService()
postCtrl := controller.NewPostController(postService, shortcodeSvc) postCtrl := controller.NewPostController(postService, shortcodeSvc)
adminPostCtrl := adminCtrl.NewAdminPostController(postService) adminPostCtrl := adminCtrl.NewAdminPostController(postService)

View File

@ -16,14 +16,16 @@ type PostService struct {
repo postStore repo postStore
ss *config.SiteSettings ss *config.SiteSettings
notifier postNotifier notifier postNotifier
userRepo userExpReader
} }
// NewPostService 构造函数 // NewPostService 构造函数
func NewPostService(repo postStore, ss *config.SiteSettings, notifier postNotifier) *PostService { func NewPostService(repo postStore, ss *config.SiteSettings, notifier postNotifier, userRepo userExpReader) *PostService {
return &PostService{ return &PostService{
repo: repo, repo: repo,
ss: ss, ss: ss,
notifier: notifier, notifier: notifier,
userRepo: userRepo,
} }
} }
@ -145,6 +147,15 @@ func (s *PostService) IsPostAccessible(userID uint, role string, postUserID uint
return userID == postUserID || model.HasMinRole(role, model.RoleModerator) return userID == postUserID || model.HasMinRole(role, model.RoleModerator)
} }
// CanCreatePost 检查用户是否可以创建帖子LV0 用户不允许投稿)
func (s *PostService) CanCreatePost(userID uint) bool {
user, err := s.userRepo.FindByID(userID)
if err != nil {
return false
}
return user.Exp >= 1
}
// RecordRead 记录已登录用户阅读文章(已登录去重 + 防刷冷却) // RecordRead 记录已登录用户阅读文章(已登录去重 + 防刷冷却)
func (s *PostService) RecordRead(userID, postID uint) { func (s *PostService) RecordRead(userID, postID uint) {
firstRead, err := s.repo.RecordRead(userID, postID) firstRead, err := s.repo.RecordRead(userID, postID)

View File

@ -66,6 +66,11 @@ type postAdminStatStore interface {
CountPending() (int64, error) CountPending() (int64, error)
} }
// userExpReader PostService 读取用户经验值的最小接口ISP
type userExpReader interface {
FindByID(id uint) (*model.User, error)
}
// postNotifier PostService 所需的通知服务接口 // postNotifier PostService 所需的通知服务接口
type postNotifier interface { type postNotifier interface {
NotifyPostApproved(userID uint, postTitle string, postID uint) NotifyPostApproved(userID uint, postTitle string, postID uint)