atproto/packages/bsky/tests/postgates.test.ts
Eric Bailey aba664fbdf
Detached QPs and hidden replies (#2675)
* Add new postgate lex, hiddeReplies to threadgate, codegen

* Add protobufs

* Add to mock dataplane

* Add matching postgate method to feed hydration methods

* Add to getRecord

* Add to HydrationState

* Fix typo

* Add to mergeStates, fetch embeds in threads

* Integrate into embed views

* Add test for QPs in threads

* Add feed test

* Fix naming convention in protos

* Add #viewRemoved record view, rename postgate.json

* Integrate new view

* Filter hidden replies from feeds

* Filter out replies at the handler level, do not filter for author feeds

* Fix lint

* Move hidden reply check to view layer

* Reduce, reuse, recycle

* Rename to lowercase

* Rename layer vars

* Add quote gate props to postgate (#2693)

* Add quote gate props to postgate

* Consistent naming

* Fix record structure

* Codegen

* Show hidden replies in author feed

* Allow reposts of hidden replies

* Lex and codegen

* Add violates_quote_gate to proto

* Consistent naming, codegen

* Integrate violatesQuotegate and canQuotepost

* Remove rules, codegen

* Hydrate all postgates for all requested posts

* Match other impl

* Add test, need to split these out

* Format

* Hydrate first nested embeds too

* Add postgate test suite

* Add violatesQuoteGate to dataplane

* Ingest and set violatesQuoteGate, return on meta

* Return removed embed for quotes that violate gate

* Add test

* Dedupe URIs before fetching postgates

* Update snaps

* Snap

* Format

* Updating naming conventions for postgate-related attributes

* Correct naming

* Consistency

* Proto too

* Rename to viewDetached

* Codegen

* Rename everything

* Codegen

* Quotes that violate a quote gate can still be quoted themselves

* Couple more renames

* Snaps

* Ensure reply ref is tombstoned for hidden replies

* Split out hidden replies tests and create fresh fixture

* Hydrate threadgates for reply notifications, filter hidden replies

* Remove snap

* Add flaky test

* Rename violatesEmbeddingRules

* Fix flaky test

* Only write to db if violatesEmbeddingRules is true

* DRY up post uri -> gate uri logic

* isThreadgateListRule

* Don't share users object between tests

* No pascal

* Remove default params

* Find -> some

* canQuotepost -> canEmbed, remove optional

* Fix quoteee typo

* await follows

* Throw in post uri -> gate utils

* Ensure fetch threadgates for reply roots

* Don't hydrate threadgates twice

* DRY up uri -> did parsing

* Clean up parsePostgate logic

* Format

* Revert change

* Revert change

* Replace a couple more uri->did conversions

* Only filter replies from feeds if viewer hid them

* Revert, filter out replies that are hidden from feeds

* Remove old test

* Replace uri->did util

* Revert change to unused file

* Only validatePostEmbed and check postgates for post records

* Ensure notifications aren't generated down a hidden reply chain

* Changeset

* Cleanup

* Fix notification filtering logic

* Simplify

* Don't notify for invalid embeds

* Use new APIs

* Add hasPostGate and hasThreadGate flags from dataplane

* Only fetch postgates if post has one

* Only fetch threadgates if post has one or was deleted

* Remove notification filtering

* Don't hydrate threadgates for notifications

* Move hidden replies in feeds to match block handling

* Do no filtering of hidden replies in feeds

* Revert "Don't hydrate threadgates for notifications"

This reverts commit 1dcec0b239a7b9d6800427b26b8ba3e6a54210f9.

* Revert "Remove notification filtering"

This reverts commit 1e7069dfd809d1f18e9f05fd1d422e7399aa1bb0.

* Filter notifications for OP only

* Add additional check to hidden replies test

* Move noty filter logic into method handler

* Update .changeset/perfect-parrots-appear.md

Co-authored-by: devin ivy <devinivy@gmail.com>

* Update packages/bsky/tests/seed/postgates.ts

Co-authored-by: devin ivy <devinivy@gmail.com>

* Another structuredClone

* Update packages/bsky/src/hydration/hydrator.ts

Co-authored-by: devin ivy <devinivy@gmail.com>

* Better comment

* Update packages/bsky/src/data-plane/server/indexing/plugins/post.ts

Co-authored-by: devin ivy <devinivy@gmail.com>

* Regen protos to match dataplane

* Update quotes snap to include embeddingDisabled

* Clarify usage of post uri -> gate utils

---------

Co-authored-by: devin ivy <devinivy@gmail.com>
2024-08-21 14:36:51 -05:00

187 lines
5.1 KiB
TypeScript

import { TestNetwork, SeedClient, RecordRef } from '@atproto/dev-env'
import AtpAgent, { AppBskyEmbedRecord } from '@atproto/api'
import { ids } from '../src/lexicon/lexicons'
import { postgatesSeed, Users } from './seed/postgates'
describe('postgates', () => {
let network: TestNetwork
let agent: AtpAgent
let pdsAgent: AtpAgent
let sc: SeedClient
let users: Users
beforeAll(async () => {
network = await TestNetwork.create({
dbPostgresSchema: 'bsky_tests_postgates',
})
agent = network.bsky.getClient()
pdsAgent = network.pds.getClient()
sc = network.getSeedClient()
const result = await postgatesSeed(sc)
users = result.users
await network.processAll()
})
afterAll(async () => {
await network.close()
})
describe(`quotee <-> quoter`, () => {
it(`quotee detaches own post from quoter`, async () => {
const quoteePost = await sc.post(users.quotee.did, `post`)
const quoterPost = await sc.post(
users.quoter.did,
`quote post`,
undefined,
undefined,
quoteePost.ref,
)
await pdsAgent.api.app.bsky.feed.postgate.create(
{
repo: users.quotee.did,
rkey: quoteePost.ref.uri.rkey,
},
{
post: quoteePost.ref.uriStr,
createdAt: new Date().toISOString(),
detachedEmbeddingUris: [quoterPost.ref.uriStr],
},
sc.getHeaders(users.quotee.did),
)
await network.processAll()
const root = await agent.api.app.bsky.feed.getPostThread(
{ uri: quoterPost.ref.uriStr },
{
headers: await network.serviceHeaders(
users.viewer.did,
ids.AppBskyFeedGetPostThread,
),
},
)
expect(
// @ts-ignore I know more than you
AppBskyEmbedRecord.isViewDetached(root.data.thread.post.embed.record),
).toBe(true)
})
it(`postgate made by bystander has no effect`, async () => {
const quoteePost = await sc.post(users.quotee.did, `post`)
const quoterPost = await sc.post(
users.quoter.did,
`quote post`,
undefined,
undefined,
quoteePost.ref,
)
await pdsAgent.api.app.bsky.feed.postgate.create(
{
repo: users.viewer.did,
rkey: quoteePost.ref.uri.rkey,
},
{
post: quoteePost.ref.uriStr,
createdAt: new Date().toISOString(),
detachedEmbeddingUris: [quoterPost.ref.uriStr],
},
sc.getHeaders(users.viewer.did),
)
await network.processAll()
const root = await agent.api.app.bsky.feed.getPostThread(
{ uri: quoterPost.ref.uriStr },
{
headers: await network.serviceHeaders(
users.viewer.did,
ids.AppBskyFeedGetPostThread,
),
},
)
expect(
// @ts-ignore I know more than you
AppBskyEmbedRecord.isViewDetached(root.data.thread.post.embed.record),
).toBe(false)
})
})
describe(`embeddingRules`, () => {
it(`disables quoteposts`, async () => {
const quoteePost = await sc.post(users.quotee.did, `post`)
await pdsAgent.api.app.bsky.feed.postgate.create(
{
repo: users.quotee.did,
rkey: quoteePost.ref.uri.rkey,
},
{
post: quoteePost.ref.uriStr,
createdAt: new Date().toISOString(),
embeddingRules: [{ $type: 'app.bsky.feed.postgate#disableRule' }],
},
sc.getHeaders(users.quotee.did),
)
await network.processAll()
const root = await agent.api.app.bsky.feed.getPostThread(
{ uri: quoteePost.ref.uriStr },
{
headers: await network.serviceHeaders(
users.viewer.did,
ids.AppBskyFeedGetPostThread,
),
},
)
expect(
// @ts-ignore I know more than you
root.data.thread.post.viewer.embeddingDisabled,
).toBe(true)
})
it(`quotepost created after quotes disabled hides embed`, async () => {
const quoteePost = await sc.post(users.quotee.did, `post`)
await pdsAgent.api.app.bsky.feed.postgate.create(
{
repo: users.quotee.did,
rkey: quoteePost.ref.uri.rkey,
},
{
post: quoteePost.ref.uriStr,
createdAt: new Date().toISOString(),
embeddingRules: [{ $type: 'app.bsky.feed.postgate#disableRule' }],
},
sc.getHeaders(users.quotee.did),
)
await network.processAll()
const quoterPost = await sc.post(
users.quoter.did,
`quote post`,
undefined,
undefined,
quoteePost.ref,
)
await network.processAll()
const root = await agent.api.app.bsky.feed.getPostThread(
{ uri: quoterPost.ref.uriStr },
{
headers: await network.serviceHeaders(
users.viewer.did,
ids.AppBskyFeedGetPostThread,
),
},
)
expect(
// @ts-ignore I know more than you
AppBskyEmbedRecord.isViewDetached(root.data.thread.post.embed.record),
).toBe(true)
})
})
})