feat(video): add like/unlike/isliked/getlikescount APIs for videos
This commit is contained in:
@@ -23,7 +23,7 @@ func NewDB(dbcfg config.DatabaseConfig) (*gorm.DB, error) {
|
||||
}
|
||||
|
||||
func AutoMigrate(db *gorm.DB) error {
|
||||
return db.AutoMigrate(&account.Account{}, &video.Video{})
|
||||
return db.AutoMigrate(&account.Account{}, &video.Video{}, &video.Like{})
|
||||
}
|
||||
|
||||
func CloseDB(db *gorm.DB) error {
|
||||
|
||||
@@ -44,6 +44,21 @@ func SetRouter(db *gorm.DB) *gin.Engine {
|
||||
{
|
||||
protectedVideoGroup.POST("/publish", videoHandler.PublishVideo)
|
||||
}
|
||||
// like
|
||||
likeRepository := video.NewLikeRepository(db)
|
||||
likeService := video.NewLikeService(likeRepository)
|
||||
likeHandler := video.NewLikeHandler(likeService)
|
||||
likeGroup := r.Group("/like")
|
||||
{
|
||||
likeGroup.POST("/getLikesCount", likeHandler.GetLikesCount)
|
||||
}
|
||||
protectedLikeGroup := likeGroup.Group("")
|
||||
protectedLikeGroup.Use(middleware.JWTAuth(accountRepository))
|
||||
{
|
||||
protectedLikeGroup.POST("/like", likeHandler.Like)
|
||||
protectedLikeGroup.POST("/unlike", likeHandler.Unlike)
|
||||
protectedLikeGroup.POST("/isLiked", likeHandler.IsLiked)
|
||||
}
|
||||
|
||||
// feed
|
||||
feedRepository := feed.NewFeedRepository(db)
|
||||
|
||||
10
internal/video/like_entity.go
Normal file
10
internal/video/like_entity.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package video
|
||||
|
||||
import "time"
|
||||
|
||||
type Like struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
VideoID uint `gorm:"index, not null"`
|
||||
AccountID uint `gorm:"index, not null"`
|
||||
CreatedAt time.Time
|
||||
}
|
||||
117
internal/video/like_handler.go
Normal file
117
internal/video/like_handler.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package video
|
||||
|
||||
import (
|
||||
"feedsystem_video_go/internal/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type LikeRequest struct {
|
||||
VideoID uint `json:"video_id"`
|
||||
}
|
||||
|
||||
type LikeHandler struct {
|
||||
service *LikeService
|
||||
}
|
||||
|
||||
func NewLikeHandler(service *LikeService) *LikeHandler {
|
||||
return &LikeHandler{service: service}
|
||||
}
|
||||
|
||||
func (lh *LikeHandler) Like(c *gin.Context) {
|
||||
var req LikeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if req.VideoID <= 0 {
|
||||
c.JSON(400, gin.H{"error": "video_id is required"})
|
||||
return
|
||||
}
|
||||
|
||||
accountID, err := middleware.GetAccountID(c)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
like := &Like{
|
||||
VideoID: req.VideoID,
|
||||
AccountID: accountID,
|
||||
}
|
||||
if err := lh.service.Like(c.Request.Context(), like); err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"message": "like success"})
|
||||
}
|
||||
|
||||
func (lh *LikeHandler) Unlike(c *gin.Context) {
|
||||
var req LikeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if req.VideoID <= 0 {
|
||||
c.JSON(400, gin.H{"error": "video_id is required"})
|
||||
return
|
||||
}
|
||||
|
||||
accountID, err := middleware.GetAccountID(c)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
like := &Like{
|
||||
VideoID: req.VideoID,
|
||||
AccountID: accountID,
|
||||
}
|
||||
if err := lh.service.Unlike(c.Request.Context(), like); err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"message": "unlike success"})
|
||||
}
|
||||
|
||||
func (lh *LikeHandler) IsLiked(c *gin.Context) {
|
||||
var req LikeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if req.VideoID <= 0 {
|
||||
c.JSON(400, gin.H{"error": "video_id is required"})
|
||||
return
|
||||
}
|
||||
|
||||
accountID, err := middleware.GetAccountID(c)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
isLiked, err := lh.service.IsLiked(c.Request.Context(), req.VideoID, accountID)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"is_liked": isLiked})
|
||||
}
|
||||
|
||||
func (lh *LikeHandler) GetLikesCount(c *gin.Context) {
|
||||
var req LikeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if req.VideoID <= 0 {
|
||||
c.JSON(400, gin.H{"error": "video_id is required"})
|
||||
return
|
||||
}
|
||||
likesCount, err := lh.service.GetLikesCount(c.Request.Context(), req.VideoID)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"likes_count": likesCount})
|
||||
}
|
||||
47
internal/video/like_repo.go
Normal file
47
internal/video/like_repo.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package video
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type LikeRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewLikeRepository(db *gorm.DB) *LikeRepository {
|
||||
return &LikeRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *LikeRepository) Like(ctx context.Context, like *Like) error {
|
||||
return r.db.WithContext(ctx).Create(like).Error
|
||||
}
|
||||
|
||||
func (r *LikeRepository) Unlike(ctx context.Context, like *Like) error {
|
||||
return r.db.WithContext(ctx).
|
||||
Where("video_id = ? AND account_id = ?", like.VideoID, like.AccountID).
|
||||
Delete(&Like{}).Error
|
||||
}
|
||||
|
||||
func (r *LikeRepository) IsLiked(ctx context.Context, videoID, accountID uint) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&Like{}).
|
||||
Where("video_id = ? AND account_id = ?", videoID, accountID).
|
||||
Count(&count).Error
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (r *LikeRepository) GetLikesCount(ctx context.Context, videoID uint) (int64, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&Like{}).
|
||||
Where("video_id = ?", videoID).
|
||||
Count(&count).Error
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
38
internal/video/like_service.go
Normal file
38
internal/video/like_service.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package video
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LikeService struct {
|
||||
repo *LikeRepository
|
||||
}
|
||||
|
||||
func NewLikeService(repo *LikeRepository) *LikeService {
|
||||
return &LikeService{repo: repo}
|
||||
}
|
||||
|
||||
func (s *LikeService) Like(ctx context.Context, like *Like) error {
|
||||
if isLiked, err := s.IsLiked(ctx, like.VideoID, like.AccountID); err == nil && isLiked {
|
||||
return errors.New("user has liked this video")
|
||||
}
|
||||
like.CreatedAt = time.Now()
|
||||
return s.repo.Like(ctx, like)
|
||||
}
|
||||
|
||||
func (s *LikeService) Unlike(ctx context.Context, like *Like) error {
|
||||
if isLiked, err := s.IsLiked(ctx, like.VideoID, like.AccountID); err == nil && !isLiked {
|
||||
return errors.New("user has not liked this video")
|
||||
}
|
||||
return s.repo.Unlike(ctx, like)
|
||||
}
|
||||
|
||||
func (s *LikeService) IsLiked(ctx context.Context, videoID, accountID uint) (bool, error) {
|
||||
return s.repo.IsLiked(ctx, videoID, accountID)
|
||||
}
|
||||
|
||||
func (s *LikeService) GetLikesCount(ctx context.Context, videoID uint) (int64, error) {
|
||||
return s.repo.GetLikesCount(ctx, videoID)
|
||||
}
|
||||
Reference in New Issue
Block a user