mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge pull request #6091 from Ocelot-Social-Community/filter-posts-in-my-groups
feat(backend): filter posts in my groups
This commit is contained in:
commit
5538ef93db
@ -0,0 +1,40 @@
|
||||
import { mergeWith, isArray } from 'lodash'
|
||||
|
||||
const getMyGroupIds = async (context) => {
|
||||
const { user } = context
|
||||
if (!(user && user.id)) return []
|
||||
const session = context.driver.session()
|
||||
|
||||
const readTxResultPromise = await session.readTransaction(async (transaction) => {
|
||||
const cypher = `
|
||||
MATCH (group:Group)<-[membership:MEMBER_OF]-(:User { id: $userId })
|
||||
WHERE membership.role IN ['usual', 'admin', 'owner']
|
||||
RETURN collect(group.id) AS myGroupIds`
|
||||
const getMyGroupIdsResponse = await transaction.run(cypher, { userId: user.id })
|
||||
return getMyGroupIdsResponse.records.map((record) => record.get('myGroupIds'))
|
||||
})
|
||||
try {
|
||||
const [myGroupIds] = readTxResultPromise
|
||||
return myGroupIds
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export const filterPostsOfMyGroups = async (params, context) => {
|
||||
if (!(params.filter && params.filter.postsInMyGroups)) return params
|
||||
delete params.filter.postsInMyGroups
|
||||
const myGroupIds = await getMyGroupIds(context)
|
||||
params.filter = mergeWith(
|
||||
params.filter,
|
||||
{
|
||||
group: { id_in: myGroupIds },
|
||||
},
|
||||
(objValue, srcValue) => {
|
||||
if (isArray(objValue)) {
|
||||
return objValue.concat(srcValue)
|
||||
}
|
||||
},
|
||||
)
|
||||
return params
|
||||
}
|
||||
@ -6,6 +6,7 @@ import { mergeImage, deleteImage } from './images/images'
|
||||
import Resolver from './helpers/Resolver'
|
||||
import { filterForMutedUsers } from './helpers/filterForMutedUsers'
|
||||
import { filterInvisiblePosts } from './helpers/filterInvisiblePosts'
|
||||
import { filterPostsOfMyGroups } from './helpers/filterPostsOfMyGroups'
|
||||
import CONFIG from '../../config'
|
||||
|
||||
const maintainPinnedPosts = (params) => {
|
||||
@ -21,12 +22,14 @@ const maintainPinnedPosts = (params) => {
|
||||
export default {
|
||||
Query: {
|
||||
Post: async (object, params, context, resolveInfo) => {
|
||||
params = await filterPostsOfMyGroups(params, context)
|
||||
params = await filterInvisiblePosts(params, context)
|
||||
params = await filterForMutedUsers(params, context)
|
||||
params = await maintainPinnedPosts(params)
|
||||
return neo4jgraphql(object, params, context, resolveInfo)
|
||||
},
|
||||
profilePagePosts: async (object, params, context, resolveInfo) => {
|
||||
params = await filterPostsOfMyGroups(params, context)
|
||||
params = await filterInvisiblePosts(params, context)
|
||||
params = await filterForMutedUsers(params, context)
|
||||
return neo4jgraphql(object, params, context, resolveInfo)
|
||||
|
||||
@ -1678,5 +1678,59 @@ describe('Posts in Groups', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('filter posts in my groups', () => {
|
||||
describe('without any posts in groups', () => {
|
||||
beforeAll(async () => {
|
||||
authenticatedUser = await anyUser.toJson()
|
||||
})
|
||||
|
||||
it('finds no posts', async () => {
|
||||
const result = await query({
|
||||
query: filterPosts(),
|
||||
variables: { filter: { postsInMyGroups: true } },
|
||||
})
|
||||
expect(result.data.Post).toHaveLength(0)
|
||||
expect(result).toMatchObject({
|
||||
data: {
|
||||
Post: [],
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with posts in groups', () => {
|
||||
beforeAll(async () => {
|
||||
// member of hidden-group and closed-group
|
||||
authenticatedUser = await allGroupsUser.toJson()
|
||||
})
|
||||
|
||||
it('finds two posts', async () => {
|
||||
const result = await query({
|
||||
query: filterPosts(),
|
||||
variables: { filter: { postsInMyGroups: true } },
|
||||
})
|
||||
expect(result.data.Post).toHaveLength(2)
|
||||
expect(result).toMatchObject({
|
||||
data: {
|
||||
Post: expect.arrayContaining([
|
||||
{
|
||||
id: 'post-to-closed-group',
|
||||
title: 'A post to a closed group',
|
||||
content: 'I am posting into a closed group as a member of the group',
|
||||
},
|
||||
{
|
||||
id: 'post-to-hidden-group',
|
||||
title: 'A post to a hidden group',
|
||||
content: 'I am posting into a hidden group as a member of the group',
|
||||
},
|
||||
]),
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -82,6 +82,7 @@ input _PostFilter {
|
||||
emotions_single: _PostEMOTEDFilter
|
||||
emotions_every: _PostEMOTEDFilter
|
||||
group: _GroupFilter
|
||||
postsInMyGroups: Boolean
|
||||
}
|
||||
|
||||
enum _PostOrdering {
|
||||
|
||||
@ -9,12 +9,14 @@ let wrapper
|
||||
describe('FollowingFilter', () => {
|
||||
const mutations = {
|
||||
'posts/TOGGLE_FILTER_BY_FOLLOWED': jest.fn(),
|
||||
'posts/TOGGLE_FILTER_BY_MY_GROUPS': jest.fn(),
|
||||
}
|
||||
const getters = {
|
||||
'auth/user': () => {
|
||||
return { id: 'u34' }
|
||||
},
|
||||
'posts/filteredByUsersFollowed': jest.fn(),
|
||||
'posts/filteredByPostsInMyGroups': jest.fn(),
|
||||
}
|
||||
|
||||
const mocks = {
|
||||
@ -34,12 +36,18 @@ describe('FollowingFilter', () => {
|
||||
describe('mount', () => {
|
||||
it('sets "filter-by-followed" button attribute `filled`', () => {
|
||||
getters['posts/filteredByUsersFollowed'] = jest.fn(() => true)
|
||||
getters['posts/filteredByPostsInMyGroups'] = jest.fn(() => true)
|
||||
const wrapper = Wrapper()
|
||||
expect(
|
||||
wrapper
|
||||
.find('.following-filter .filter-list .follower-item .base-button')
|
||||
.classes('--filled'),
|
||||
).toBe(true)
|
||||
expect(
|
||||
wrapper
|
||||
.find('.following-filter .filter-list .posts-in-my-groups-item .base-button')
|
||||
.classes('--filled'),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
describe('click "filter-by-followed" button', () => {
|
||||
@ -48,5 +56,14 @@ describe('FollowingFilter', () => {
|
||||
expect(mutations['posts/TOGGLE_FILTER_BY_FOLLOWED']).toHaveBeenCalledWith({}, 'u34')
|
||||
})
|
||||
})
|
||||
|
||||
describe('click "filter-by-my-groups" button', () => {
|
||||
it('calls TOGGLE_FILTER_BY_MY_GROUPS', () => {
|
||||
wrapper
|
||||
.find('.following-filter .filter-list .posts-in-my-groups-item .base-button')
|
||||
.trigger('click')
|
||||
expect(mutations['posts/TOGGLE_FILTER_BY_MY_GROUPS']).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -10,6 +10,15 @@
|
||||
@click="toggleFilteredByFollowed(currentUser.id)"
|
||||
/>
|
||||
</li>
|
||||
<li class="item posts-in-my-groups-item">
|
||||
<labeled-button
|
||||
icon="users"
|
||||
:label="$t('filter-menu.my-groups')"
|
||||
:filled="filteredByPostsInMyGroups"
|
||||
:title="$t('contribution.filterMyGroups')"
|
||||
@click="toggleFilteredByMyGroups()"
|
||||
/>
|
||||
</li>
|
||||
</template>
|
||||
</filter-menu-section>
|
||||
</template>
|
||||
@ -28,12 +37,14 @@ export default {
|
||||
computed: {
|
||||
...mapGetters({
|
||||
filteredByUsersFollowed: 'posts/filteredByUsersFollowed',
|
||||
filteredByPostsInMyGroups: 'posts/filteredByPostsInMyGroups',
|
||||
currentUser: 'auth/user',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
toggleFilteredByFollowed: 'posts/TOGGLE_FILTER_BY_FOLLOWED',
|
||||
toggleFilteredByMyGroups: 'posts/TOGGLE_FILTER_BY_MY_GROUPS',
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
@ -270,9 +270,11 @@
|
||||
"filterFollow": "Beiträge von Nutzern filtern, denen ich folge",
|
||||
"filterMasonryGrid": {
|
||||
"myFriends": "Nutzer denen ich folge",
|
||||
"myGroups": "Meine Gruppen",
|
||||
"myTopics": "Meine Themen",
|
||||
"noFilter": "Beiträge filtern"
|
||||
},
|
||||
"filterMyGroups": "Beiträge in meinen Gruppen",
|
||||
"inappropriatePicture": "Dieses Bild kann für einige Menschen unangemessen sein.",
|
||||
"languageSelectLabel": "Sprache Deines Beitrags",
|
||||
"languageSelectText": "Sprache wählen",
|
||||
@ -380,6 +382,7 @@
|
||||
"filter-by": "Filtern nach ...",
|
||||
"following": "Nutzer denen ich folge",
|
||||
"languages": "Sprachen",
|
||||
"my-groups": "Meinen Gruppen",
|
||||
"order": {
|
||||
"newest": {
|
||||
"hint": "Sortiere die Neuesten nach vorn",
|
||||
|
||||
@ -270,9 +270,11 @@
|
||||
"filterFollow": "Filter contributions from users I follow",
|
||||
"filterMasonryGrid": {
|
||||
"myFriends": "Users I follow",
|
||||
"myGroups": "My groups",
|
||||
"myTopics": "My topics",
|
||||
"noFilter": "Filter posts"
|
||||
},
|
||||
"filterMyGroups": "Contributions in my groups",
|
||||
"inappropriatePicture": "This image may be inappropriate for some people.",
|
||||
"languageSelectLabel": "Language of your contribution",
|
||||
"languageSelectText": "Select Language",
|
||||
@ -380,6 +382,7 @@
|
||||
"filter-by": "Filter by ...",
|
||||
"following": "Users I follow",
|
||||
"languages": "Languages",
|
||||
"my-groups": "My groups",
|
||||
"order": {
|
||||
"newest": {
|
||||
"hint": "Sort posts by the newest first",
|
||||
|
||||
@ -30,7 +30,11 @@
|
||||
<div class="filterButtonMenu" :class="{ 'hide-filter': hideByScroll }">
|
||||
<base-button
|
||||
class="my-filter-button"
|
||||
v-if="!postsFilter['categories_some'] && !postsFilter['author']"
|
||||
v-if="
|
||||
!postsFilter['categories_some'] &&
|
||||
!postsFilter['author'] &&
|
||||
!postsFilter['postsInMyGroups']
|
||||
"
|
||||
right
|
||||
@click="showFilter = !showFilter"
|
||||
filled
|
||||
@ -66,6 +70,20 @@
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span v-if="postsFilter['postsInMyGroups']">
|
||||
<base-button class="my-filter-button" right @click="showFilter = !showFilter" filled>
|
||||
{{ $t('contribution.filterMasonryGrid.myGroups') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
class="filter-remove"
|
||||
@click="resetByGroups"
|
||||
icon="close"
|
||||
:title="$t('filter-menu.deleteFilter')"
|
||||
style="margin-left: -8px"
|
||||
filled
|
||||
/>
|
||||
</span>
|
||||
|
||||
<div id="my-filter" v-if="showFilter">
|
||||
<div @mouseleave="showFilter = false">
|
||||
<filter-menu-component @showFilterMenu="showFilterMenu" />
|
||||
@ -203,6 +221,7 @@ export default {
|
||||
methods: {
|
||||
...mapMutations({
|
||||
resetByFollowed: 'posts/TOGGLE_FILTER_BY_FOLLOWED',
|
||||
resetByGroups: 'posts/TOGGLE_FILTER_BY_MY_GROUPS',
|
||||
resetCategories: 'posts/RESET_CATEGORIES',
|
||||
toggleCategory: 'posts/TOGGLE_CATEGORY',
|
||||
}),
|
||||
|
||||
@ -30,6 +30,18 @@ export const mutations = {
|
||||
}
|
||||
}
|
||||
},
|
||||
TOGGLE_FILTER_BY_MY_GROUPS(state) {
|
||||
const filter = clone(state.filter)
|
||||
if (get(filter, 'postsInMyGroups')) {
|
||||
delete filter.postsInMyGroups
|
||||
state.filter = filter
|
||||
} else {
|
||||
state.filter = {
|
||||
...filter,
|
||||
postsInMyGroups: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
RESET_CATEGORIES(state) {
|
||||
const filter = clone(state.filter)
|
||||
delete filter.categories_some
|
||||
@ -84,6 +96,9 @@ export const getters = {
|
||||
filteredByUsersFollowed(state) {
|
||||
return !!get(state.filter, 'author.followedBy_some.id')
|
||||
},
|
||||
filteredByPostsInMyGroups(state) {
|
||||
return !!get(state.filter, 'postsInMyGroups')
|
||||
},
|
||||
filteredByEmotions(state) {
|
||||
return get(state.filter, 'emotions_some.emotion_in') || []
|
||||
},
|
||||
|
||||
@ -56,6 +56,18 @@ describe('getters', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('filteredByPostsInMyGroups', () => {
|
||||
it('returns true if filter is set', () => {
|
||||
state = { filter: { postsInMyGroups: true } }
|
||||
expect(getters.filteredByPostsInMyGroups(state)).toBe(true)
|
||||
})
|
||||
|
||||
it('returns false if filter is not set', () => {
|
||||
state = { filter: { categories_some: { id_in: [23] } } }
|
||||
expect(getters.filteredByUsersFollowed(state)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('filteredByEmotions', () => {
|
||||
it('returns an emotions array if filter is set', () => {
|
||||
state = { filter: { emotions_some: { emotion_in: ['sad'] } } }
|
||||
@ -230,6 +242,35 @@ describe('mutations', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('TOGGLE_FILTER_BY_MY_GROUPS', () => {
|
||||
beforeEach(() => {
|
||||
testMutation = () => {
|
||||
mutations.TOGGLE_FILTER_BY_MY_GROUPS(state)
|
||||
return getters.filter(state)
|
||||
}
|
||||
})
|
||||
|
||||
describe('given empty filter', () => {
|
||||
beforeEach(() => {
|
||||
state = { filter: {} }
|
||||
})
|
||||
|
||||
it('sets postsInMyGroups filter to true', () => {
|
||||
expect(testMutation()).toEqual({ postsInMyGroups: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe('already filtered', () => {
|
||||
beforeEach(() => {
|
||||
state = { filter: { postsInMyGroups: true } }
|
||||
})
|
||||
|
||||
it('removes postsInMyGroups filter', () => {
|
||||
expect(testMutation()).toEqual({})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('TOGGLE_ORDER', () => {
|
||||
beforeEach(() => {
|
||||
testMutation = (key) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user