feat: 添加了social的关注功能
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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
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