filter blocks in curate list (#2720)
This commit is contained in:
parent
1572058887
commit
47263e9f3d
packages/bsky
src/api/app/bsky
tests/views
@ -7,12 +7,14 @@ import {
|
||||
HydrateCtx,
|
||||
HydrationState,
|
||||
Hydrator,
|
||||
mergeStates,
|
||||
} from '../../../../hydration/hydrator'
|
||||
import { Views } from '../../../../views'
|
||||
import { DataPlaneClient } from '../../../../data-plane'
|
||||
import { mapDefined } from '@atproto/common'
|
||||
import { parseString } from '../../../../hydration/util'
|
||||
import { FeedItem } from '../../../../hydration/feed'
|
||||
import { uriToDid } from '../../../../util/uris'
|
||||
|
||||
export default function (server: Server, ctx: AppContext) {
|
||||
const getListFeed = createPipeline(
|
||||
@ -71,23 +73,34 @@ const hydration = async (inputs: {
|
||||
skeleton: Skeleton
|
||||
}): Promise<HydrationState> => {
|
||||
const { ctx, params, skeleton } = inputs
|
||||
return ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx)
|
||||
const [feedItemsState, bidirectionalBlocks] = await Promise.all([
|
||||
ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx),
|
||||
getBlocks({ ctx, params, skeleton }),
|
||||
])
|
||||
return mergeStates(feedItemsState, {
|
||||
bidirectionalBlocks,
|
||||
})
|
||||
}
|
||||
|
||||
const noBlocksOrMutes = (inputs: {
|
||||
ctx: Context
|
||||
params: Params
|
||||
skeleton: Skeleton
|
||||
hydration: HydrationState
|
||||
}): Skeleton => {
|
||||
const { ctx, skeleton, hydration } = inputs
|
||||
const { ctx, params, skeleton, hydration } = inputs
|
||||
skeleton.items = skeleton.items.filter((item) => {
|
||||
const bam = ctx.views.feedItemBlocksAndMutes(item, hydration)
|
||||
const creatorBlocks = hydration.bidirectionalBlocks?.get(
|
||||
uriToDid(params.list),
|
||||
)
|
||||
return (
|
||||
!bam.authorBlocked &&
|
||||
!bam.authorMuted &&
|
||||
!bam.originatorBlocked &&
|
||||
!bam.originatorMuted &&
|
||||
!bam.ancestorAuthorBlocked
|
||||
!bam.ancestorAuthorBlocked &&
|
||||
!creatorBlocks?.get(uriToDid(item.post.uri))
|
||||
)
|
||||
})
|
||||
return skeleton
|
||||
@ -105,6 +118,20 @@ const presentation = (inputs: {
|
||||
return { feed, cursor: skeleton.cursor }
|
||||
}
|
||||
|
||||
const getBlocks = async (input: {
|
||||
ctx: Context
|
||||
skeleton: Skeleton
|
||||
params: Params
|
||||
}) => {
|
||||
const { ctx, skeleton, params } = input
|
||||
const pairs: Map<string, string[]> = new Map()
|
||||
pairs.set(
|
||||
uriToDid(params.list),
|
||||
skeleton.items.map((item) => uriToDid(item.post.uri)),
|
||||
)
|
||||
return await ctx.hydrator.hydrateBidirectionalBlocks(pairs)
|
||||
}
|
||||
|
||||
type Context = {
|
||||
hydrator: Hydrator
|
||||
views: Views
|
||||
|
@ -70,7 +70,7 @@ const hydration = async (
|
||||
params.hydrateCtx,
|
||||
),
|
||||
])
|
||||
const bidirectionalBlocks = await maybeGetBlocksForReferenceList({
|
||||
const bidirectionalBlocks = await maybeGetBlocksForReferenceAndCurateList({
|
||||
ctx,
|
||||
params,
|
||||
skeleton,
|
||||
@ -106,7 +106,7 @@ const presentation = (
|
||||
return { list, items, cursor }
|
||||
}
|
||||
|
||||
const maybeGetBlocksForReferenceList = async (input: {
|
||||
const maybeGetBlocksForReferenceAndCurateList = async (input: {
|
||||
ctx: Context
|
||||
listState: HydrationState
|
||||
skeleton: SkeletonState
|
||||
@ -118,8 +118,8 @@ const maybeGetBlocksForReferenceList = async (input: {
|
||||
const listRecord = listState.lists?.get(list)
|
||||
const creator = didFromUri(list)
|
||||
if (
|
||||
listRecord?.record.purpose !== 'app.bsky.graph.defs#referencelist' ||
|
||||
params.hydrateCtx.viewer === creator
|
||||
params.hydrateCtx.viewer === creator ||
|
||||
listRecord?.record.purpose === 'app.bsky.graph.defs#modlist'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
@ -46,6 +46,52 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`bsky actor likes feed views does include users with creator block relationship in reference lists for creator 2`] = `
|
||||
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 {
|
||||
@ -62,6 +108,72 @@ Array [
|
||||
"purpose": "app.bsky.graph.defs#curatelist",
|
||||
"uri": "record(0)",
|
||||
},
|
||||
Object {
|
||||
"cid": "cids(1)",
|
||||
"creator": Object {
|
||||
"did": "user(0)",
|
||||
"handle": "eve.test",
|
||||
"labels": Array [],
|
||||
},
|
||||
"indexedAt": "1970-01-01T00:00:00.000Z",
|
||||
"labels": Array [],
|
||||
"listItemCount": 3,
|
||||
"name": "blah curate list!",
|
||||
"purpose": "app.bsky.graph.defs#curatelist",
|
||||
"uri": "record(1)",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`bsky actor likes feed views does not include users with creator block relationship in reference and curate 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)",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`bsky actor likes feed views does not include users with creator block relationship in reference and curate lists for signed-out viewers 2`] = `
|
||||
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)",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
@ -100,6 +212,41 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`bsky actor likes feed views does not include users with creator block relationship in reference lists for non-creator, in-list viewers 2`] = `
|
||||
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 {
|
||||
@ -134,7 +281,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`bsky actor likes feed views does not include users with creator block relationship in reference lists for signed-out viewers 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 2`] = `
|
||||
Array [
|
||||
Object {
|
||||
"subject": Object {
|
||||
@ -146,6 +293,10 @@ Array [
|
||||
"handle": "bob.test",
|
||||
"indexedAt": "1970-01-01T00:00:00.000Z",
|
||||
"labels": Array [],
|
||||
"viewer": Object {
|
||||
"blockedBy": false,
|
||||
"muted": false,
|
||||
},
|
||||
},
|
||||
"uri": "record(0)",
|
||||
},
|
||||
@ -154,6 +305,39 @@ Array [
|
||||
"did": "user(2)",
|
||||
"handle": "eve.test",
|
||||
"labels": Array [],
|
||||
"viewer": Object {
|
||||
"blockedBy": false,
|
||||
"muted": false,
|
||||
},
|
||||
},
|
||||
"uri": "record(1)",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`bsky actor likes feed views does return all users regardless of creator block relationship in moderation lists 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"subject": Object {
|
||||
"did": "user(0)",
|
||||
"handle": "greta.test",
|
||||
"labels": Array [],
|
||||
"viewer": Object {
|
||||
"blockedBy": false,
|
||||
"muted": false,
|
||||
},
|
||||
},
|
||||
"uri": "record(0)",
|
||||
},
|
||||
Object {
|
||||
"subject": Object {
|
||||
"did": "user(1)",
|
||||
"handle": "frankie.test",
|
||||
"labels": Array [],
|
||||
"viewer": Object {
|
||||
"blockedBy": false,
|
||||
"muted": false,
|
||||
},
|
||||
},
|
||||
"uri": "record(1)",
|
||||
},
|
||||
|
@ -175,4 +175,16 @@ describe('list feed views', () => {
|
||||
recordUri: postRef.uriStr,
|
||||
})
|
||||
})
|
||||
|
||||
it('does not return posts with creator blocks', async () => {
|
||||
await sc.block(bob, alice)
|
||||
await network.processAll()
|
||||
|
||||
const res = await agent.api.app.bsky.feed.getListFeed({
|
||||
list: listRef.uriStr,
|
||||
})
|
||||
|
||||
const hasBob = res.data.feed.some((item) => item.post.author.did === bob)
|
||||
expect(hasBob).toBe(false)
|
||||
})
|
||||
})
|
||||
|
@ -8,7 +8,9 @@ describe('bsky actor likes feed views', () => {
|
||||
let agent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
let curateList: string
|
||||
let referenceList: string
|
||||
let alice: string
|
||||
let eve: string
|
||||
let frankie: string
|
||||
let greta: string
|
||||
@ -35,17 +37,32 @@ describe('bsky actor likes feed views', () => {
|
||||
email: 'greta@greta.com',
|
||||
password: 'hunter4real',
|
||||
})
|
||||
const newList = await sc.createList(
|
||||
|
||||
const newRefList = await sc.createList(
|
||||
sc.dids.eve,
|
||||
'blah starter pack list!',
|
||||
'reference',
|
||||
)
|
||||
await sc.addToList(sc.dids.eve, sc.dids.eve, newList)
|
||||
await sc.addToList(sc.dids.eve, sc.dids.bob, newList)
|
||||
await sc.addToList(sc.dids.eve, sc.dids.frankie, newList)
|
||||
const newCurrList = await sc.createList(
|
||||
sc.dids.eve,
|
||||
'blah curate list!',
|
||||
'curate',
|
||||
)
|
||||
|
||||
await sc.addToList(sc.dids.eve, sc.dids.eve, newRefList)
|
||||
await sc.addToList(sc.dids.eve, sc.dids.bob, newRefList)
|
||||
await sc.addToList(sc.dids.eve, sc.dids.frankie, newRefList)
|
||||
|
||||
await sc.addToList(sc.dids.eve, sc.dids.eve, newCurrList)
|
||||
await sc.addToList(sc.dids.eve, sc.dids.bob, newCurrList)
|
||||
await sc.addToList(sc.dids.eve, sc.dids.frankie, newCurrList)
|
||||
|
||||
await sc.block(sc.dids.frankie, sc.dids.eve)
|
||||
|
||||
await network.processAll()
|
||||
referenceList = newList.uriStr
|
||||
curateList = newCurrList.uriStr
|
||||
referenceList = newRefList.uriStr
|
||||
alice = sc.dids.alice
|
||||
eve = sc.dids.eve
|
||||
frankie = sc.dids.frankie
|
||||
greta = sc.dids.greta
|
||||
@ -61,44 +78,92 @@ describe('bsky actor likes feed views', () => {
|
||||
const view = await agent.api.app.bsky.graph.getLists({
|
||||
actor: eve,
|
||||
})
|
||||
expect(view.data.lists.length).toBe(1)
|
||||
expect(view.data.lists.length).toBe(2)
|
||||
expect(forSnapshot(view.data.lists)).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('does not include users with creator block relationship in reference lists for non-creator, in-list viewers', async () => {
|
||||
const view = await agent.api.app.bsky.graph.getList(
|
||||
const curView = await agent.api.app.bsky.graph.getList(
|
||||
{
|
||||
list: curateList,
|
||||
},
|
||||
{
|
||||
headers: await network.serviceHeaders(frankie, ids.AppBskyGraphGetList),
|
||||
},
|
||||
)
|
||||
expect(curView.data.items.length).toBe(2)
|
||||
expect(forSnapshot(curView.data.items)).toMatchSnapshot()
|
||||
|
||||
const refView = await agent.api.app.bsky.graph.getList(
|
||||
{ list: referenceList },
|
||||
{
|
||||
headers: await network.serviceHeaders(frankie, ids.AppBskyGraphGetList),
|
||||
},
|
||||
)
|
||||
expect(view.data.items.length).toBe(2)
|
||||
expect(forSnapshot(view.data.items)).toMatchSnapshot()
|
||||
expect(refView.data.items.length).toBe(2)
|
||||
expect(forSnapshot(refView.data.items)).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('does not include users with creator block relationship in reference lists for non-creator, not-in-list viewers', async () => {
|
||||
const view = await agent.api.app.bsky.graph.getList(
|
||||
const curView = await agent.api.app.bsky.graph.getList(
|
||||
{
|
||||
list: curateList,
|
||||
},
|
||||
{ headers: await network.serviceHeaders(greta, ids.AppBskyGraphGetList) },
|
||||
)
|
||||
expect(curView.data.items.length).toBe(2)
|
||||
expect(forSnapshot(curView.data.items)).toMatchSnapshot()
|
||||
|
||||
const refView = await agent.api.app.bsky.graph.getList(
|
||||
{ list: referenceList },
|
||||
{ headers: await network.serviceHeaders(greta, ids.AppBskyGraphGetList) },
|
||||
)
|
||||
expect(view.data.items.length).toBe(2)
|
||||
expect(forSnapshot(view.data.items)).toMatchSnapshot()
|
||||
expect(refView.data.items.length).toBe(2)
|
||||
expect(forSnapshot(refView.data.items)).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('does not include users with creator block relationship in reference lists for signed-out viewers', async () => {
|
||||
const view = await agent.api.app.bsky.graph.getList({
|
||||
it('does not include users with creator block relationship in reference and curate lists for signed-out viewers', async () => {
|
||||
const curView = await agent.api.app.bsky.graph.getList({
|
||||
list: curateList,
|
||||
})
|
||||
expect(curView.data.items.length).toBe(2)
|
||||
expect(forSnapshot(curView.data.items)).toMatchSnapshot()
|
||||
|
||||
const refView = await agent.api.app.bsky.graph.getList({
|
||||
list: referenceList,
|
||||
})
|
||||
expect(view.data.items.length).toBe(2)
|
||||
expect(forSnapshot(view.data.items)).toMatchSnapshot()
|
||||
expect(refView.data.items.length).toBe(2)
|
||||
expect(forSnapshot(refView.data.items)).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('does include users with creator block relationship in reference lists for creator', async () => {
|
||||
const view = await agent.api.app.bsky.graph.getList(
|
||||
const curView = await agent.api.app.bsky.graph.getList(
|
||||
{ list: curateList },
|
||||
{ headers: await network.serviceHeaders(eve, ids.AppBskyGraphGetList) },
|
||||
)
|
||||
expect(curView.data.items.length).toBe(3)
|
||||
expect(forSnapshot(curView.data.items)).toMatchSnapshot()
|
||||
|
||||
const refView = await agent.api.app.bsky.graph.getList(
|
||||
{ list: referenceList },
|
||||
{ headers: await network.serviceHeaders(eve, ids.AppBskyGraphGetList) },
|
||||
)
|
||||
expect(view.data.items.length).toBe(3)
|
||||
expect(refView.data.items.length).toBe(3)
|
||||
expect(forSnapshot(refView.data.items)).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('does return all users regardless of creator block relationship in moderation lists', async () => {
|
||||
const blockList = await sc.createList(eve, 'block list', 'mod')
|
||||
await sc.addToList(eve, frankie, blockList)
|
||||
await sc.addToList(eve, greta, blockList)
|
||||
await sc.block(frankie, greta)
|
||||
await network.processAll()
|
||||
|
||||
const view = await agent.api.app.bsky.graph.getList(
|
||||
{ list: blockList.uriStr },
|
||||
{ headers: await network.serviceHeaders(alice, ids.AppBskyGraphGetList) },
|
||||
)
|
||||
expect(view.data.items.length).toBe(2)
|
||||
expect(forSnapshot(view.data.items)).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user