mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
feat(backend): pin public group posts (#8606)
* feat(backend): pin more than one post * add postPinnedCount query, better names for env variable * add store and mixin for pinned posts counts * test pinned post store * context menu for pin posts * fix typos * unpin posts is always possible * feat(backend): pin public group posts * allow posts in public groups to be pinned by admins --------- Co-authored-by: Wolfgang Huß <wolle.huss@pjannto.com>
This commit is contained in:
parent
b736a2a2e3
commit
fb2ef852a1
@ -10,6 +10,7 @@ import CONFIG from '@config/index'
|
|||||||
import databaseContext from '@context/database'
|
import databaseContext from '@context/database'
|
||||||
import Factory, { cleanDatabase } from '@db/factories'
|
import Factory, { cleanDatabase } from '@db/factories'
|
||||||
import Image from '@db/models/Image'
|
import Image from '@db/models/Image'
|
||||||
|
import { createGroupMutation } from '@graphql/queries/createGroupMutation'
|
||||||
import { createPostMutation } from '@graphql/queries/createPostMutation'
|
import { createPostMutation } from '@graphql/queries/createPostMutation'
|
||||||
import createServer, { getContext } from '@src/server'
|
import createServer, { getContext } from '@src/server'
|
||||||
|
|
||||||
@ -1305,6 +1306,130 @@ describe('pin posts', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('post in public group', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: createGroupMutation(),
|
||||||
|
variables: {
|
||||||
|
name: 'Public Group',
|
||||||
|
id: 'public-group',
|
||||||
|
about: 'This is a public group',
|
||||||
|
groupType: 'public',
|
||||||
|
actionRadius: 'regional',
|
||||||
|
description:
|
||||||
|
'This is a public group to test if the posts of this group can be pinned.',
|
||||||
|
categoryIds,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: createPostMutation(),
|
||||||
|
variables: {
|
||||||
|
id: 'public-group-post',
|
||||||
|
title: 'Public group post',
|
||||||
|
content: 'This is a post in a public group',
|
||||||
|
groupId: 'public-group',
|
||||||
|
categoryIds,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
variables = { ...variables, id: 'public-group-post' }
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can be pinned', async () => {
|
||||||
|
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject({
|
||||||
|
data: {
|
||||||
|
pinPost: {
|
||||||
|
id: 'public-group-post',
|
||||||
|
author: {
|
||||||
|
slug: 'testuser',
|
||||||
|
},
|
||||||
|
pinnedBy: {
|
||||||
|
id: 'current-user',
|
||||||
|
name: 'Admin',
|
||||||
|
role: 'admin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('post in closed group', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: createGroupMutation(),
|
||||||
|
variables: {
|
||||||
|
name: 'Closed Group',
|
||||||
|
id: 'closed-group',
|
||||||
|
about: 'This is a closed group',
|
||||||
|
groupType: 'closed',
|
||||||
|
actionRadius: 'regional',
|
||||||
|
description:
|
||||||
|
'This is a closed group to test if the posts of this group can be pinned.',
|
||||||
|
categoryIds,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: createPostMutation(),
|
||||||
|
variables: {
|
||||||
|
id: 'closed-group-post',
|
||||||
|
title: 'Closed group post',
|
||||||
|
content: 'This is a post in a closed group',
|
||||||
|
groupId: 'closed-group',
|
||||||
|
categoryIds,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
variables = { ...variables, id: 'closed-group-post' }
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can not be pinned', async () => {
|
||||||
|
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject({
|
||||||
|
data: {
|
||||||
|
pinPost: null,
|
||||||
|
},
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('post in hidden group', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: createGroupMutation(),
|
||||||
|
variables: {
|
||||||
|
name: 'Hidden Group',
|
||||||
|
id: 'hidden-group',
|
||||||
|
about: 'This is a hidden group',
|
||||||
|
groupType: 'hidden',
|
||||||
|
actionRadius: 'regional',
|
||||||
|
description:
|
||||||
|
'This is a hidden group to test if the posts of this group can be pinned.',
|
||||||
|
categoryIds,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: createPostMutation(),
|
||||||
|
variables: {
|
||||||
|
id: 'hidden-group-post',
|
||||||
|
title: 'Hidden group post',
|
||||||
|
content: 'This is a post in a hidden group',
|
||||||
|
groupId: 'hidden-group',
|
||||||
|
categoryIds,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
variables = { ...variables, id: 'hidden-group-post' }
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can not be pinned', async () => {
|
||||||
|
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject({
|
||||||
|
data: {
|
||||||
|
pinPost: null,
|
||||||
|
},
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('PostOrdering', () => {
|
describe('PostOrdering', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await Factory.build('post', {
|
await Factory.build('post', {
|
||||||
|
|||||||
@ -351,7 +351,8 @@ export default {
|
|||||||
const pinPostCypher = `
|
const pinPostCypher = `
|
||||||
MATCH (user:User {id: $userId}) WHERE user.role = 'admin'
|
MATCH (user:User {id: $userId}) WHERE user.role = 'admin'
|
||||||
MATCH (post:Post {id: $params.id})
|
MATCH (post:Post {id: $params.id})
|
||||||
WHERE NOT((post)-[:IN]->(:Group))
|
WHERE NOT EXISTS((post)-[:IN]->(:Group)) OR
|
||||||
|
(post)-[:IN]->(:Group { groupType: 'public'})
|
||||||
MERGE (user)-[pinned:PINNED {createdAt: toString(datetime())}]->(post)
|
MERGE (user)-[pinned:PINNED {createdAt: toString(datetime())}]->(post)
|
||||||
SET post.pinned = true
|
SET post.pinned = true
|
||||||
RETURN post, pinned.createdAt as pinnedAt`
|
RETURN post, pinned.createdAt as pinnedAt`
|
||||||
|
|||||||
@ -197,6 +197,79 @@ describe('ContentMenu.vue', () => {
|
|||||||
],
|
],
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('post in public group', () => {
|
||||||
|
it('can pin unpinned post', async () => {
|
||||||
|
getters['auth/isAdmin'] = () => true
|
||||||
|
const wrapper = await openContentMenu({
|
||||||
|
isOwner: false,
|
||||||
|
resourceType: 'contribution',
|
||||||
|
resource: {
|
||||||
|
id: 'd23a4265-f5f7-4e17-9f86-85f714b4b9f8',
|
||||||
|
pinnedBy: null,
|
||||||
|
group: {
|
||||||
|
groupType: 'public',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
wrapper
|
||||||
|
.findAll('.ds-menu-item')
|
||||||
|
.filter((item) => item.text() === 'post.menu.pin')
|
||||||
|
.at(0)
|
||||||
|
.trigger('click')
|
||||||
|
expect(wrapper.emitted('pinPost')).toEqual([
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'd23a4265-f5f7-4e17-9f86-85f714b4b9f8',
|
||||||
|
pinnedBy: null,
|
||||||
|
group: {
|
||||||
|
groupType: 'public',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('post in closed group', () => {
|
||||||
|
it('can not be pinned', async () => {
|
||||||
|
getters['auth/isAdmin'] = () => true
|
||||||
|
const wrapper = await openContentMenu({
|
||||||
|
isOwner: false,
|
||||||
|
resourceType: 'contribution',
|
||||||
|
resource: {
|
||||||
|
id: 'd23a4265-f5f7-4e17-9f86-85f714b4b9f8',
|
||||||
|
pinnedBy: null,
|
||||||
|
group: {
|
||||||
|
groupType: 'closed',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
wrapper.findAll('.ds-menu-item').filter((item) => item.text() === 'post.menu.pin'),
|
||||||
|
).toHaveLength(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('post in hidden group', () => {
|
||||||
|
it('can not be pinned', async () => {
|
||||||
|
getters['auth/isAdmin'] = () => true
|
||||||
|
const wrapper = await openContentMenu({
|
||||||
|
isOwner: false,
|
||||||
|
resourceType: 'contribution',
|
||||||
|
resource: {
|
||||||
|
id: 'd23a4265-f5f7-4e17-9f86-85f714b4b9f8',
|
||||||
|
pinnedBy: null,
|
||||||
|
group: {
|
||||||
|
groupType: 'hidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
wrapper.findAll('.ds-menu-item').filter((item) => item.text() === 'post.menu.pin'),
|
||||||
|
).toHaveLength(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('when maxPinnedPosts = 3', () => {
|
describe('when maxPinnedPosts = 3', () => {
|
||||||
|
|||||||
@ -82,7 +82,7 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isAdmin && !this.resource.group) {
|
if (this.isAdmin && (!this.resource.group || this.resource.group.groupType === 'public')) {
|
||||||
if (!this.resource.pinnedBy && this.canBePinned) {
|
if (!this.resource.pinnedBy && this.canBePinned) {
|
||||||
routes.push({
|
routes.push({
|
||||||
label: this.$t(`post.menu.pin`),
|
label: this.$t(`post.menu.pin`),
|
||||||
|
|||||||
@ -53,6 +53,7 @@ export default (i18n) => {
|
|||||||
id
|
id
|
||||||
name
|
name
|
||||||
slug
|
slug
|
||||||
|
groupType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,6 +96,7 @@ export const filterPosts = (i18n) => {
|
|||||||
id
|
id
|
||||||
name
|
name
|
||||||
slug
|
slug
|
||||||
|
groupType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,6 +138,7 @@ export const profilePagePosts = (i18n) => {
|
|||||||
id
|
id
|
||||||
name
|
name
|
||||||
slug
|
slug
|
||||||
|
groupType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user