From d2ffde8469f54254278fde4ce73243f3b174a846 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 9 Dec 2024 22:14:30 +0800 Subject: [PATCH] :sparkles: Featured posts --- pkg/internal/http/api/index.go | 2 +- pkg/internal/http/api/recommendation_api.go | 55 +++++++++------------ pkg/internal/services/featured.go | 40 +++++++++++++++ 3 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 pkg/internal/services/featured.go diff --git a/pkg/internal/http/api/index.go b/pkg/internal/http/api/index.go index 10d40ad..3613b20 100644 --- a/pkg/internal/http/api/index.go +++ b/pkg/internal/http/api/index.go @@ -20,7 +20,7 @@ func MapAPIs(app *fiber.App, baseURL string) { recommendations := api.Group("/recommendations").Name("Recommendations API") { - recommendations.Get("/", listRecommendationNews) + recommendations.Get("/", listRecommendation) recommendations.Get("/friends", listRecommendationFriends) recommendations.Get("/shuffle", listRecommendationShuffle) } diff --git a/pkg/internal/http/api/recommendation_api.go b/pkg/internal/http/api/recommendation_api.go index 908a6c6..741f5f6 100644 --- a/pkg/internal/http/api/recommendation_api.go +++ b/pkg/internal/http/api/recommendation_api.go @@ -3,6 +3,7 @@ package api import ( "git.solsynth.dev/hypernet/interactive/pkg/internal/database" "git.solsynth.dev/hypernet/interactive/pkg/internal/gap" + "git.solsynth.dev/hypernet/interactive/pkg/internal/models" "git.solsynth.dev/hypernet/interactive/pkg/internal/services" "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" "git.solsynth.dev/hypernet/nexus/pkg/proto" @@ -12,45 +13,33 @@ import ( "github.com/samber/lo" ) -func listRecommendationNews(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) - offset := c.QueryInt("offset", 0) +func listRecommendation(c *fiber.Ctx) error { + const featuredMax = 3 - tx := database.C - - var err error - if tx, err = universalPostFilter(c, tx); err != nil { - return err - } - - countTx := tx - count, err := services.CountPost(countTx) + posts, err := services.GetFeaturedPosts(featuredMax) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - order := "published_at DESC" - if c.QueryBool("featured", false) { - order = "published_at DESC, (COALESCE(total_upvote, 0) - COALESCE(total_downvote, 0)) DESC" - } - - items, err := services.ListPost(tx, take, offset, order) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - - if c.QueryBool("truncate", true) { - for _, item := range items { - if item != nil { - item = lo.ToPtr(services.TruncatePostContent(*item)) - } - } - } - - return c.JSON(fiber.Map{ - "count": count, - "data": items, + postIdx := lo.Map(posts, func(item models.Post, index int) uint { + return item.ID }) + + tx := database.C.Where("id IN ?", postIdx) + newPosts, err := services.ListPost(tx, featuredMax, 0, " DESC") + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + newPostMap := lo.SliceToMap(newPosts, func(item *models.Post) (uint, models.Post) { + return item.ID, *item + }) + + // Revert the position + for idx, item := range posts { + posts[idx] = newPostMap[item.ID] + } + + return c.JSON(posts) } func listRecommendationFriends(c *fiber.Ctx) error { diff --git a/pkg/internal/services/featured.go b/pkg/internal/services/featured.go new file mode 100644 index 0000000..4a221ab --- /dev/null +++ b/pkg/internal/services/featured.go @@ -0,0 +1,40 @@ +package services + +import ( + "git.solsynth.dev/hypernet/interactive/pkg/internal/database" + "git.solsynth.dev/hypernet/interactive/pkg/internal/models" + "time" +) + +// GetFeaturedPosts How to determine featured posts? +// Get the most upvoted posts in the last 7 days +// And then how to get the upvote count of each post in the last 7 days? +// We will get the reactions that attitude equals to 1 and created within the last 7 days +// By the way, the upvote count will subtract the downvote count +// Notice, this function is a raw query, it is not recommended to return the result directly +// Instead, you should get the id and query it again via the ListPost function +func GetFeaturedPosts(count int) ([]models.Post, error) { + deadline := time.Now().Add(-7 * 24 * time.Hour) + + var posts []models.Post + if err := database.C.Raw(` + SELECT p.* + FROM posts p + JOIN ( + SELECT + post_id, + SUM(CASE WHEN attitude = 1 THEN 1 ELSE 0 END) - + SUM(CASE WHEN attitude = 2 THEN 1 ELSE 0 END) AS social_points + FROM reactions + WHERE created_at >= ? + GROUP BY post_id + ORDER BY social_points DESC + LIMIT ? + ) t ON p.id = t.post_id + ORDER BY t.social_points DESC, p.published_at DESC + `, deadline, count).Scan(&posts).Error; err != nil { + return posts, err + } + + return posts, nil +}