feat: 添加了social的关注功能
This commit is contained in:
@@ -3,6 +3,7 @@ package db
|
||||
import (
|
||||
"feedsystem_video_go/internal/account"
|
||||
"feedsystem_video_go/internal/config"
|
||||
"feedsystem_video_go/internal/social"
|
||||
"feedsystem_video_go/internal/video"
|
||||
"fmt"
|
||||
|
||||
@@ -23,7 +24,7 @@ func NewDB(dbcfg config.DatabaseConfig) (*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 {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"feedsystem_video_go/internal/account"
|
||||
"feedsystem_video_go/internal/feed"
|
||||
"feedsystem_video_go/internal/middleware"
|
||||
"feedsystem_video_go/internal/social"
|
||||
"feedsystem_video_go/internal/video"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -73,6 +74,19 @@ func SetRouter(db *gorm.DB) *gin.Engine {
|
||||
protectedCommentGroup.POST("/publish", commentHandler.PublishComment)
|
||||
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
|
||||
feedRepository := feed.NewFeedRepository(db)
|
||||
feedService := feed.NewFeedService(feedRepository, likeRepository)
|
||||
|
||||
33
internal/social/entity.go
Normal file
33
internal/social/entity.go
Normal 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
118
internal/social/handler.go
Normal 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
91
internal/social/repo.go
Normal 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
|
||||
}
|
||||
82
internal/social/service.go
Normal file
82
internal/social/service.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user