更新帖子相关功能
This commit is contained in:
parent
92b93e6037
commit
03172c5072
|
@ -1,3 +1,4 @@
|
|||
// file name: post_controller.go
|
||||
package controller
|
||||
|
||||
import (
|
||||
|
@ -5,6 +6,7 @@ import (
|
|||
"bbs-backend/api/request"
|
||||
"bbs-backend/common/errcode"
|
||||
"bbs-backend/common/response"
|
||||
"bbs-backend/dal/model"
|
||||
"bbs-backend/logic/appservice"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
|
@ -18,7 +20,7 @@ func CreatePost(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
post, err := appservice.CreatePost(req)
|
||||
post, err := appservice.CreatePost(c, req)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, errcode.ErrInternalServerError)
|
||||
return
|
||||
|
@ -54,11 +56,22 @@ func GetPost(c *gin.Context) {
|
|||
Title: post.Title,
|
||||
Content: post.Content,
|
||||
Author: post.Author.Username,
|
||||
Category: post.Category.Name,
|
||||
Tags: getTagNames(post.Tags),
|
||||
LikesCount: post.LikesCount,
|
||||
CommentsCount: post.CommentsCount,
|
||||
ViewsCount: post.ViewsCount,
|
||||
})
|
||||
}
|
||||
|
||||
func GetPosts(c *gin.Context) {
|
||||
posts, err := appservice.GetPosts()
|
||||
var req request.GetPostsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, errcode.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
posts, err := appservice.GetPosts(req)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, errcode.ErrInternalServerError)
|
||||
return
|
||||
|
@ -71,6 +84,11 @@ func GetPosts(c *gin.Context) {
|
|||
Title: post.Title,
|
||||
Content: post.Content,
|
||||
Author: post.Author.Username,
|
||||
Category: post.Category.Name,
|
||||
Tags: getTagNames(post.Tags),
|
||||
LikesCount: post.LikesCount,
|
||||
CommentsCount: post.CommentsCount,
|
||||
ViewsCount: post.ViewsCount,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -78,3 +96,11 @@ func GetPosts(c *gin.Context) {
|
|||
Posts: postReplies,
|
||||
})
|
||||
}
|
||||
|
||||
func getTagNames(tags []model.Tag) []string {
|
||||
var tagNames []string
|
||||
for _, tag := range tags {
|
||||
tagNames = append(tagNames, tag.Name)
|
||||
}
|
||||
return tagNames
|
||||
}
|
||||
|
|
66
api/controller/tag_controller.go
Normal file
66
api/controller/tag_controller.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
// file name: tag_controller.go
|
||||
package controller
|
||||
|
||||
import (
|
||||
"bbs-backend/api/request"
|
||||
"bbs-backend/common/errcode"
|
||||
"bbs-backend/common/response"
|
||||
"bbs-backend/logic/appservice"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CreateTag(c *gin.Context) {
|
||||
var req request.CreateTagRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, errcode.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
tag, err := appservice.CreateTag(req)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, errcode.ErrInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"id": tag.ID, "name": tag.Name})
|
||||
}
|
||||
|
||||
func UpdateTag(c *gin.Context) {
|
||||
tagID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusBadRequest, errcode.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req request.UpdateTagRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, errcode.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = appservice.UpdateTag(uint(tagID), req)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, errcode.ErrInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "Tag updated successfully"})
|
||||
}
|
||||
|
||||
func DeleteTag(c *gin.Context) {
|
||||
tagID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusBadRequest, errcode.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = appservice.DeleteTag(uint(tagID))
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, errcode.ErrInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "Tag deleted successfully"})
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
// file name: post_reply.go
|
||||
package reply
|
||||
|
||||
type CreatePostReply struct {
|
||||
|
@ -11,6 +12,11 @@ type GetPostReply struct {
|
|||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Author string `json:"author"`
|
||||
Category string `json:"category"`
|
||||
Tags []string `json:"tags"`
|
||||
LikesCount int `json:"likes_count"`
|
||||
CommentsCount int `json:"comments_count"`
|
||||
ViewsCount int `json:"views_count"`
|
||||
}
|
||||
|
||||
type GetPostsReply struct {
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
// file name: post_request.go
|
||||
package request
|
||||
|
||||
type CreatePostRequest struct {
|
||||
Title string `json:"title" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
CategoryID uint `json:"category_id" binding:"required"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
type GetPostsRequest struct {
|
||||
Page int `form:"page" binding:"required"`
|
||||
PageSize int `form:"pageSize" binding:"required"`
|
||||
Category string `form:"category"`
|
||||
}
|
||||
|
|
10
api/request/tag_request.go
Normal file
10
api/request/tag_request.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
// file name: tag_request.go
|
||||
package request
|
||||
|
||||
type CreateTagRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
|
||||
type UpdateTagRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
}
|
|
@ -9,18 +9,28 @@ import (
|
|||
func SetupRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
|
||||
// User 相关路由
|
||||
r.POST("/register", controller.Register)
|
||||
r.POST("/login", controller.Login)
|
||||
r.GET("/users/:id", controller.GetUserInfo)
|
||||
r.PUT("/update-user-info", controller.UpdateUserInfo)
|
||||
r.POST("/upload-avatar", controller.UploadAvatar)
|
||||
r.POST("/send-verification-code", controller.SendVerificationCode)
|
||||
r.POST("/verify-email", controller.VerifyEmail)
|
||||
|
||||
// Post 相关路由
|
||||
r.POST("/posts", controller.CreatePost)
|
||||
r.GET("/posts", controller.GetPosts)
|
||||
r.GET("/posts/:id", controller.GetPost)
|
||||
r.PUT("/update-user-info", controller.UpdateUserInfo) // 更新用户信息
|
||||
r.POST("/upload-avatar", controller.UploadAvatar) // 上传头像
|
||||
r.POST("/send-verification-code", controller.SendVerificationCode) // 发送验证码
|
||||
r.POST("/verify-email", controller.VerifyEmail) // 验证邮箱
|
||||
r.GET("/bbs-info", controller.GetBBSInfo) // 获取论坛信息
|
||||
r.PUT("/bbs-info", controller.UpdateBBSInfo) // 更新论坛信息
|
||||
|
||||
// BBS 相关路由
|
||||
r.GET("/bbs-info", controller.GetBBSInfo)
|
||||
r.PUT("/bbs-info", controller.UpdateBBSInfo)
|
||||
|
||||
// Tag 相关路由
|
||||
r.POST("/tags", controller.CreateTag)
|
||||
r.PUT("/tags/:id", controller.UpdateTag)
|
||||
r.DELETE("/tags/:id", controller.DeleteTag)
|
||||
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// file name: post_dao.go
|
||||
package dao
|
||||
|
||||
import (
|
||||
"bbs-backend/api/request"
|
||||
"bbs-backend/dal"
|
||||
"bbs-backend/dal/model"
|
||||
)
|
||||
|
@ -11,16 +13,23 @@ func CreatePost(post *model.Post) error {
|
|||
|
||||
func GetPostByID(postID uint) (*model.Post, error) {
|
||||
var post model.Post
|
||||
err := dal.DB.Preload("Author").First(&post, postID).Error
|
||||
err := dal.DB.Preload("Author").Preload("Category").Preload("Tags").First(&post, postID).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &post, nil
|
||||
}
|
||||
|
||||
func GetAllPosts() ([]*model.Post, error) {
|
||||
func GetPosts(req request.GetPostsRequest) ([]*model.Post, error) {
|
||||
var posts []*model.Post
|
||||
err := dal.DB.Preload("Author").Find(&posts).Error
|
||||
query := dal.DB.Preload("Author").Preload("Category").Preload("Tags")
|
||||
|
||||
if req.Category != "" {
|
||||
query = query.Joins("JOIN categories ON posts.category_id = categories.id").Where("categories.name = ?", req.Category)
|
||||
}
|
||||
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
err := query.Offset(offset).Limit(req.PageSize).Find(&posts).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
19
dal/dao/tag_dao.go
Normal file
19
dal/dao/tag_dao.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
// file name: tag_dao.go
|
||||
package dao
|
||||
|
||||
import (
|
||||
"bbs-backend/dal"
|
||||
"bbs-backend/dal/model"
|
||||
)
|
||||
|
||||
func CreateTag(tag *model.Tag) error {
|
||||
return dal.DB.Create(tag).Error
|
||||
}
|
||||
|
||||
func UpdateTag(tag *model.Tag) error {
|
||||
return dal.DB.Save(tag).Error
|
||||
}
|
||||
|
||||
func DeleteTag(tagID uint) error {
|
||||
return dal.DB.Delete(&model.Tag{}, tagID).Error
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
// file name: init_db.go
|
||||
package dal
|
||||
|
||||
import (
|
||||
|
@ -18,7 +19,7 @@ func MigrateAndSeedDB() {
|
|||
InitDB()
|
||||
|
||||
// Migrate the schema
|
||||
err := DB.AutoMigrate(&model.User{}, &model.Post{}, &model.Comment{}, &model.Category{}, &model.Role{}, &model.Session{}, &model.BBSConfig{})
|
||||
err := DB.AutoMigrate(&model.User{}, &model.Post{}, &model.Comment{}, &model.Category{}, &model.Role{}, &model.Session{}, &model.BBSConfig{}, &model.Tag{})
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to migrate database schema: %v", err)
|
||||
}
|
||||
|
@ -39,9 +40,11 @@ func MigrateAndSeedDB() {
|
|||
var userCount int64
|
||||
var categoryCount int64
|
||||
var configCount int64
|
||||
var tagCount int64
|
||||
DB.Model(&model.User{}).Where("username = ?", "admin").Count(&userCount)
|
||||
DB.Model(&model.Category{}).Where("name = ?", "General").Count(&categoryCount)
|
||||
DB.Model(&model.BBSConfig{}).Count(&configCount)
|
||||
DB.Model(&model.Tag{}).Where("name = ?", "default").Count(&tagCount)
|
||||
|
||||
if userCount == 0 {
|
||||
// Seed initial user data
|
||||
|
@ -103,4 +106,12 @@ func MigrateAndSeedDB() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tagCount == 0 {
|
||||
// Seed initial tag data
|
||||
tag := model.Tag{Name: "default"}
|
||||
if err := DB.FirstOrCreate(&tag, model.Tag{Name: tag.Name}).Error; err != nil {
|
||||
log.Fatalf("Failed to seed tag: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// file name: category_model.go
|
||||
package model
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// file name: post_model.go
|
||||
package model
|
||||
|
||||
import (
|
||||
|
@ -12,5 +13,9 @@ type Post struct {
|
|||
Author User
|
||||
CategoryID uint
|
||||
Category Category
|
||||
Tags []Tag `gorm:"many2many:post_tags;"`
|
||||
LikesCount int `gorm:"default:0"`
|
||||
CommentsCount int `gorm:"default:0"`
|
||||
ViewsCount int `gorm:"default:0"`
|
||||
Comments []Comment
|
||||
}
|
||||
|
|
12
dal/model/tag_model.go
Normal file
12
dal/model/tag_model.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
// file name: tag_model.go
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"type:varchar(100);unique;not null" json:"name"`
|
||||
Posts []Post `gorm:"many2many:post_tags;" json:"posts"`
|
||||
}
|
|
@ -1,20 +1,44 @@
|
|||
// file name: post_service.go
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"bbs-backend/api/request"
|
||||
"bbs-backend/common/errcode"
|
||||
"bbs-backend/dal"
|
||||
"bbs-backend/dal/model"
|
||||
"bbs-backend/logic/domainservice"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CreatePost(req request.CreatePostRequest) (*model.Post, error) {
|
||||
func CreatePost(c *gin.Context, req request.CreatePostRequest) (*model.Post, error) {
|
||||
// 获取当前用户的 ID
|
||||
userID, err := getUserIDFromToken(c)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrUnauthorized
|
||||
}
|
||||
|
||||
post := &model.Post{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
AuthorID: 1, // 假设当前用户ID为1
|
||||
AuthorID: userID,
|
||||
CategoryID: req.CategoryID,
|
||||
}
|
||||
|
||||
err := domainservice.CreatePostDomainService(post)
|
||||
// 处理标签
|
||||
var tags []model.Tag
|
||||
for _, tagName := range req.Tags {
|
||||
var tag model.Tag
|
||||
// 检查标签是否存在,如果不存在则创建
|
||||
if err := dal.DB.Where("name = ?", tagName).FirstOrCreate(&tag, model.Tag{Name: tagName}).Error; err != nil {
|
||||
return nil, errcode.ErrInternalServerError
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
post.Tags = tags
|
||||
|
||||
err = domainservice.CreatePostDomainService(post)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternalServerError
|
||||
}
|
||||
|
@ -22,6 +46,34 @@ func CreatePost(req request.CreatePostRequest) (*model.Post, error) {
|
|||
return post, nil
|
||||
}
|
||||
|
||||
func getUserIDFromToken(c *gin.Context) (uint, error) {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" {
|
||||
return 0, errcode.ErrUnauthorized
|
||||
}
|
||||
|
||||
tokenString := strings.Replace(authHeader, "Bearer ", "", 1)
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte("your_secret_key"), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 0, errcode.ErrUnauthorized
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok || !token.Valid {
|
||||
return 0, errcode.ErrUnauthorized
|
||||
}
|
||||
|
||||
userID, ok := claims["user_id"].(float64)
|
||||
if !ok {
|
||||
return 0, errcode.ErrUnauthorized
|
||||
}
|
||||
|
||||
return uint(userID), nil
|
||||
}
|
||||
|
||||
func GetPost(postID uint) (*model.Post, error) {
|
||||
post, err := domainservice.GetPostDomainService(postID)
|
||||
if err != nil {
|
||||
|
@ -30,8 +82,8 @@ func GetPost(postID uint) (*model.Post, error) {
|
|||
return post, nil
|
||||
}
|
||||
|
||||
func GetPosts() ([]*model.Post, error) {
|
||||
posts, err := domainservice.GetPostsDomainService()
|
||||
func GetPosts(req request.GetPostsRequest) ([]*model.Post, error) {
|
||||
posts, err := domainservice.GetPostsDomainService(req)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternalServerError
|
||||
}
|
||||
|
|
46
logic/appservice/tag_service.go
Normal file
46
logic/appservice/tag_service.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
// file name: tag_service.go
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"bbs-backend/api/request"
|
||||
"bbs-backend/common/errcode"
|
||||
"bbs-backend/dal/model"
|
||||
"bbs-backend/logic/domainservice"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateTag(req request.CreateTagRequest) (*model.Tag, error) {
|
||||
tag := &model.Tag{
|
||||
Name: req.Name,
|
||||
}
|
||||
|
||||
err := domainservice.CreateTagDomainService(tag)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternalServerError
|
||||
}
|
||||
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func UpdateTag(tagID uint, req request.UpdateTagRequest) error {
|
||||
tag := &model.Tag{
|
||||
Model: gorm.Model{ID: tagID},
|
||||
Name: req.Name,
|
||||
}
|
||||
|
||||
err := domainservice.UpdateTagDomainService(tag)
|
||||
if err != nil {
|
||||
return errcode.ErrInternalServerError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteTag(tagID uint) error {
|
||||
err := domainservice.DeleteTagDomainService(tagID)
|
||||
if err != nil {
|
||||
return errcode.ErrInternalServerError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
// file name: post_domain_service.go
|
||||
package domainservice
|
||||
|
||||
import (
|
||||
"bbs-backend/api/request"
|
||||
"bbs-backend/common/errcode"
|
||||
"bbs-backend/dal/dao"
|
||||
"bbs-backend/dal/model"
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreatePostDomainService(post *model.Post) error {
|
||||
|
@ -17,6 +17,7 @@ func CreatePostDomainService(post *model.Post) error {
|
|||
return errcode.ErrInvalidContent
|
||||
}
|
||||
|
||||
// 创建帖子
|
||||
err := dao.CreatePost(post)
|
||||
if err != nil {
|
||||
return errcode.ErrInternalServerError
|
||||
|
@ -28,17 +29,14 @@ func CreatePostDomainService(post *model.Post) error {
|
|||
func GetPostDomainService(postID uint) (*model.Post, error) {
|
||||
post, err := dao.GetPostByID(postID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errcode.ErrPostNotFound
|
||||
}
|
||||
return nil, errcode.ErrInternalServerError
|
||||
}
|
||||
|
||||
return post, nil
|
||||
}
|
||||
|
||||
func GetPostsDomainService() ([]*model.Post, error) {
|
||||
posts, err := dao.GetAllPosts()
|
||||
func GetPostsDomainService(req request.GetPostsRequest) ([]*model.Post, error) {
|
||||
posts, err := dao.GetPosts(req)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternalServerError
|
||||
}
|
||||
|
|
35
logic/domainservice/tag_domain_service.go
Normal file
35
logic/domainservice/tag_domain_service.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
// file name: tag_domain_service.go
|
||||
package domainservice
|
||||
|
||||
import (
|
||||
"bbs-backend/common/errcode"
|
||||
"bbs-backend/dal/dao"
|
||||
"bbs-backend/dal/model"
|
||||
)
|
||||
|
||||
func CreateTagDomainService(tag *model.Tag) error {
|
||||
err := dao.CreateTag(tag)
|
||||
if err != nil {
|
||||
return errcode.ErrInternalServerError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateTagDomainService(tag *model.Tag) error {
|
||||
err := dao.UpdateTag(tag)
|
||||
if err != nil {
|
||||
return errcode.ErrInternalServerError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteTagDomainService(tagID uint) error {
|
||||
err := dao.DeleteTag(tagID)
|
||||
if err != nil {
|
||||
return errcode.ErrInternalServerError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user