Drop the redundant Post.Text/internalPost.Text fields and complete the rename in server converters and test fixtures so the tree builds again. - types.go: remove Text from Post and internalPost; toPost only writes Author when the account acct is present - posts_convert.go: apPostsPtrToItems / apPostsToAnalyticsItems read Content - server tests: drop duplicate Text literal fields (values identical to Content)
255 lines
6.4 KiB
Go
255 lines
6.4 KiB
Go
package server
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/bluesky-social/indigo/api/bsky"
|
|
"github.com/nacorid/naco-api/internal/activitypub"
|
|
"github.com/nacorid/naco-api/internal/clustering"
|
|
"github.com/nacorid/naco-api/internal/nostr"
|
|
"github.com/nacorid/naco-api/internal/twitter"
|
|
)
|
|
|
|
func bskyPostViewToResponse(p *bsky.FeedDefs_PostView) *GetPostResponsePost {
|
|
author := ""
|
|
if p.Author != nil {
|
|
author = p.Author.Did
|
|
}
|
|
content := ""
|
|
created := ""
|
|
if fp, ok := p.Record.Val.(*bsky.FeedPost); ok {
|
|
content = fp.Text
|
|
created = fp.CreatedAt
|
|
}
|
|
likes, reposts, quotes, replies := int64(0), int64(0), int64(0), int64(0)
|
|
if p.LikeCount != nil {
|
|
likes = *p.LikeCount
|
|
}
|
|
if p.RepostCount != nil {
|
|
reposts = *p.RepostCount
|
|
}
|
|
if p.QuoteCount != nil {
|
|
quotes = *p.QuoteCount
|
|
}
|
|
if p.ReplyCount != nil {
|
|
replies = *p.ReplyCount
|
|
}
|
|
return &GetPostResponsePost{
|
|
Author: author,
|
|
Content: content,
|
|
Likes: likes,
|
|
Reposts: reposts,
|
|
Quotes: quotes,
|
|
Replies: replies,
|
|
CreatedAt: created,
|
|
}
|
|
}
|
|
|
|
func apPostToResponse(p *activitypub.Post) *GetPostResponsePost {
|
|
created := ""
|
|
if !p.CreatedAt.IsZero() {
|
|
created = p.CreatedAt.Format(time.RFC3339)
|
|
}
|
|
return &GetPostResponsePost{
|
|
Author: p.Author,
|
|
Content: p.Content,
|
|
Likes: int64(p.FavouritesCount),
|
|
Reposts: int64(p.ReblogsCount),
|
|
Replies: int64(p.RepliesCount),
|
|
CreatedAt: created,
|
|
}
|
|
}
|
|
|
|
func nostrPostToResponse(p *nostr.Post) *GetPostResponsePost {
|
|
created := ""
|
|
if !p.CreatedAt.IsZero() {
|
|
created = p.CreatedAt.Format(time.RFC3339)
|
|
}
|
|
return &GetPostResponsePost{
|
|
Author: p.Author,
|
|
Content: p.Content,
|
|
CreatedAt: created,
|
|
}
|
|
}
|
|
|
|
func twitterPostToResponse(p *twitter.Post) *GetPostResponsePost {
|
|
created := ""
|
|
if !p.CreatedAt.IsZero() {
|
|
created = p.CreatedAt.Format(time.RFC3339)
|
|
}
|
|
return &GetPostResponsePost{
|
|
Author: p.Author,
|
|
Content: p.Content,
|
|
Likes: int64(p.Likes),
|
|
Reposts: int64(p.Reposts),
|
|
Quotes: int64(p.Quotes),
|
|
Replies: int64(p.Replies),
|
|
CreatedAt: created,
|
|
}
|
|
}
|
|
|
|
// ---- Batch converters for GetPostResponsePost ----
|
|
|
|
func blueskyFeedViewsToResponses(views []*bsky.FeedDefs_FeedViewPost) ([]*GetPostResponsePost, string) {
|
|
posts := make([]*GetPostResponsePost, 0, len(views))
|
|
var aid string
|
|
for _, p := range views {
|
|
if p.Post == nil {
|
|
continue
|
|
}
|
|
posts = append(posts, bskyPostViewToResponse(p.Post))
|
|
if p.Post.Author != nil {
|
|
aid = p.Post.Author.Did
|
|
}
|
|
}
|
|
return posts, aid
|
|
}
|
|
|
|
func apPostsPtrToResponses(posts []*activitypub.Post) ([]*GetPostResponsePost, string) {
|
|
out := make([]*GetPostResponsePost, 0, len(posts))
|
|
var aid string
|
|
for _, p := range posts {
|
|
out = append(out, apPostToResponse(p))
|
|
aid = p.Author
|
|
}
|
|
return out, aid
|
|
}
|
|
|
|
func apPostsToResponses(posts []*activitypub.Post) ([]*GetPostResponsePost, string) {
|
|
out := make([]*GetPostResponsePost, 0, len(posts))
|
|
var aid string
|
|
for _, p := range posts {
|
|
out = append(out, apPostToResponse(p))
|
|
aid = p.Author
|
|
}
|
|
return out, aid
|
|
}
|
|
|
|
func nostrPostsToResponses(posts []*nostr.Post) ([]*GetPostResponsePost, string) {
|
|
out := make([]*GetPostResponsePost, 0, len(posts))
|
|
var aid string
|
|
for _, p := range posts {
|
|
out = append(out, nostrPostToResponse(p))
|
|
aid = p.Author
|
|
}
|
|
return out, aid
|
|
}
|
|
|
|
func twitterPostsToResponses(posts []*twitter.Post) ([]*GetPostResponsePost, string) {
|
|
out := make([]*GetPostResponsePost, 0, len(posts))
|
|
var aid string
|
|
for _, p := range posts {
|
|
out = append(out, twitterPostToResponse(p))
|
|
aid = p.Author
|
|
}
|
|
return out, aid
|
|
}
|
|
|
|
// ---- Batch converters for clustering.Item (style & analytics) ----
|
|
|
|
func blueskyFeedViewsToItems(views []*bsky.FeedDefs_FeedViewPost) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(views))
|
|
for _, p := range views {
|
|
fp, ok := p.Post.Record.Val.(*bsky.FeedPost)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if fp.Text == "" {
|
|
continue
|
|
}
|
|
out = append(out, clustering.Item{ID: p.Post.Uri, Text: fp.Text})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func apPostsPtrToItems(posts []*activitypub.Post) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(posts))
|
|
for _, p := range posts {
|
|
if p.Content != "" {
|
|
out = append(out, clustering.Item{ID: p.ID, Text: p.Content})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func nostrPostsToItems(posts []*nostr.Post) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(posts))
|
|
for _, p := range posts {
|
|
if p.Content != "" {
|
|
out = append(out, clustering.Item{ID: p.ID, Text: p.Content})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func twitterPostsToItems(posts []*twitter.Post) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(posts))
|
|
for _, p := range posts {
|
|
if p.Content != "" {
|
|
out = append(out, clustering.Item{ID: p.ID, Text: p.Content})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// analytics-specific converters that preserve engagement + timestamps
|
|
|
|
func blueskyFeedViewsToAnalyticsItems(views []*bsky.FeedDefs_FeedViewPost) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(views))
|
|
for _, p := range views {
|
|
if p.Post == nil || p.Post.Record == nil {
|
|
continue
|
|
}
|
|
fp, ok := p.Post.Record.Val.(*bsky.FeedPost)
|
|
if !ok {
|
|
continue
|
|
}
|
|
item := clustering.Item{ID: p.Post.Uri, Text: fp.Text}
|
|
if ts, err := time.Parse(time.RFC3339, p.Post.IndexedAt); err == nil {
|
|
item.Timestamp = ts
|
|
}
|
|
item.Likes = int64Val(p.Post.LikeCount)
|
|
item.Reposts = int64Val(p.Post.RepostCount)
|
|
item.Replies = int64Val(p.Post.ReplyCount)
|
|
item.Quotes = int64Val(p.Post.QuoteCount)
|
|
out = append(out, item)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func apPostsToAnalyticsItems(posts []*activitypub.Post) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(posts))
|
|
for _, p := range posts {
|
|
if p.Content != "" {
|
|
out = append(out, clustering.Item{
|
|
ID: p.ID, Text: p.Content, Timestamp: p.CreatedAt,
|
|
Likes: int64(p.FavouritesCount), Reposts: int64(p.ReblogsCount), Replies: int64(p.RepliesCount),
|
|
})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func nostrPostsToAnalyticsItems(posts []*nostr.Post) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(posts))
|
|
for _, p := range posts {
|
|
if p.Content != "" {
|
|
out = append(out, clustering.Item{ID: p.ID, Text: p.Content, Timestamp: p.CreatedAt})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func twitterPostsToAnalyticsItems(posts []*twitter.Post) []clustering.Item {
|
|
out := make([]clustering.Item, 0, len(posts))
|
|
for _, p := range posts {
|
|
if p.Content == "" {
|
|
continue
|
|
}
|
|
out = append(out, clustering.Item{
|
|
ID: p.ID, Text: p.Content, Timestamp: p.CreatedAt,
|
|
Likes: int64(p.Likes), Reposts: int64(p.Reposts), Replies: int64(p.Replies), Quotes: int64(p.Quotes),
|
|
})
|
|
}
|
|
return out
|
|
}
|