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() }