Skip to content

Commit

Permalink
Don't return profiles in reference lists/starter packs that have a bl…
Browse files Browse the repository at this point in the history
…ock relationship with the owner (bluesky-social#2713)

* proposal

* clean

* create seed

* type

* update tests

* change pairs

* `maybeGetBlocksForReferenceList`

* add logic for filtering inside of `getStarterPack()`

* move seeding to test

* nits

* tweak getting blocks

* oops
  • Loading branch information
haileyok authored Aug 16, 2024
1 parent bc131eb commit 17e2d29
Show file tree
Hide file tree
Showing 6 changed files with 591 additions and 66 deletions.
51 changes: 47 additions & 4 deletions packages/bsky/src/api/app/bsky/graph/getList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@ import AppContext from '../../../../context'
import {
createPipeline,
HydrationFnInput,
noRules,
PresentationFnInput,
RulesFnInput,
SkeletonFnInput,
} from '../../../../pipeline'
import {
HydrateCtx,
HydrationState,
Hydrator,
mergeStates,
mergeManyStates,
} from '../../../../hydration/hydrator'
import { Views } from '../../../../views'
import { clearlyBadCursor, resHeaders } from '../../../util'
import { ListItemInfo } from '../../../../proto/bsky_pb'
import { didFromUri } from '../../../../hydration/util'

export default function (server: Server, ctx: AppContext) {
const getList = createPipeline(skeleton, hydration, noRules, presentation)
const getList = createPipeline(skeleton, hydration, noBlocks, presentation)
server.app.bsky.graph.getList({
auth: ctx.authVerifier.standardOptional,
handler: async ({ params, auth, req }) => {
Expand Down Expand Up @@ -68,7 +70,23 @@ const hydration = async (
params.hydrateCtx,
),
])
return mergeStates(listState, profileState)
const bidirectionalBlocks = await maybeGetBlocksForReferenceList({
ctx,
params,
skeleton,
listState,
})
return mergeManyStates(listState, profileState, { bidirectionalBlocks })
}

const noBlocks = (input: RulesFnInput<Context, Params, SkeletonState>) => {
const { skeleton, hydration } = input
const creator = didFromUri(skeleton.listUri)
const blocks = hydration.bidirectionalBlocks?.get(creator)
skeleton.listitems = skeleton.listitems.filter(({ did }) => {
return !blocks?.get(did)
})
return skeleton
}

const presentation = (
Expand All @@ -88,6 +106,31 @@ const presentation = (
return { list, items, cursor }
}

const maybeGetBlocksForReferenceList = async (input: {
ctx: Context
listState: HydrationState
skeleton: SkeletonState
params: Params
}) => {
const { ctx, params, listState, skeleton } = input
const { listitems } = skeleton
const { list } = params
const listRecord = listState.lists?.get(list)
const creator = didFromUri(list)
if (
listRecord?.record.purpose !== 'app.bsky.graph.defs#referencelist' ||
params.hydrateCtx.viewer === creator
) {
return
}
const pairs: Map<string, string[]> = new Map()
pairs.set(
creator,
listitems.map(({ did }) => did),
)
return await ctx.hydrator.hydrateBidirectionalBlocks(pairs)
}

type Context = {
hydrator: Hydrator
views: Views
Expand Down
20 changes: 18 additions & 2 deletions packages/bsky/src/hydration/hydrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,17 @@ export class Hydrator {
const listMemberDids = listsMembers.flatMap((lm) =>
lm.listitems.map((li) => li.did),
)
const listCreatorMemberPairs = [...listMembersByList.entries()].flatMap(
([listUri, members]) => {
const creator = didFromUri(listUri)
return members.listitems.map(
(li): RelationshipPair => [creator, li.did],
)
},
)
const blocks = await this.graph.getBidirectionalBlocks(
listCreatorMemberPairs,
)
// sample top list items per starter pack based on their follows
const listMemberAggs = await this.actor.getProfileAggregates(listMemberDids)
const listItemUris: string[] = []
Expand All @@ -659,8 +670,13 @@ export class Hydrator {
if (!sp?.record.list || !agg) return
const members = listMembersByList.get(sp.record.list)
if (!members) return
const creator = didFromUri(sp.record.list)
// update aggregation with list items for top 12 most followed members
agg.listItemSampleUris = [...members.listitems]
agg.listItemSampleUris = [
...members.listitems.filter(
(li) => ctx.viewer === creator || !blocks?.isBlocked(creator, li.did),
),
]
.sort((li1, li2) => {
const score1 = listMemberAggs.get(li1.did)?.followers ?? 0
const score2 = listMemberAggs.get(li2.did)?.followers ?? 0
Expand Down Expand Up @@ -1079,7 +1095,7 @@ export const mergeStates = (
}
}

const mergeManyStates = (...states: HydrationState[]) => {
export const mergeManyStates = (...states: HydrationState[]) => {
return states.reduce(mergeStates, {} as HydrationState)
}

Expand Down
171 changes: 145 additions & 26 deletions packages/bsky/tests/views/__snapshots__/lists.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,42 +1,161 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`bsky actor likes feed views does include users with creator block relationship in reference lists for creator 1`] = `
Array [
Object {
"subject": Object {
"did": "user(0)",
"handle": "frankie.test",
"labels": Array [],
"viewer": Object {
"blockedBy": true,
"muted": false,
},
},
"uri": "record(0)",
},
Object {
"subject": Object {
"avatar": "https://bsky.public.url/img/avatar/plain/user(2)/cids(0)@jpeg",
"createdAt": "1970-01-01T00:00:00.000Z",
"description": "hi im bob label_me",
"did": "user(1)",
"displayName": "bobby",
"handle": "bob.test",
"indexedAt": "1970-01-01T00:00:00.000Z",
"labels": Array [],
"viewer": Object {
"blockedBy": false,
"muted": false,
},
},
"uri": "record(1)",
},
Object {
"subject": Object {
"did": "user(3)",
"handle": "eve.test",
"labels": Array [],
"viewer": Object {
"blockedBy": false,
"muted": false,
},
},
"uri": "record(2)",
},
]
`;

exports[`bsky actor likes feed views does not include reference lists in getActorLists 1`] = `
Array [
Object {
"cid": "cids(0)",
"creator": Object {
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)@jpeg",
"createdAt": "1970-01-01T00:00:00.000Z",
"description": "its me!",
"did": "user(0)",
"displayName": "ali",
"handle": "alice.test",
"indexedAt": "1970-01-01T00:00:00.000Z",
"labels": Array [
Object {
"cid": "cids(2)",
"cts": "1970-01-01T00:00:00.000Z",
"src": "user(0)",
"uri": "record(1)",
"val": "self-label-a",
},
Object {
"cid": "cids(2)",
"cts": "1970-01-01T00:00:00.000Z",
"src": "user(0)",
"uri": "record(1)",
"val": "self-label-b",
},
],
},
"description": "",
"descriptionFacets": Array [],
"handle": "eve.test",
"labels": Array [],
},
"indexedAt": "1970-01-01T00:00:00.000Z",
"labels": Array [],
"listItemCount": 0,
"name": "cool curate list!",
"name": "cool curate list",
"purpose": "app.bsky.graph.defs#curatelist",
"uri": "record(0)",
},
]
`;

exports[`bsky actor likes feed views does not include users with creator block relationship in reference lists for non-creator, in-list viewers 1`] = `
Array [
Object {
"subject": Object {
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(0)@jpeg",
"createdAt": "1970-01-01T00:00:00.000Z",
"description": "hi im bob label_me",
"did": "user(0)",
"displayName": "bobby",
"handle": "bob.test",
"indexedAt": "1970-01-01T00:00:00.000Z",
"labels": Array [],
"viewer": Object {
"blockedBy": false,
"muted": false,
},
},
"uri": "record(0)",
},
Object {
"subject": Object {
"did": "user(2)",
"handle": "eve.test",
"labels": Array [],
"viewer": Object {
"blockedBy": false,
"blocking": "record(2)",
"muted": false,
},
},
"uri": "record(1)",
},
]
`;

exports[`bsky actor likes feed views does not include users with creator block relationship in reference lists for non-creator, not-in-list viewers 1`] = `
Array [
Object {
"subject": Object {
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(0)@jpeg",
"createdAt": "1970-01-01T00:00:00.000Z",
"description": "hi im bob label_me",
"did": "user(0)",
"displayName": "bobby",
"handle": "bob.test",
"indexedAt": "1970-01-01T00:00:00.000Z",
"labels": Array [],
"viewer": Object {
"blockedBy": false,
"muted": false,
},
},
"uri": "record(0)",
},
Object {
"subject": Object {
"did": "user(2)",
"handle": "eve.test",
"labels": Array [],
"viewer": Object {
"blockedBy": false,
"muted": false,
},
},
"uri": "record(1)",
},
]
`;

exports[`bsky actor likes feed views does not include users with creator block relationship in reference lists for signed-out viewers 1`] = `
Array [
Object {
"subject": Object {
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(0)@jpeg",
"createdAt": "1970-01-01T00:00:00.000Z",
"description": "hi im bob label_me",
"did": "user(0)",
"displayName": "bobby",
"handle": "bob.test",
"indexedAt": "1970-01-01T00:00:00.000Z",
"labels": Array [],
},
"uri": "record(0)",
},
Object {
"subject": Object {
"did": "user(2)",
"handle": "eve.test",
"labels": Array [],
},
"uri": "record(1)",
},
]
`;
Loading

0 comments on commit 17e2d29

Please sign in to comment.