+2
-2
cmd/server/main.go
+2
-2
cmd/server/main.go
···log.Println("Timeline XRPC endpoints registered (requires authentication, includes viewer vote state)")+log.Println("Discover XRPC endpoints registered (public with optional auth for viewer vote state)")
+73
internal/api/handlers/common/viewer_state.go
+73
internal/api/handlers/common/viewer_state.go
···+// This allows the helper to work with different feed post types (discover, timeline, communityFeed).
+3
-36
internal/api/handlers/communityFeed/get_community.go
+3
-36
internal/api/handlers/communityFeed/get_community.go
······
+11
-4
internal/api/handlers/discover/get_discover.go
+11
-4
internal/api/handlers/discover/get_discover.go
······+func NewGetDiscoverHandler(service discover.Service, voteService votes.Service) *GetDiscoverHandler {···
+3
-34
internal/api/handlers/timeline/get_timeline.go
+3
-34
internal/api/handlers/timeline/get_timeline.go
······
+9
-4
internal/api/routes/discover.go
+9
-4
internal/api/routes/discover.go
·········+r.With(authMiddleware.OptionalAuth).Get("/xrpc/social.coves.feed.getDiscover", getDiscoverHandler.HandleGetDiscover)
+5
internal/core/communityFeeds/types.go
+5
internal/core/communityFeeds/types.go
···
+5
internal/core/discover/types.go
+5
internal/core/discover/types.go
···
+5
internal/core/timeline/types.go
+5
internal/core/timeline/types.go
···
+193
-5
tests/integration/discover_test.go
+193
-5
tests/integration/discover_test.go
······+func (m *mockVoteService) CreateVote(_ context.Context, _ *oauthlib.ClientSessionData, _ votes.CreateVoteRequest) (*votes.CreateVoteResponse, error) {+func (m *mockVoteService) DeleteVote(_ context.Context, _ *oauthlib.ClientSessionData, _ votes.DeleteVoteRequest) error {+func (m *mockVoteService) EnsureCachePopulated(_ context.Context, _ *oauthlib.ClientSessionData) error {+func (m *mockVoteService) GetViewerVotesForSubjects(userDID string, subjectURIs []string) map[string]*votes.CachedVote {···+handler := discover.NewGetDiscoverHandler(discoverService, nil) // nil vote service - tests don't need vote state···+handler := discover.NewGetDiscoverHandler(discoverService, nil) // nil vote service - tests don't need vote state·········req := httptest.NewRequest(http.MethodGet, "/xrpc/social.coves.feed.getDiscover?sort=new&limit=100", nil)···+// TestGetDiscover_ViewerVoteState tests that authenticated users see their vote state on posts+communityDID, err := createFeedTestCommunity(db, ctx, fmt.Sprintf("votes-%d", testID), fmt.Sprintf("alice-%d.test", testID))+post1URI := createTestPost(t, db, communityDID, "did:plc:author1", "Post with upvote", 10, time.Now().Add(-1*time.Hour))+post2URI := createTestPost(t, db, communityDID, "did:plc:author2", "Post with downvote", 5, time.Now().Add(-2*time.Hour))+_ = createTestPost(t, db, communityDID, "did:plc:author3", "Post without vote", 3, time.Now().Add(-3*time.Hour))+req := httptest.NewRequest(http.MethodGet, "/xrpc/social.coves.feed.getDiscover?sort=new&limit=50", nil)+assert.Contains(t, *feedPost.Post.Viewer.VoteURI, "vote1", "Post1 should have correct vote URI")+// TestGetDiscover_NoViewerStateWithoutAuth tests that unauthenticated users don't get viewer state+communityDID, err := createFeedTestCommunity(db, ctx, fmt.Sprintf("noauth-%d", testID), fmt.Sprintf("alice-%d.test", testID))+mockVotes.AddVote("did:plc:someuser", postURI, "up", "at://did:plc:someuser/social.coves.vote/vote1")+req := httptest.NewRequest(http.MethodGet, "/xrpc/social.coves.feed.getDiscover?sort=new&limit=50", nil)
+11
-11
tests/integration/feed_test.go
+11
-11
tests/integration/feed_test.go
···············req := httptest.NewRequest(http.MethodGet, "/xrpc/social.coves.communityFeed.getCommunity?community=did:plc:nonexistent&sort=hot&limit=10", nil)··················
+7
-7
tests/integration/timeline_test.go
+7
-7
tests/integration/timeline_test.go
···············req := httptest.NewRequest(http.MethodGet, "/xrpc/social.coves.feed.getTimeline?sort=new&limit=10", nil)······
+1
-1
tests/integration/user_journey_e2e_test.go
+1
-1
tests/integration/user_journey_e2e_test.go
···routes.RegisterCommunityRoutes(r, communityService, e2eAuth.OAuthAuthMiddleware, nil) // nil = allow all community creators
+12
internal/atproto/jetstream/comment_consumer.go
+12
internal/atproto/jetstream/comment_consumer.go
·········comment.Content, comment.ContentFacets, comment.Embed, comment.ContentLabels, pq.Array(comment.Langs),