feat: 添加了social的关注功能

This commit is contained in:
Leon
2025-12-19 19:03:42 +08:00
parent 7e97fc5026
commit d2f40acf4d
6 changed files with 340 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ package db
import ( import (
"feedsystem_video_go/internal/account" "feedsystem_video_go/internal/account"
"feedsystem_video_go/internal/config" "feedsystem_video_go/internal/config"
"feedsystem_video_go/internal/social"
"feedsystem_video_go/internal/video" "feedsystem_video_go/internal/video"
"fmt" "fmt"
@@ -23,7 +24,7 @@ func NewDB(dbcfg config.DatabaseConfig) (*gorm.DB, error) {
} }
func AutoMigrate(db *gorm.DB) error { func AutoMigrate(db *gorm.DB) error {
return db.AutoMigrate(&account.Account{}, &video.Video{}, &video.Like{}, &video.Comment{}) return db.AutoMigrate(&account.Account{}, &video.Video{}, &video.Like{}, &video.Comment{}, &social.Social{})
} }
func CloseDB(db *gorm.DB) error { func CloseDB(db *gorm.DB) error {

View File

@@ -4,6 +4,7 @@ import (
"feedsystem_video_go/internal/account" "feedsystem_video_go/internal/account"
"feedsystem_video_go/internal/feed" "feedsystem_video_go/internal/feed"
"feedsystem_video_go/internal/middleware" "feedsystem_video_go/internal/middleware"
"feedsystem_video_go/internal/social"
"feedsystem_video_go/internal/video" "feedsystem_video_go/internal/video"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -73,6 +74,19 @@ func SetRouter(db *gorm.DB) *gin.Engine {
protectedCommentGroup.POST("/publish", commentHandler.PublishComment) protectedCommentGroup.POST("/publish", commentHandler.PublishComment)
protectedCommentGroup.POST("/delete", commentHandler.DeleteComment) protectedCommentGroup.POST("/delete", commentHandler.DeleteComment)
} }
// social
socialRepository := social.NewSocialRepository(db)
socialService := social.NewSocialService(socialRepository, accountRepository)
socialHandler := social.NewSocialHandler(socialService)
socialGroup := r.Group("/social")
protectedSocialGroup := socialGroup.Group("")
protectedSocialGroup.Use(middleware.JWTAuth(accountRepository))
{
protectedSocialGroup.POST("/follow", socialHandler.Follow)
protectedSocialGroup.POST("/unfollow", socialHandler.Unfollow)
protectedSocialGroup.POST("/getAllFollowers", socialHandler.GetAllFollowers)
protectedSocialGroup.POST("/getAllVloggers", socialHandler.GetAllVloggers)
}
// feed // feed
feedRepository := feed.NewFeedRepository(db) feedRepository := feed.NewFeedRepository(db)
feedService := feed.NewFeedService(feedRepository, likeRepository) feedService := feed.NewFeedService(feedRepository, likeRepository)

33
internal/social/entity.go Normal file
View File

@@ -0,0 +1,33 @@
package social
import "feedsystem_video_go/internal/account"
type Social struct {
ID uint `gorm:"primaryKey"`
FollowerID uint `gorm:"index"`
VloggerID uint `gorm:"index"`
}
type FollowRequest struct {
VloggerID uint `json:"vlogger_id"`
}
type UnfollowRequest struct {
VloggerID uint `json:"vlogger_id"`
}
type GetAllFollowersRequest struct {
VloggerID uint `json:"vlogger_id"`
}
type GetAllFollowersResponse struct {
Followers []*account.Account `json:"followers"`
}
type GetAllVloggersRequest struct {
FollowerID uint `json:"follower_id"`
}
type GetAllVloggersResponse struct {
Vloggers []*account.Account `json:"vloggers"`
}

118
internal/social/handler.go Normal file
View File

@@ -0,0 +1,118 @@
package social
import (
"feedsystem_video_go/internal/middleware"
"net/http"
"github.com/gin-gonic/gin"
)
type SocialHandler struct {
service *SocialService
}
func NewSocialHandler(service *SocialService) *SocialHandler {
return &SocialHandler{service: service}
}
func (h *SocialHandler) Follow(c *gin.Context) {
var req FollowRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if req.VloggerID <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "vlogger_id is required"})
return
}
FollowerID, err := middleware.GetAccountID(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
return
}
social := &Social{
FollowerID: FollowerID,
VloggerID: req.VloggerID,
}
if err := h.service.Follow(c.Request.Context(), social); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "followed"})
}
func (h *SocialHandler) Unfollow(c *gin.Context) {
var req UnfollowRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if req.VloggerID <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "vlogger_id is required"})
return
}
FollowerID, err := middleware.GetAccountID(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
return
}
social := &Social{
FollowerID: FollowerID,
VloggerID: req.VloggerID,
}
if err := h.service.Unfollow(c.Request.Context(), social); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "unfollowed"})
}
func (h *SocialHandler) GetAllFollowers(c *gin.Context) {
var req GetAllFollowersRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
vloggerID := req.VloggerID
if vloggerID == 0 {
accountID, err := middleware.GetAccountID(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
return
}
vloggerID = accountID
}
followers, err := h.service.GetAllFollowers(c.Request.Context(), vloggerID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, GetAllFollowersResponse{Followers: followers})
}
func (h *SocialHandler) GetAllVloggers(c *gin.Context) {
var req GetAllVloggersRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
followerID := req.FollowerID
if followerID == 0 {
accountID, err := middleware.GetAccountID(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
return
}
followerID = accountID
}
vloggers, err := h.service.GetAllVloggers(c.Request.Context(), followerID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, GetAllVloggersResponse{Vloggers: vloggers})
}

91
internal/social/repo.go Normal file
View File

@@ -0,0 +1,91 @@
package social
import (
"context"
"feedsystem_video_go/internal/account"
"gorm.io/gorm"
)
type SocialRepository struct {
db *gorm.DB
}
func NewSocialRepository(db *gorm.DB) *SocialRepository {
return &SocialRepository{db: db}
}
func (r *SocialRepository) Follow(ctx context.Context, social *Social) error {
return r.db.WithContext(ctx).Create(social).Error
}
func (r *SocialRepository) Unfollow(ctx context.Context, social *Social) error {
return r.db.WithContext(ctx).
Where("follower_id = ? AND vlogger_id = ?", social.FollowerID, social.VloggerID).
Delete(&Social{}).Error
}
func (r *SocialRepository) GetAllFollowers(ctx context.Context, VloggerID uint) ([]*account.Account, error) {
var relations []Social
if err := r.db.WithContext(ctx).
Model(&Social{}).
Where("vlogger_id = ?", VloggerID).
Find(&relations).Error; err != nil {
return nil, err
}
followerIDs := make([]uint, 0, len(relations))
for _, rel := range relations {
followerIDs = append(followerIDs, rel.FollowerID)
}
if len(followerIDs) == 0 {
return []*account.Account{}, nil
}
var followers []*account.Account
if err := r.db.WithContext(ctx).
Model(&account.Account{}).
Where("id IN ?", followerIDs).
Find(&followers).Error; err != nil {
return nil, err
}
return followers, nil
}
func (r *SocialRepository) GetAllVloggers(ctx context.Context, FollowerID uint) ([]*account.Account, error) {
var relations []Social
if err := r.db.WithContext(ctx).
Model(&Social{}).
Where("follower_id = ?", FollowerID).
Find(&relations).Error; err != nil {
return nil, err
}
vloggerIDs := make([]uint, 0, len(relations))
for _, rel := range relations {
vloggerIDs = append(vloggerIDs, rel.VloggerID)
}
if len(vloggerIDs) == 0 {
return []*account.Account{}, nil
}
var vloggers []*account.Account
if err := r.db.WithContext(ctx).
Model(&account.Account{}).
Where("id IN ?", vloggerIDs).
Find(&vloggers).Error; err != nil {
return nil, err
}
return vloggers, nil
}
func (r *SocialRepository) IsFollowed(ctx context.Context, social *Social) (bool, error) {
var count int64
if err := r.db.WithContext(ctx).
Model(&Social{}).
Where("follower_id = ? AND vlogger_id = ?", social.FollowerID, social.VloggerID).
Count(&count).Error; err != nil {
return false, err
}
return count > 0, nil
}

View File

@@ -0,0 +1,82 @@
package social
import (
"context"
"errors"
"feedsystem_video_go/internal/account"
)
type SocialService struct {
repo *SocialRepository
accountrepo *account.AccountRepository
}
func NewSocialService(repo *SocialRepository, accountrepo *account.AccountRepository) *SocialService {
return &SocialService{repo: repo, accountrepo: accountrepo}
}
func (s *SocialService) Follow(ctx context.Context, social *Social) error {
_, err := s.accountrepo.FindByID(ctx, social.FollowerID)
if err != nil {
return err
}
_, err = s.accountrepo.FindByID(ctx, social.VloggerID)
if err != nil {
return err
}
isFollowed, err := s.repo.IsFollowed(ctx, social)
if err != nil {
return err
}
if isFollowed {
return errors.New("already followed")
}
return s.repo.Follow(ctx, social)
}
func (s *SocialService) Unfollow(ctx context.Context, social *Social) error {
_, err := s.accountrepo.FindByID(ctx, social.FollowerID)
if err != nil {
return err
}
_, err = s.accountrepo.FindByID(ctx, social.VloggerID)
if err != nil {
return err
}
isFollowed, err := s.repo.IsFollowed(ctx, social)
if err != nil {
return err
}
if !isFollowed {
return errors.New("not followed")
}
return s.repo.Unfollow(ctx, social)
}
func (s *SocialService) GetAllFollowers(ctx context.Context, VloggerID uint) ([]*account.Account, error) {
_, err := s.accountrepo.FindByID(ctx, VloggerID)
if err != nil {
return nil, err
}
return s.repo.GetAllFollowers(ctx, VloggerID)
}
func (s *SocialService) GetAllVloggers(ctx context.Context, FollowerID uint) ([]*account.Account, error) {
_, err := s.accountrepo.FindByID(ctx, FollowerID)
if err != nil {
return nil, err
}
return s.repo.GetAllVloggers(ctx, FollowerID)
}
func (s *SocialService) IsFollowed(ctx context.Context, social *Social) (bool, error) {
_, err := s.accountrepo.FindByID(ctx, social.FollowerID)
if err != nil {
return false, err
}
_, err = s.accountrepo.FindByID(ctx, social.VloggerID)
if err != nil {
return false, err
}
return s.repo.IsFollowed(ctx, social)
}