From ffe39aae8394394f73bbfaa9047a8b5818aa053a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 8 Dec 2023 15:32:06 -0600 Subject: [PATCH] Include own replies to own post roots via new filter `posts_and_author_threads` (#1776) * Include own replies to own post roots in post_no_replies * Updates * Simplify * snaps * snaps * Remove unused import * Add new threads filter to getAuthorFeed * Implement new filter * Typo --- .changeset/funny-eyes-wash.md | 5 + .changeset/large-books-cover.md | 7 ++ lexicons/app/bsky/feed/getAuthorFeed.json | 3 +- packages/api/src/client/lexicons.ts | 1 + .../types/app/bsky/feed/getAuthorFeed.ts | 1 + packages/api/src/moderation/const/labels.ts | 8 +- .../src/api/app/bsky/feed/getAuthorFeed.ts | 7 ++ packages/bsky/src/lexicon/lexicons.ts | 1 + .../types/app/bsky/feed/getAuthorFeed.ts | 1 + packages/bsky/tests/seeds/author-feed.ts | 95 +++++++++++++++++++ .../__snapshots__/author-feed.test.ts.snap | 20 ++-- packages/bsky/tests/views/author-feed.test.ts | 22 ++++- packages/pds/src/lexicon/lexicons.ts | 1 + .../types/app/bsky/feed/getAuthorFeed.ts | 1 + 14 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 .changeset/funny-eyes-wash.md create mode 100644 .changeset/large-books-cover.md create mode 100644 packages/bsky/tests/seeds/author-feed.ts diff --git a/.changeset/funny-eyes-wash.md b/.changeset/funny-eyes-wash.md new file mode 100644 index 00000000000..449464e00b0 --- /dev/null +++ b/.changeset/funny-eyes-wash.md @@ -0,0 +1,5 @@ +--- +'@atproto/bsky': patch +--- + +Integrate `posts_and_author_threads` filter into `getAuthorFeed` implementation. diff --git a/.changeset/large-books-cover.md b/.changeset/large-books-cover.md new file mode 100644 index 00000000000..0430b421a17 --- /dev/null +++ b/.changeset/large-books-cover.md @@ -0,0 +1,7 @@ +--- +'@atproto/bsky': patch +'@atproto/api': patch +'@atproto/pds': patch +--- + +Add `posts_and_author_threads` filter to `getAuthorFeed` diff --git a/lexicons/app/bsky/feed/getAuthorFeed.json b/lexicons/app/bsky/feed/getAuthorFeed.json index 27dccf63e20..1939fa9a49d 100644 --- a/lexicons/app/bsky/feed/getAuthorFeed.json +++ b/lexicons/app/bsky/feed/getAuthorFeed.json @@ -22,7 +22,8 @@ "knownValues": [ "posts_with_replies", "posts_no_replies", - "posts_with_media" + "posts_with_media", + "posts_and_author_threads" ], "default": "posts_with_replies" } diff --git a/packages/api/src/client/lexicons.ts b/packages/api/src/client/lexicons.ts index 90176ef6486..87cb89fd19d 100644 --- a/packages/api/src/client/lexicons.ts +++ b/packages/api/src/client/lexicons.ts @@ -5572,6 +5572,7 @@ export const schemaDict = { 'posts_with_replies', 'posts_no_replies', 'posts_with_media', + 'posts_and_author_threads', ], default: 'posts_with_replies', }, diff --git a/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts b/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts index 3f3abc9933f..a070dad6ff7 100644 --- a/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts +++ b/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts @@ -16,6 +16,7 @@ export interface QueryParams { | 'posts_with_replies' | 'posts_no_replies' | 'posts_with_media' + | 'posts_and_author_threads' | (string & {}) } diff --git a/packages/api/src/moderation/const/labels.ts b/packages/api/src/moderation/const/labels.ts index f8a9a7911c0..cbce29cdd7d 100644 --- a/packages/api/src/moderation/const/labels.ts +++ b/packages/api/src/moderation/const/labels.ts @@ -99,23 +99,23 @@ export const LABELS: LabelDefinitionMap = { strings: { settings: { en: { - name: 'Requested Hidden to Logged-out Users', + name: 'Sign-in Required', description: - 'This user has requested that their content only be shown to logged-in accounts.', + 'This user has requested that their account only be shown to signed-in users.', }, }, account: { en: { name: 'Sign-in Required', description: - 'This user has requested that their content only be shown to logged-in accounts.', + 'This user has requested that their account only be shown to signed-in users.', }, }, content: { en: { name: 'Sign-in Required', description: - 'This user has requested that their content only be shown to logged-in accounts.', + 'This user has requested that their content only be shown to signed-in users.', }, }, }, diff --git a/packages/bsky/src/api/app/bsky/feed/getAuthorFeed.ts b/packages/bsky/src/api/app/bsky/feed/getAuthorFeed.ts index 26b945f3ecd..342f371f18d 100644 --- a/packages/bsky/src/api/app/bsky/feed/getAuthorFeed.ts +++ b/packages/bsky/src/api/app/bsky/feed/getAuthorFeed.ts @@ -102,6 +102,13 @@ export const skeleton = async ( feedItemsQb = feedItemsQb.where((qb) => qb.where('post.replyParent', 'is', null).orWhere('type', '=', 'repost'), ) + } else if (filter === 'posts_and_author_threads') { + feedItemsQb = feedItemsQb.where((qb) => + qb + .where('type', '=', 'repost') + .orWhere('post.replyParent', 'is', null) + .orWhere('post.replyRoot', 'like', `at://${actorDid}/%`), + ) } const keyset = new FeedKeyset(ref('feed_item.sortAt'), ref('feed_item.cid')) diff --git a/packages/bsky/src/lexicon/lexicons.ts b/packages/bsky/src/lexicon/lexicons.ts index 90176ef6486..87cb89fd19d 100644 --- a/packages/bsky/src/lexicon/lexicons.ts +++ b/packages/bsky/src/lexicon/lexicons.ts @@ -5572,6 +5572,7 @@ export const schemaDict = { 'posts_with_replies', 'posts_no_replies', 'posts_with_media', + 'posts_and_author_threads', ], default: 'posts_with_replies', }, diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts index cd66ef5c392..25f51f6fe5f 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts @@ -17,6 +17,7 @@ export interface QueryParams { | 'posts_with_replies' | 'posts_no_replies' | 'posts_with_media' + | 'posts_and_author_threads' | (string & {}) } diff --git a/packages/bsky/tests/seeds/author-feed.ts b/packages/bsky/tests/seeds/author-feed.ts new file mode 100644 index 00000000000..164564f766b --- /dev/null +++ b/packages/bsky/tests/seeds/author-feed.ts @@ -0,0 +1,95 @@ +import { SeedClient } from '@atproto/dev-env' +import basicSeed from './basic' + +export default async (sc: SeedClient) => { + await basicSeed(sc) + await sc.createAccount('eve', { + email: 'eve@test.com', + handle: 'eve.test', + password: 'eve-pass', + }) + await sc.createAccount('fred', { + email: 'fred@test.com', + handle: 'fred.test', + password: 'fred-pass', + }) + + const alice = sc.dids.alice + const eve = sc.dids.eve + const fred = sc.dids.fred + + /* + * Self thread + */ + await sc.post(eve, evePosts[0]) + await sc.reply( + eve, + sc.posts[eve][0].ref, + sc.posts[eve][0].ref, + eveOwnThreadReplies[0], + ) + await sc.reply( + eve, + sc.posts[eve][0].ref, + sc.replies[eve][0].ref, + eveOwnThreadReplies[1], + ) + await sc.reply( + eve, + sc.posts[eve][0].ref, + sc.replies[eve][1].ref, + eveOwnThreadReplies[2], + ) + + /** + * Two replies to Alice + */ + await sc.reply( + eve, + sc.posts[alice][1].ref, + sc.posts[alice][1].ref, + eveAliceReplies[0], + ) + await sc.reply( + eve, + sc.posts[alice][1].ref, + sc.replies[eve][3].ref, + eveAliceReplies[1], + ) + + /** + * Two replies to Fred, who replied to Eve's root post. This creates a + * "detached" thread, where one Fred post breaks the continuity. + */ + await sc.post(eve, evePosts[1]) + await sc.reply( + fred, + sc.posts[eve][1].ref, + sc.posts[eve][1].ref, + fredReplies[0], + ) + await sc.reply( + eve, + sc.posts[eve][1].ref, + sc.replies[fred][0].ref, + eveFredReplies[0], + ) + await sc.reply( + eve, + sc.posts[eve][1].ref, + sc.replies[eve][4].ref, + eveFredReplies[1], + ) + + return sc +} + +const evePosts = ['eve own thread', 'eve detached thread'] +const eveOwnThreadReplies = [ + 'eve own reply 1', + 'eve own reply 2', + 'eve own reply 3', +] +const eveAliceReplies = ['eve reply to alice 1', 'eve reply to alice 2'] +const eveFredReplies = ['eve reply to fred 1', 'eve reply to fred 2'] +const fredReplies = ['fred reply to eve 1'] diff --git a/packages/bsky/tests/views/__snapshots__/author-feed.test.ts.snap b/packages/bsky/tests/views/__snapshots__/author-feed.test.ts.snap index a2549b0a52c..9d1d41bd3db 100644 --- a/packages/bsky/tests/views/__snapshots__/author-feed.test.ts.snap +++ b/packages/bsky/tests/views/__snapshots__/author-feed.test.ts.snap @@ -178,7 +178,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(2)", "viewer": Object {}, @@ -395,7 +395,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(2)", "viewer": Object {}, @@ -590,7 +590,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(1)", "viewer": Object { @@ -638,7 +638,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(1)", "viewer": Object { @@ -961,7 +961,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(6)", "viewer": Object { @@ -1009,7 +1009,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(6)", "viewer": Object { @@ -1326,7 +1326,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(3)", "viewer": Object { @@ -1376,7 +1376,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(3)", "viewer": Object { @@ -1765,7 +1765,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(4)", "viewer": Object { @@ -1987,7 +1987,7 @@ Array [ "createdAt": "1970-01-01T00:00:00.000000Z", "text": "again", }, - "replyCount": 2, + "replyCount": 3, "repostCount": 1, "uri": "record(4)", "viewer": Object { diff --git a/packages/bsky/tests/views/author-feed.test.ts b/packages/bsky/tests/views/author-feed.test.ts index b8fade87c54..c5d863bfb92 100644 --- a/packages/bsky/tests/views/author-feed.test.ts +++ b/packages/bsky/tests/views/author-feed.test.ts @@ -1,7 +1,7 @@ import AtpAgent from '@atproto/api' import { TestNetwork, SeedClient } from '@atproto/dev-env' import { forSnapshot, paginateAll, stripViewerFromPost } from '../_util' -import basicSeed from '../seeds/basic' +import authorFeedSeed from '../seeds/author-feed' import { isRecord } from '../../src/lexicon/types/app/bsky/feed/post' import { isView as isEmbedRecordWithMedia } from '../../src/lexicon/types/app/bsky/embed/recordWithMedia' import { isView as isImageEmbed } from '../../src/lexicon/types/app/bsky/embed/images' @@ -16,6 +16,7 @@ describe('pds author feed views', () => { let bob: string let carol: string let dan: string + let eve: string beforeAll(async () => { network = await TestNetwork.create({ @@ -23,12 +24,13 @@ describe('pds author feed views', () => { }) agent = network.bsky.getClient() sc = network.getSeedClient() - await basicSeed(sc) + await authorFeedSeed(sc) await network.processAll() alice = sc.dids.alice bob = sc.dids.bob carol = sc.dids.carol dan = sc.dids.dan + eve = sc.dids.eve }) afterAll(async () => { @@ -305,4 +307,20 @@ describe('pds author feed views', () => { }), ).toBeTruthy() }) + + it('posts_and_author_threads includes self-replies', async () => { + const { data: eveFeed } = await agent.api.app.bsky.feed.getAuthorFeed({ + actor: eve, + filter: 'posts_and_author_threads', + }) + + expect(eveFeed.feed.length).toEqual(7) + expect( + eveFeed.feed.some(({ post }) => { + return ( + isRecord(post.record) && post.record.reply && post.author.did === eve + ) + }), + ).toBeTruthy() + }) }) diff --git a/packages/pds/src/lexicon/lexicons.ts b/packages/pds/src/lexicon/lexicons.ts index 90176ef6486..87cb89fd19d 100644 --- a/packages/pds/src/lexicon/lexicons.ts +++ b/packages/pds/src/lexicon/lexicons.ts @@ -5572,6 +5572,7 @@ export const schemaDict = { 'posts_with_replies', 'posts_no_replies', 'posts_with_media', + 'posts_and_author_threads', ], default: 'posts_with_replies', }, diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts index cd66ef5c392..25f51f6fe5f 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts @@ -17,6 +17,7 @@ export interface QueryParams { | 'posts_with_replies' | 'posts_no_replies' | 'posts_with_media' + | 'posts_and_author_threads' | (string & {}) }