move: 后端
This commit is contained in:
33
backend/internal/social/entity.go
Normal file
33
backend/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:"not null;index:idx_social_follower;uniqueIndex:idx_social_follower_vlogger"`
|
||||
VloggerID uint `gorm:"not null;index:idx_social_vlogger;uniqueIndex:idx_social_follower_vlogger"`
|
||||
}
|
||||
|
||||
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
backend/internal/social/handler.go
Normal file
118
backend/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
backend/internal/social/repo.go
Normal file
91
backend/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
|
||||
}
|
||||
85
backend/internal/social/service.go
Normal file
85
backend/internal/social/service.go
Normal file
@@ -0,0 +1,85 @@
|
||||
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
|
||||
}
|
||||
if social.FollowerID == social.VloggerID {
|
||||
return errors.New("can not follow self")
|
||||
}
|
||||
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