2025-03-13 21:12:47 +08:00

91 lines
2.3 KiB
Go

package services
import (
"fmt"
"sort"
"time"
"git.solsynth.dev/hypernet/interactive/pkg/internal/database"
"git.solsynth.dev/hypernet/interactive/pkg/internal/models"
"github.com/gofiber/fiber/v2"
"github.com/samber/lo"
"gorm.io/gorm"
)
type FeedEntry struct {
Type string `json:"type"`
Data any `json:"data"`
CreatedAt time.Time `json:"created_at"`
}
func GetFeed(c *fiber.Ctx, limit int, user *uint, cursor *time.Time) ([]FeedEntry, error) {
// We got two types of data for now
// Plan to let each of them take 50% of the output
var feed []FeedEntry
interTx, err := UniversalPostFilter(c, database.C)
if err != nil {
return nil, fmt.Errorf("failed to prepare load interactive posts: %v", err)
}
if cursor != nil {
interTx = interTx.Where("published_at < ?", *cursor)
}
interPosts, err := ListPostForFeed(interTx, limit/2, user)
if err != nil {
return nil, fmt.Errorf("failed to load interactive posts: %v", err)
}
feed = append(feed, interPosts...)
fediTx := database.C
if cursor != nil {
fediTx = fediTx.Where("created_at < ?", *cursor)
}
fediPosts, err := ListFediversePostForFeed(fediTx, limit/2)
if err != nil {
return feed, fmt.Errorf("failed to load fediverse posts: %v", err)
}
feed = append(feed, fediPosts...)
sort.Slice(feed, func(i, j int) bool {
return feed[i].CreatedAt.After(feed[j].CreatedAt)
})
return feed, nil
}
// We assume the database context already handled the filtering and pagination
// Only manage to pulling the content only
func ListPostForFeed(tx *gorm.DB, limit int, user *uint) ([]FeedEntry, error) {
posts, err := ListPost(tx, limit, -1, "published_at DESC", user)
if err != nil {
return nil, err
}
entries := lo.Map(posts, func(post *models.Post, _ int) FeedEntry {
return FeedEntry{
Type: "interactive.post",
Data: post,
CreatedAt: post.CreatedAt,
}
})
return entries, nil
}
func ListFediversePostForFeed(tx *gorm.DB, limit int) ([]FeedEntry, error) {
var posts []models.FediversePost
if err := tx.
Preload("User").Limit(limit).
Find(&posts).Error; err != nil {
return nil, err
}
entries := lo.Map(posts, func(post models.FediversePost, _ int) FeedEntry {
return FeedEntry{
Type: "fediverse.post",
Data: post,
CreatedAt: post.CreatedAt,
}
})
return entries, nil
}