Merge pull request #5332 from Ocelot-Social-Community/5059-groups/5318-group-profile-second

feat: 🍰 Implement Group Profile – Visibility
This commit is contained in:
Wolfgang Huß 2022-09-15 10:20:58 +02:00 committed by GitHub
commit 017a764812
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 126 additions and 95 deletions

View File

@ -120,36 +120,8 @@ export const changeGroupMemberRoleMutation = gql`
// ------ queries
export const groupQuery = gql`
query (
$isMember: Boolean
$id: ID
$name: String
$slug: String
$createdAt: String
$updatedAt: String
$about: String
$description: String
$locationName: String
$first: Int
$offset: Int
$orderBy: [_GroupOrdering]
$filter: _GroupFilter
) {
Group(
isMember: $isMember
id: $id
name: $name
slug: $slug
createdAt: $createdAt
updatedAt: $updatedAt
about: $about
description: $description
locationName: $locationName
first: $first
offset: $offset
orderBy: $orderBy
filter: $filter
) {
query ($isMember: Boolean, $id: ID, $slug: String) {
Group(isMember: $isMember, id: $id, slug: $slug) {
id
name
slug

View File

@ -4,20 +4,25 @@ import CONFIG from '../../config'
import { CATEGORIES_MIN, CATEGORIES_MAX } from '../../constants/categories'
import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '../../constants/groups'
import { removeHtmlTags } from '../../middleware/helpers/cleanHtml.js'
import Resolver from './helpers/Resolver'
import Resolver, {
removeUndefinedNullValuesFromObject,
convertObjectToCypherMapLiteral,
} from './helpers/Resolver'
import { mergeImage } from './images/images'
export default {
Query: {
Group: async (_object, params, context, _resolveInfo) => {
const { id: groupId, isMember } = params
const { isMember, id, slug } = params
const matchParams = { id, slug }
removeUndefinedNullValuesFromObject(matchParams)
const session = context.driver.session()
const readTxResultPromise = session.readTransaction(async (txc) => {
const groupIdCypher = groupId ? ` {id: "${groupId}"}` : ''
const groupMatchParamsCypher = convertObjectToCypherMapLiteral(matchParams, true)
let groupCypher
if (isMember === true) {
groupCypher = `
MATCH (:User {id: $userId})-[membership:MEMBER_OF]->(group:Group${groupIdCypher})
MATCH (:User {id: $userId})-[membership:MEMBER_OF]->(group:Group${groupMatchParamsCypher})
WITH group, membership
WHERE (group.groupType IN ['public', 'closed']) OR (group.groupType = 'hidden' AND membership.role IN ['usual', 'admin', 'owner'])
RETURN group {.*, myRole: membership.role}
@ -25,7 +30,7 @@ export default {
} else {
if (isMember === false) {
groupCypher = `
MATCH (group:Group${groupIdCypher})
MATCH (group:Group${groupMatchParamsCypher})
WHERE (NOT (:User {id: $userId})-[:MEMBER_OF]->(group))
WITH group
WHERE group.groupType IN ['public', 'closed']
@ -33,7 +38,7 @@ export default {
`
} else {
groupCypher = `
MATCH (group:Group${groupIdCypher})
MATCH (group:Group${groupMatchParamsCypher})
OPTIONAL MATCH (:User {id: $userId})-[membership:MEMBER_OF]->(group)
WITH group, membership
WHERE (group.groupType IN ['public', 'closed']) OR (group.groupType = 'hidden' AND membership.role IN ['usual', 'admin', 'owner'])

View File

@ -503,6 +503,72 @@ describe('in mode', () => {
})
})
describe('with given slug', () => {
describe("slug = 'the-best-group'", () => {
it('finds only the listed group with this slug', async () => {
const result = await query({
query: groupQuery,
variables: { slug: 'the-best-group' },
})
expect(result).toMatchObject({
data: {
Group: [
expect.objectContaining({
id: 'my-group',
slug: 'the-best-group',
myRole: 'owner',
}),
],
},
errors: undefined,
})
expect(result.data.Group.length).toBe(1)
})
})
describe("slug = 'third-investigative-journalism-group'", () => {
it("finds only the hidden group where I'm 'usual' member", async () => {
const result = await query({
query: groupQuery,
variables: { slug: 'third-investigative-journalism-group' },
})
expect(result).toMatchObject({
data: {
Group: expect.arrayContaining([
expect.objectContaining({
id: 'third-hidden-group',
slug: 'third-investigative-journalism-group',
myRole: 'usual',
}),
]),
},
errors: undefined,
})
expect(result.data.Group.length).toBe(1)
})
})
describe("slug = 'second-investigative-journalism-group'", () => {
it("finds no hidden group where I'm 'pending' member", async () => {
const result = await query({
query: groupQuery,
variables: { slug: 'second-investigative-journalism-group' },
})
expect(result.data.Group.length).toBe(0)
})
})
describe("slug = 'investigative-journalism-group'", () => {
it("finds no hidden group where I'm not(!) a member at all", async () => {
const result = await query({
query: groupQuery,
variables: { slug: 'investigative-journalism-group' },
})
expect(result.data.Group.length).toBe(0)
})
})
})
describe('isMember = true', () => {
it('finds only listed groups where user is member', async () => {
const result = await query({ query: groupQuery, variables: { isMember: true } })

View File

@ -121,3 +121,25 @@ export default function Resolver(type, options = {}) {
}
return result
}
export const removeUndefinedNullValuesFromObject = (obj) => {
Object.keys(obj).forEach((key) => {
if ([undefined, null].includes(obj[key])) {
delete obj[key]
}
})
}
export const convertObjectToCypherMapLiteral = (params, addSpaceInfrontIfMapIsNotEmpty = false) => {
// I have found no other way yet. maybe "apoc.convert.fromJsonMap(key)" can help, but couldn't get it how, see: https://stackoverflow.com/questions/43217823/neo4j-cypher-inline-conversion-of-string-to-a-map
// result looks like: '{id: "g0", slug: "yoga"}'
const paramsEntries = Object.entries(params)
let mapLiteral = ''
paramsEntries.forEach((ele, index) => {
mapLiteral += index === 0 ? '{' : ''
mapLiteral += `${ele[0]}: "${ele[1]}"`
mapLiteral += index < paramsEntries.length - 1 ? ', ' : '}'
})
mapLiteral = (addSpaceInfrontIfMapIsNotEmpty && mapLiteral.length > 0 ? ' ' : '') + mapLiteral
return mapLiteral
}

View File

@ -61,27 +61,19 @@ type Query {
Group(
isMember: Boolean # if 'undefined' or 'null' then get all groups
id: ID
name: String
slug: String
createdAt: String
updatedAt: String
about: String
description: String
# groupType: GroupType # test this
# actionRadius: GroupActionRadius # test this
# avatar: ImageInput # test this
locationName: String
first: Int
offset: Int
orderBy: [_GroupOrdering]
# first: Int # not implemented yet
# offset: Int # not implemented yet
# orderBy: [_GroupOrdering] # not implemented yet
# filter: _GroupFilter # not implemented yet
): [Group]
GroupMembers(
id: ID!
first: Int
offset: Int
orderBy: [_UserOrdering]
filter: _UserFilter
# first: Int # not implemented yet
# offset: Int # not implemented yet
# orderBy: [_UserOrdering] # not implemented yet
# filter: _UserFilter # not implemented yet
): [User]
# AvailableGroupTypes: [GroupType]!

View File

@ -120,36 +120,8 @@ export const changeGroupMemberRoleMutation = gql`
// ------ queries
export const groupQuery = gql`
query (
$isMember: Boolean
$id: ID
$name: String
$slug: String
$createdAt: String
$updatedAt: String
$about: String
$description: String
$locationName: String
$first: Int
$offset: Int
$orderBy: [_GroupOrdering]
$filter: _GroupFilter
) {
Group(
isMember: $isMember
id: $id
name: $name
slug: $slug
createdAt: $createdAt
updatedAt: $updatedAt
about: $about
description: $description
locationName: $locationName
first: $first
offset: $offset
orderBy: $orderBy
filter: $filter
) {
query ($isMember: Boolean, $id: ID, $slug: String) {
Group(isMember: $isMember, id: $id, slug: $slug) {
id
name
slug

View File

@ -10,22 +10,24 @@ export default function (options = {}) {
} = context
const idOrSlug = id || slug
const variables = { idOrSlug }
const client = apolloProvider.defaultClient
if (idOrSlug) {
const variables = { idOrSlug }
const client = apolloProvider.defaultClient
let response
let resource
response = await client.query({ query: queryId, variables })
resource = response.data[Object.keys(response.data)[0]][0]
if (resource && resource.slug === slug) return // all good
if (resource && resource.slug !== slug) {
return redirect(`/${path}/${resource.id}/${resource.slug}`)
let response
let resource
response = await client.query({ query: queryId, variables })
resource = response.data[Object.keys(response.data)[0]][0]
if (resource && resource.slug === slug) return // all good
if (resource && resource.slug !== slug) {
return redirect(`/${path}/${resource.id}/${resource.slug}`)
}
response = await client.query({ query: querySlug, variables })
resource = response.data[Object.keys(response.data)[0]][0]
if (resource) return redirect(`/${path}/${resource.id}/${resource.slug}`)
}
response = await client.query({ query: querySlug, variables })
resource = response.data[Object.keys(response.data)[0]][0]
if (resource) return redirect(`/${path}/${resource.id}/${resource.slug}`)
return error({ statusCode: 404, key: message })
},
}