recommender/internal/handler/http/controller/application_v1/users.go
2024-11-10 03:49:53 +08:00

288 lines
8.3 KiB
Go

package application_v1
import (
"github.com/gin-gonic/gin"
"leafdev.top/Ecosystem/recommender/internal/base/logger"
"leafdev.top/Ecosystem/recommender/internal/base/redis"
"leafdev.top/Ecosystem/recommender/internal/handler/http/request"
"leafdev.top/Ecosystem/recommender/internal/handler/http/response"
"leafdev.top/Ecosystem/recommender/internal/service/application"
"leafdev.top/Ecosystem/recommender/internal/service/auth"
"leafdev.top/Ecosystem/recommender/internal/service/category"
"leafdev.top/Ecosystem/recommender/internal/service/post"
"leafdev.top/Ecosystem/recommender/internal/service/user"
"leafdev.top/Ecosystem/recommender/pkg/consts"
"net/http"
"time"
)
const TaskProcessing = "user_likes"
var LockTTL = time.Minute * 10
type UserController struct {
authService *auth.Service
applicationService *application.Service
userService *user.Service
postService *post.Service
logger *logger.Logger
redis *redis.Redis
categoryService *category.Service
}
func NewUserController(
authService *auth.Service,
applicationService *application.Service,
userService *user.Service,
postService *post.Service,
logger *logger.Logger,
redis *redis.Redis,
categoryService *category.Service,
) *UserController {
return &UserController{
authService: authService,
applicationService: applicationService,
userService: userService,
postService: postService,
logger: logger,
redis: redis,
categoryService: categoryService,
}
}
// Like godoc
// @Summary Like
// @Description 将标签附加到用户名
// @Tags application_api
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param UserLikePost body request.UserLikePost true "UserLikePost"
// @Failure 400 {object} response.ResponseBody
// @Router /applications/v1/users/_like [post]
func (uc *UserController) Like(c *gin.Context) {
app, err := uc.authService.GetApplication(c)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusBadRequest).Send()
return
}
var userLikePostRequest = &request.UserLikePost{}
if err := c.ShouldBindJSON(userLikePostRequest); err != nil {
response.Ctx(c).Error(err).Status(http.StatusBadRequest).Send()
return
}
externalUser, err := uc.userService.GetOrCreateExternalUser(c, userLikePostRequest.ExternalUserId, app)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
// posts
postEntity, err := uc.postService.GetPostById(c, userLikePostRequest.PostId)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
if postEntity.ApplicationId != app.Id {
response.Ctx(c).Status(http.StatusNotFound).Send()
return
}
if !postEntity.Vectorized || !postEntity.Processed {
response.Ctx(c).Status(http.StatusBadRequest).Error(consts.ErrPostNotReady).Send()
return
}
// 检测是否有
var cacheKey = uc.redis.Prefix(TaskProcessing + ":" + userLikePostRequest.PostId.String())
// if exists
exists, err := uc.redis.Client.Exists(c, cacheKey).Result()
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
if exists > 0 {
response.Ctx(c).Status(http.StatusTooEarly).Error(consts.ErrAnotherOperationInProgress).Send()
return
}
_, err = uc.redis.Client.Set(c, cacheKey, userLikePostRequest.ExternalUserId, LockTTL).Result()
go func(prefix string) {
err = uc.userService.LikePost(c, externalUser, app, postEntity)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
_, err := uc.redis.Client.Del(c, prefix).Result()
if err != nil {
uc.logger.Sugar.Error(err)
}
}(cacheKey)
response.Ctx(c).Status(http.StatusNoContent).Send()
return
}
// Dislike godoc
// @Summary Dislike
// @Description 从用户的标签喜好中移除内容
// @Tags application_api
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param UserDislikePost body request.UserDislikePost true "UserDislikePost"
// @Failure 400 {object} response.ResponseBody
// @Router /applications/v1/users/_dislike [post]
func (uc *UserController) Dislike(c *gin.Context) {
app, err := uc.authService.GetApplication(c)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusBadRequest).Send()
return
}
var userDislikePostRequest = &request.UserDislikePost{}
if err := c.ShouldBindJSON(userDislikePostRequest); err != nil {
response.Ctx(c).Error(err).Status(http.StatusBadRequest).Send()
return
}
externalUser, err := uc.userService.GetOrCreateExternalUser(c, userDislikePostRequest.ExternalUserId, app)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
// posts
postEntity, err := uc.postService.GetPostById(c, userDislikePostRequest.PostId)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
if postEntity.ApplicationId != app.Id {
response.Ctx(c).Status(http.StatusNotFound).Send()
return
}
if !postEntity.Vectorized || !postEntity.Processed {
response.Ctx(c).Status(http.StatusBadRequest).Error(consts.ErrPostNotReady).Send()
return
}
// 检测是否有
var cacheKey = uc.redis.Prefix(TaskProcessing + ":" + userDislikePostRequest.PostId.String())
exists, err := uc.redis.Client.Exists(c, cacheKey).Result()
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
if exists > 0 {
response.Ctx(c).Status(http.StatusTooEarly).Error(consts.ErrAnotherOperationInProgress).Send()
return
}
_, err = uc.redis.Client.Set(c, cacheKey, userDislikePostRequest.ExternalUserId, LockTTL).Result()
go func(prefix string) {
err = uc.userService.DislikePost(c, externalUser, app, postEntity)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
_, err := uc.redis.Client.Del(c, prefix).Result()
if err != nil {
uc.logger.Sugar.Error(err)
}
}(cacheKey)
response.Ctx(c).Status(http.StatusNoContent).Send()
return
}
// Suggest godoc
// @Summary Suggest
// @Description 推荐资源
// @Tags application_api
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param UserSuggestsRequest body request.UserSuggestsRequest true "UserSuggestsRequest"
// @Success 200 {object} response.ResponseBody{data=[]entity.Post}
// @Failure 400 {object} response.ResponseBody
// @Router /applications/v1/users/_suggest [post]
func (uc *UserController) Suggest(c *gin.Context) {
app, err := uc.authService.GetApplication(c)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusBadRequest).Send()
return
}
var userSuggestsRequest = &request.UserSuggestsRequest{}
if err := c.ShouldBindJSON(userSuggestsRequest); err != nil {
response.Ctx(c).Error(err).Status(http.StatusBadRequest).Send()
return
}
exists, err := uc.userService.UserExists(c, userSuggestsRequest.ExternalUserId, app)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
if !exists {
response.Ctx(c).Status(http.StatusNotFound).Send()
return
}
externalUserEntity, err := uc.userService.GetExternalUser(c, userSuggestsRequest.ExternalUserId, app)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
// category
exists, err = uc.categoryService.CategoryExists(c, userSuggestsRequest.CategoryId, app)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
if !exists {
response.Ctx(c).Status(http.StatusNotFound).Error(consts.ErrCategoryNotExists).Send()
return
}
categoryEntity, err := uc.categoryService.GetCategoryById(c, userSuggestsRequest.CategoryId)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
// 建议文章
err = uc.userService.SummaryUser(c, externalUserEntity, app)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Error(err).Send()
return
}
// 建议文章
posts, err := uc.userService.SuggestPosts(c, externalUserEntity, categoryEntity)
if err != nil {
response.Ctx(c).Error(err).Status(http.StatusInternalServerError).Send()
return
}
response.Ctx(c).Data(posts).Send()
}