fix(backend): ensure a pinned post is accessible even tho the user was muted (#9200)

This commit is contained in:
Ulf Gebhardt 2026-02-10 19:55:33 +01:00 committed by GitHub
parent 04effaa506
commit f2e77595b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 150 additions and 0 deletions

View File

@ -8,6 +8,8 @@ import { getMutedUsers } from '@graphql/resolvers/users'
export const filterForMutedUsers = async (params, context) => {
if (!context.user) return params
// Skip mute filter for single post lookups (direct navigation by id or slug)
if (params.id || params.slug) return params
const [mutedUsers] = await Promise.all([getMutedUsers(context)])
const mutedUsersIds = [...mutedUsers.map((user) => user.id)]
if (!mutedUsersIds.length) return params

View File

@ -245,6 +245,81 @@ describe('blockUser', () => {
})
})
})
describe('if the current user blocks and mutes the other user', () => {
beforeEach(async () => {
await currentUser.relateTo(blockedUser, 'blocked')
await currentUser.relateTo(blockedUser, 'muted')
})
it('the muted+blocked user post is still accessible by direct id lookup', async () => {
await expect(query({ query: Post, variables: { id: 'p23' } })).resolves.toMatchObject(
{
data: {
Post: [
expect.objectContaining({
id: 'p23',
title: 'A post written by the blocked user',
}),
],
},
},
)
})
describe('and the blocked+muted user has a pinned post', () => {
beforeEach(async () => {
const pinnedPost = await database.neode.create('Post', {
id: 'p-pinned',
title: 'A pinned post by the blocked user',
content: 'pinned content',
pinned: true,
})
await pinnedPost.relateTo(blockedUser, 'author')
})
it('the pinned post is still accessible by id', async () => {
await expect(
query({ query: Post, variables: { id: 'p-pinned' } }),
).resolves.toMatchObject({
data: {
Post: [
expect.objectContaining({
id: 'p-pinned',
title: 'A pinned post by the blocked user',
pinned: true,
}),
],
},
})
})
it('the pinned post shows up in the post list', async () => {
await expect(
query({ query: Post, variables: { orderBy: 'createdAt_asc' } }),
).resolves.toMatchObject({
data: {
Post: expect.arrayContaining([
expect.objectContaining({
id: 'p-pinned',
pinned: true,
}),
]),
},
})
})
it('the non-pinned post from the muted+blocked user is still hidden in the feed', async () => {
const result = await query({
query: Post,
variables: { orderBy: 'createdAt_asc' },
})
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
const postIds = result.data?.Post.map((p) => p.id)
expect(postIds).not.toContain('p23')
})
})
})
})
describe('from the perspective of the blocked user', () => {

View File

@ -241,6 +241,79 @@ describe('muteUser', () => {
},
})
})
it("the muted user's post is still accessible by direct id lookup", async () => {
const { query } = createTestClient(server)
await expect(query({ query: Post, variables: { id: 'p23' } })).resolves.toMatchObject(
{
data: {
Post: [
expect.objectContaining({
id: 'p23',
title: 'A post written by the muted user',
}),
],
},
},
)
})
describe('but the muted user has a pinned post', () => {
beforeEach(async () => {
const pinnedPost = await neode.create('Post', {
id: 'p-pinned',
title: 'A pinned post by the muted user',
content: 'pinned content',
pinned: true,
})
await pinnedPost.relateTo(mutedUser, 'author')
})
it('the pinned post still shows up in the post list', async () => {
const { query } = createTestClient(server)
await expect(
query({ query: Post, variables: { orderBy: 'createdAt_asc' } }),
).resolves.toMatchObject({
data: {
Post: expect.arrayContaining([
expect.objectContaining({
id: 'p-pinned',
title: 'A pinned post by the muted user',
pinned: true,
}),
]),
},
})
})
it('the pinned post is accessible by id', async () => {
const { query } = createTestClient(server)
await expect(
query({ query: Post, variables: { id: 'p-pinned' } }),
).resolves.toMatchObject({
data: {
Post: [
expect.objectContaining({
id: 'p-pinned',
title: 'A pinned post by the muted user',
pinned: true,
}),
],
},
})
})
it('the non-pinned post from the muted user is still hidden in the feed', async () => {
const { query } = createTestClient(server)
const result = await query({
query: Post,
variables: { orderBy: 'createdAt_asc' },
})
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
const postIds = result.data?.Post.map((p) => p.id)
expect(postIds).not.toContain('p23')
})
})
})
})