mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge branch '5059-epic-groups' of github.com:Ocelot-Social-Community/Ocelot-Social into 5344-add-group-members-management
# Conflicts: # backend/src/db/graphql/groups.js # backend/src/schema/resolvers/groups.js # webapp/components/Group/GroupCard.vue # webapp/components/Group/GroupForm.vue # webapp/components/Group/GroupTeaser.vue # webapp/graphql/groups.js # webapp/locales/de.json # webapp/locales/en.json # webapp/pages/group/edit/_id.vue
This commit is contained in:
commit
2aa85d7b05
@ -1,3 +1,3 @@
|
||||
// this file is duplicated in `backend/src/constants/group.js` and `webapp/constants/group.js`
|
||||
export const DESCRIPTION_WITHOUT_HTML_LENGTH_MIN = 100 // with removed HTML tags
|
||||
export const DESCRIPTION_EXCERPT_HTML_LENGTH = 120 // with removed HTML tags
|
||||
export const DESCRIPTION_EXCERPT_HTML_LENGTH = 250 // with removed HTML tags
|
||||
|
||||
@ -2,171 +2,202 @@ import gql from 'graphql-tag'
|
||||
|
||||
// ------ mutations
|
||||
|
||||
export const createGroupMutation = gql`
|
||||
mutation (
|
||||
$id: ID
|
||||
$name: String!
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String!
|
||||
$groupType: GroupType!
|
||||
$actionRadius: GroupActionRadius!
|
||||
$categoryIds: [ID]
|
||||
$locationName: String
|
||||
) {
|
||||
CreateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
groupType: $groupType
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
locationName: $locationName
|
||||
export const createGroupMutation = () => {
|
||||
return gql`
|
||||
mutation (
|
||||
$id: ID
|
||||
$name: String!
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String!
|
||||
$groupType: GroupType!
|
||||
$actionRadius: GroupActionRadius!
|
||||
$categoryIds: [ID]
|
||||
$locationName: String # empty string '' sets it to null
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
CreateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
groupType: $groupType
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
locationName: $locationName
|
||||
) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
}
|
||||
locationName
|
||||
location {
|
||||
name
|
||||
nameDE
|
||||
nameEN
|
||||
}
|
||||
myRole
|
||||
}
|
||||
# locationName # test this as result
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const updateGroupMutation = gql`
|
||||
mutation (
|
||||
$id: ID!
|
||||
$name: String
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String
|
||||
$actionRadius: GroupActionRadius
|
||||
$categoryIds: [ID]
|
||||
$avatar: ImageInput
|
||||
$locationName: String
|
||||
) {
|
||||
UpdateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
avatar: $avatar
|
||||
locationName: $locationName
|
||||
export const updateGroupMutation = () => {
|
||||
return gql`
|
||||
mutation (
|
||||
$id: ID!
|
||||
$name: String
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String
|
||||
$actionRadius: GroupActionRadius
|
||||
$categoryIds: [ID]
|
||||
$avatar: ImageInput
|
||||
$locationName: String # empty string '' sets it to null
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
UpdateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
avatar: $avatar
|
||||
locationName: $locationName
|
||||
) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
}
|
||||
# avatar # test this as result
|
||||
locationName
|
||||
location {
|
||||
name
|
||||
nameDE
|
||||
nameEN
|
||||
}
|
||||
myRole
|
||||
}
|
||||
# avatar # test this as result
|
||||
# locationName # test this as result
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const joinGroupMutation = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
JoinGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const joinGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
JoinGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const leaveGroupMutation = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
LeaveGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const leaveGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
LeaveGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const changeGroupMemberRoleMutation = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
|
||||
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const changeGroupMemberRoleMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
|
||||
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
// ------ queries
|
||||
|
||||
export const groupQuery = gql`
|
||||
query ($isMember: Boolean, $id: ID, $slug: String) {
|
||||
Group(isMember: $isMember, id: $id, slug: $slug) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
export const groupQuery = () => {
|
||||
return gql`
|
||||
query ($isMember: Boolean, $id: ID, $slug: String) {
|
||||
Group(isMember: $isMember, id: $id, slug: $slug) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
}
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
locationName
|
||||
location {
|
||||
name
|
||||
nameDE
|
||||
nameEN
|
||||
}
|
||||
myRole
|
||||
}
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
# locationName # test this as result
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const groupMembersQuery = gql`
|
||||
query ($id: ID!) {
|
||||
GroupMembers(id: $id) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const groupMembersQuery = () => {
|
||||
return gql`
|
||||
query ($id: ID!) {
|
||||
GroupMembers(id: $id) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
authenticatedUser = await peterLustig.toJson()
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
id: 'g0',
|
||||
name: 'Investigative Journalism',
|
||||
@ -313,27 +313,28 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
description: `<p class=""><em>English:</em></p><p class="">This group is hidden.</p><h3>What is our group for?</h3><p>This group was created to allow investigative journalists to share and collaborate.</p><h3>How does it work?</h3><p>Here you can internally share posts and comments about them.</p><p><br></p><p><em>Deutsch:</em></p><p class="">Diese Gruppe ist verborgen.</p><h3>Wofür ist unsere Gruppe?</h3><p class="">Diese Gruppe wurde geschaffen, um investigativen Journalisten den Austausch und die Zusammenarbeit zu ermöglichen.</p><h3>Wie funktioniert das?</h3><p class="">Hier könnt ihr euch intern über Beiträge und Kommentare zu ihnen austauschen.</p>`,
|
||||
groupType: 'hidden',
|
||||
actionRadius: 'global',
|
||||
categoryIds: ['cat6', 'cat9', 'cat14'],
|
||||
categoryIds: ['cat6', 'cat12', 'cat16'],
|
||||
locationName: 'Hamburg, Germany',
|
||||
},
|
||||
}),
|
||||
])
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g0',
|
||||
userId: 'u2',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g0',
|
||||
userId: 'u4',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g0',
|
||||
userId: 'u6',
|
||||
@ -342,7 +343,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
])
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g0',
|
||||
userId: 'u2',
|
||||
@ -350,7 +351,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g0',
|
||||
userId: 'u4',
|
||||
@ -362,7 +363,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
authenticatedUser = await jennyRostock.toJson()
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
id: 'g1',
|
||||
name: 'School For Citizens',
|
||||
@ -370,41 +371,42 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
description: `<p class=""><em>English</em></p><h3>Our goal</h3><p>Only those who enjoy learning and do not lose their curiosity can obtain a good education for life and continue to learn with joy throughout their lives.</p><h3>Curiosity</h3><p>For this we need a school that takes up the curiosity of the children, the people, and satisfies it through a lot of experience.</p><p><br></p><p><em>Deutsch</em></p><h3>Unser Ziel</h3><p class="">Nur wer Spaß am Lernen hat und seine Neugier nicht verliert, kann gute Bildung für's Leben erlangen und sein ganzes Leben mit Freude weiter lernen.</p><h3>Neugier</h3><p class="">Dazu benötigen wir eine Schule, die die Neugier der Kinder, der Menschen, aufnimmt und durch viel Erfahrung befriedigt.</p>`,
|
||||
groupType: 'closed',
|
||||
actionRadius: 'national',
|
||||
categoryIds: ['cat7', 'cat9', 'cat16'],
|
||||
categoryIds: ['cat8', 'cat14'],
|
||||
locationName: 'France',
|
||||
},
|
||||
}),
|
||||
])
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u1',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u2',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u5',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u6',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u7',
|
||||
@ -413,7 +415,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
])
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u1',
|
||||
@ -421,7 +423,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u5',
|
||||
@ -429,7 +431,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g1',
|
||||
userId: 'u6',
|
||||
@ -441,7 +443,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
authenticatedUser = await bobDerBaumeister.toJson()
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
id: 'g2',
|
||||
name: 'Yoga Practice',
|
||||
@ -449,41 +451,41 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
description: `<h3>What Is yoga?</h3><p>Yoga is not just about practicing asanas. It's about how we do it.</p><p class="">And practicing asanas doesn't have to be yoga, it can be more athletic than yogic.</p><h3>What makes practicing asanas yogic?</h3><p class="">The important thing is:</p><ul><li><p>Use the exercises (consciously) for your personal development.</p></li></ul>`,
|
||||
groupType: 'public',
|
||||
actionRadius: 'interplanetary',
|
||||
categoryIds: ['cat3', 'cat13', 'cat16'],
|
||||
categoryIds: ['cat4', 'cat5', 'cat17'],
|
||||
},
|
||||
}),
|
||||
])
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u3',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u4',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u5',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u6',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u7',
|
||||
@ -492,31 +494,31 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
])
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u3',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u4',
|
||||
roleInGroup: 'pending',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u4',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u5',
|
||||
roleInGroup: 'usual',
|
||||
roleInGroup: 'admin',
|
||||
},
|
||||
}),
|
||||
mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g2',
|
||||
userId: 'u6',
|
||||
|
||||
@ -82,7 +82,7 @@ const isAllowedToChangeGroupSettings = rule({
|
||||
}
|
||||
})
|
||||
|
||||
const isAllowedSeeingMembersOfGroup = rule({
|
||||
const isAllowedSeeingGroupMembers = rule({
|
||||
cache: 'no_cache',
|
||||
})(async (_parent, args, { user, driver }) => {
|
||||
if (!(user && user.id)) return false
|
||||
@ -284,7 +284,7 @@ export default shield(
|
||||
statistics: allow,
|
||||
currentUser: allow,
|
||||
Group: isAuthenticated,
|
||||
GroupMembers: isAllowedSeeingMembersOfGroup,
|
||||
GroupMembers: isAllowedSeeingGroupMembers,
|
||||
Post: allow,
|
||||
profilePagePosts: allow,
|
||||
Comment: allow,
|
||||
|
||||
@ -51,6 +51,7 @@ beforeEach(async () => {
|
||||
await Factory.build('category', {
|
||||
id: 'cat9',
|
||||
name: 'Democracy & Politics',
|
||||
slug: 'democracy-politics',
|
||||
icon: 'university',
|
||||
})
|
||||
authenticatedUser = await admin.toJson()
|
||||
@ -79,7 +80,7 @@ describe('slugifyMiddleware', () => {
|
||||
it('generates a slug based on name', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables,
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
@ -93,13 +94,14 @@ describe('slugifyMiddleware', () => {
|
||||
actionRadius: 'national',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('generates a slug based on given slug', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
slug: 'the-group',
|
||||
@ -111,6 +113,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'the-group',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -118,7 +121,7 @@ describe('slugifyMiddleware', () => {
|
||||
describe('if slug exists', () => {
|
||||
beforeEach(async () => {
|
||||
await mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
name: 'Pre-Existing Group',
|
||||
@ -131,7 +134,7 @@ describe('slugifyMiddleware', () => {
|
||||
it('chooses another slug', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
name: 'Pre-Existing Group',
|
||||
@ -144,6 +147,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'pre-existing-group-1',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
@ -152,7 +156,7 @@ describe('slugifyMiddleware', () => {
|
||||
try {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
name: 'Pre-Existing Group',
|
||||
@ -194,7 +198,7 @@ describe('slugifyMiddleware', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
createGroupResult = await mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
name: 'The Best Group',
|
||||
slug: 'the-best-group',
|
||||
@ -213,7 +217,7 @@ describe('slugifyMiddleware', () => {
|
||||
it('has the new slug', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateGroupMutation,
|
||||
mutation: updateGroupMutation(),
|
||||
variables: {
|
||||
id: createGroupResult.data.CreateGroup.id,
|
||||
name: 'My Best Group',
|
||||
@ -231,6 +235,7 @@ describe('slugifyMiddleware', () => {
|
||||
myRole: 'owner',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -239,7 +244,7 @@ describe('slugifyMiddleware', () => {
|
||||
it('has the new slug', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateGroupMutation,
|
||||
mutation: updateGroupMutation(),
|
||||
variables: {
|
||||
id: createGroupResult.data.CreateGroup.id,
|
||||
slug: 'my-best-group',
|
||||
@ -257,6 +262,7 @@ describe('slugifyMiddleware', () => {
|
||||
myRole: 'owner',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -265,7 +271,7 @@ describe('slugifyMiddleware', () => {
|
||||
describe('if new slug exists in another group', () => {
|
||||
beforeEach(async () => {
|
||||
await mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
name: 'Pre-Existing Group',
|
||||
slug: 'pre-existing-group',
|
||||
@ -282,7 +288,7 @@ describe('slugifyMiddleware', () => {
|
||||
it('has unique slug "*-1"', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateGroupMutation,
|
||||
mutation: updateGroupMutation(),
|
||||
variables: {
|
||||
id: createGroupResult.data.CreateGroup.id,
|
||||
name: 'Pre-Existing Group',
|
||||
@ -300,6 +306,7 @@ describe('slugifyMiddleware', () => {
|
||||
myRole: 'owner',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -309,7 +316,7 @@ describe('slugifyMiddleware', () => {
|
||||
try {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateGroupMutation,
|
||||
mutation: updateGroupMutation(),
|
||||
variables: {
|
||||
id: createGroupResult.data.CreateGroup.id,
|
||||
slug: 'pre-existing-group',
|
||||
@ -368,6 +375,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'i-am-a-brand-new-post',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
@ -386,6 +394,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'the-post',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -422,6 +431,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'pre-existing-post-1',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
@ -504,6 +514,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'i-am-a-user',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
@ -522,6 +533,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'the-user',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -546,6 +558,7 @@ describe('slugifyMiddleware', () => {
|
||||
slug: 'i-am-a-user-1',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ export default makeAugmentedSchema({
|
||||
'FILED',
|
||||
'REVIEWED',
|
||||
'Report',
|
||||
'Group',
|
||||
],
|
||||
},
|
||||
mutation: false,
|
||||
|
||||
@ -9,7 +9,7 @@ import Resolver, {
|
||||
convertObjectToCypherMapLiteral,
|
||||
} from './helpers/Resolver'
|
||||
import { mergeImage } from './images/images'
|
||||
import createOrUpdateLocations from './users/location'
|
||||
import { createOrUpdateLocations } from './users/location'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
@ -86,6 +86,7 @@ export default {
|
||||
CreateGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
const { categoryIds } = params
|
||||
delete params.categoryIds
|
||||
params.locationName = params.locationName === '' ? null : params.locationName
|
||||
if (CONFIG.CATEGORIES_ACTIVE && (!categoryIds || categoryIds.length < CATEGORIES_MIN)) {
|
||||
throw new UserInputError('Too view categories!')
|
||||
}
|
||||
@ -137,7 +138,8 @@ export default {
|
||||
})
|
||||
try {
|
||||
const group = await writeTxResultPromise
|
||||
await createOrUpdateLocations(params.id, params.locationName, session)
|
||||
// TODO: put in a middleware, see "UpdateGroup", "UpdateUser"
|
||||
await createOrUpdateLocations('Group', params.id, params.locationName, session)
|
||||
return group
|
||||
} catch (error) {
|
||||
if (error.code === 'Neo.ClientError.Schema.ConstraintValidationFailed')
|
||||
@ -149,9 +151,11 @@ export default {
|
||||
},
|
||||
UpdateGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
const { categoryIds } = params
|
||||
const { id: groupId, avatar: avatarInput } = params
|
||||
delete params.categoryIds
|
||||
const { id: groupId, avatar: avatarInput } = params
|
||||
delete params.avatar
|
||||
params.locationName = params.locationName === '' ? null : params.locationName
|
||||
|
||||
if (CONFIG.CATEGORIES_ACTIVE && categoryIds) {
|
||||
if (categoryIds.length < CATEGORIES_MIN) {
|
||||
throw new UserInputError('Too view categories!')
|
||||
@ -210,7 +214,8 @@ export default {
|
||||
})
|
||||
try {
|
||||
const group = await writeTxResultPromise
|
||||
await createOrUpdateLocations(params.id, params.locationName, session)
|
||||
// TODO: put in a middleware, see "CreateGroup", "UpdateUser"
|
||||
await createOrUpdateLocations('Group', params.id, params.locationName, session)
|
||||
return group
|
||||
} catch (error) {
|
||||
if (error.code === 'Neo.ClientError.Schema.ConstraintValidationFailed')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ import { UserInputError, ForbiddenError } from 'apollo-server'
|
||||
import { mergeImage, deleteImage } from './images/images'
|
||||
import Resolver from './helpers/Resolver'
|
||||
import log from './helpers/databaseLogger'
|
||||
import createOrUpdateLocations from './users/location'
|
||||
import { createOrUpdateLocations } from './users/location'
|
||||
|
||||
const neode = getNeode()
|
||||
|
||||
@ -139,9 +139,10 @@ export default {
|
||||
return blockedUser.toJson()
|
||||
},
|
||||
UpdateUser: async (_parent, params, context, _resolveInfo) => {
|
||||
const { termsAndConditionsAgreedVersion } = params
|
||||
const { avatar: avatarInput } = params
|
||||
delete params.avatar
|
||||
params.locationName = params.locationName === '' ? null : params.locationName
|
||||
const { termsAndConditionsAgreedVersion } = params
|
||||
if (termsAndConditionsAgreedVersion) {
|
||||
const regEx = new RegExp(/^[0-9]+\.[0-9]+\.[0-9]+$/g)
|
||||
if (!regEx.test(termsAndConditionsAgreedVersion)) {
|
||||
@ -169,7 +170,8 @@ export default {
|
||||
})
|
||||
try {
|
||||
const user = await writeTxResultPromise
|
||||
await createOrUpdateLocations(params.id, params.locationName, session)
|
||||
// TODO: put in a middleware, see "CreateGroup", "UpdateGroup"
|
||||
await createOrUpdateLocations('User', params.id, params.locationName, session)
|
||||
return user
|
||||
} catch (error) {
|
||||
throw new UserInputError(error.message)
|
||||
|
||||
@ -161,7 +161,7 @@ describe('UpdateUser', () => {
|
||||
$id: ID!
|
||||
$name: String
|
||||
$termsAndConditionsAgreedVersion: String
|
||||
$locationName: String
|
||||
$locationName: String # empty string '' sets it to null
|
||||
) {
|
||||
UpdateUser(
|
||||
id: $id
|
||||
@ -174,6 +174,11 @@ describe('UpdateUser', () => {
|
||||
termsAndConditionsAgreedVersion
|
||||
termsAndConditionsAgreedAt
|
||||
locationName
|
||||
location {
|
||||
name
|
||||
nameDE
|
||||
nameEN
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -289,11 +294,39 @@ describe('UpdateUser', () => {
|
||||
expect(errors[0]).toHaveProperty('message', 'Invalid version format!')
|
||||
})
|
||||
|
||||
it('supports updating location', async () => {
|
||||
variables = { ...variables, locationName: 'Hamburg, New Jersey, United States' }
|
||||
await expect(mutate({ mutation: updateUserMutation, variables })).resolves.toMatchObject({
|
||||
data: { UpdateUser: { locationName: 'Hamburg, New Jersey, United States' } },
|
||||
errors: undefined,
|
||||
describe('supports updating location', () => {
|
||||
describe('change location to "Hamburg, New Jersey, United States"', () => {
|
||||
it('has updated location to "Hamburg, New Jersey, United States"', async () => {
|
||||
variables = { ...variables, locationName: 'Hamburg, New Jersey, United States' }
|
||||
await expect(mutate({ mutation: updateUserMutation, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
UpdateUser: {
|
||||
locationName: 'Hamburg, New Jersey, United States',
|
||||
location: expect.objectContaining({
|
||||
name: 'Hamburg',
|
||||
nameDE: 'Hamburg',
|
||||
nameEN: 'Hamburg',
|
||||
}),
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('change location to unset location', () => {
|
||||
it('has updated location to unset location', async () => {
|
||||
variables = { ...variables, locationName: '' }
|
||||
await expect(mutate({ mutation: updateUserMutation, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
UpdateUser: {
|
||||
locationName: null,
|
||||
location: null,
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import request from 'request'
|
||||
import { UserInputError } from 'apollo-server'
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
import Debug from 'debug'
|
||||
import asyncForEach from '../../../helpers/asyncForEach'
|
||||
import CONFIG from '../../../config'
|
||||
@ -62,77 +61,86 @@ const createLocation = async (session, mapboxData) => {
|
||||
})
|
||||
}
|
||||
|
||||
const createOrUpdateLocations = async (userId, locationName, session) => {
|
||||
if (isEmpty(locationName)) {
|
||||
return
|
||||
}
|
||||
const res = await fetch(
|
||||
`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(
|
||||
locationName,
|
||||
)}.json?access_token=${CONFIG.MAPBOX_TOKEN}&types=region,place,country&language=${locales.join(
|
||||
',',
|
||||
)}`,
|
||||
)
|
||||
export const createOrUpdateLocations = async (nodeLabel, nodeId, locationName, session) => {
|
||||
if (locationName === undefined) return
|
||||
|
||||
debug(res)
|
||||
let locationId
|
||||
|
||||
if (!res || !res.features || !res.features[0]) {
|
||||
throw new UserInputError('locationName is invalid')
|
||||
}
|
||||
if (locationName !== null) {
|
||||
const res = await fetch(
|
||||
`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(
|
||||
locationName,
|
||||
)}.json?access_token=${
|
||||
CONFIG.MAPBOX_TOKEN
|
||||
}&types=region,place,country&language=${locales.join(',')}`,
|
||||
)
|
||||
|
||||
let data
|
||||
debug(res)
|
||||
|
||||
res.features.forEach((item) => {
|
||||
if (item.matching_place_name === locationName) {
|
||||
data = item
|
||||
if (!res || !res.features || !res.features[0]) {
|
||||
throw new UserInputError('locationName is invalid')
|
||||
}
|
||||
})
|
||||
if (!data) {
|
||||
data = res.features[0]
|
||||
}
|
||||
|
||||
if (!data || !data.place_type || !data.place_type.length) {
|
||||
throw new UserInputError('locationName is invalid')
|
||||
}
|
||||
let data
|
||||
|
||||
if (data.place_type.length > 1) {
|
||||
data.id = 'region.' + data.id.split('.')[1]
|
||||
}
|
||||
await createLocation(session, data)
|
||||
|
||||
let parent = data
|
||||
|
||||
if (data.context) {
|
||||
await asyncForEach(data.context, async (ctx) => {
|
||||
await createLocation(session, ctx)
|
||||
await session.writeTransaction((transaction) => {
|
||||
return transaction.run(
|
||||
`
|
||||
MATCH (parent:Location {id: $parentId}), (child:Location {id: $childId})
|
||||
MERGE (child)<-[:IS_IN]-(parent)
|
||||
RETURN child.id, parent.id
|
||||
`,
|
||||
{
|
||||
parentId: parent.id,
|
||||
childId: ctx.id,
|
||||
},
|
||||
)
|
||||
})
|
||||
parent = ctx
|
||||
res.features.forEach((item) => {
|
||||
if (item.matching_place_name === locationName) {
|
||||
data = item
|
||||
}
|
||||
})
|
||||
if (!data) {
|
||||
data = res.features[0]
|
||||
}
|
||||
|
||||
if (!data || !data.place_type || !data.place_type.length) {
|
||||
throw new UserInputError('locationName is invalid')
|
||||
}
|
||||
|
||||
if (data.place_type.length > 1) {
|
||||
data.id = 'region.' + data.id.split('.')[1]
|
||||
}
|
||||
await createLocation(session, data)
|
||||
|
||||
let parent = data
|
||||
|
||||
if (data.context) {
|
||||
await asyncForEach(data.context, async (ctx) => {
|
||||
await createLocation(session, ctx)
|
||||
await session.writeTransaction((transaction) => {
|
||||
return transaction.run(
|
||||
`
|
||||
MATCH (parent:Location {id: $parentId}), (child:Location {id: $childId})
|
||||
MERGE (child)<-[:IS_IN]-(parent)
|
||||
RETURN child.id, parent.id
|
||||
`,
|
||||
{
|
||||
parentId: parent.id,
|
||||
childId: ctx.id,
|
||||
},
|
||||
)
|
||||
})
|
||||
parent = ctx
|
||||
})
|
||||
}
|
||||
|
||||
locationId = data.id
|
||||
} else {
|
||||
locationId = 'non-existent-id'
|
||||
}
|
||||
// delete all current locations from user and add new location
|
||||
|
||||
// delete all current locations from node and add new location
|
||||
await session.writeTransaction((transaction) => {
|
||||
return transaction.run(
|
||||
`
|
||||
MATCH (user:User {id: $userId})-[relationship:IS_IN]->(location:Location)
|
||||
DETACH DELETE relationship
|
||||
WITH user
|
||||
MATCH (location:Location {id: $locationId})
|
||||
MERGE (user)-[:IS_IN]->(location)
|
||||
RETURN location.id, user.id
|
||||
`,
|
||||
{ userId: userId, locationId: data.id },
|
||||
MATCH (node:${nodeLabel} {id: $nodeId})
|
||||
OPTIONAL MATCH (node)-[relationship:IS_IN]->(:Location)
|
||||
DELETE relationship
|
||||
WITH node
|
||||
MATCH (location:Location {id: $locationId})
|
||||
MERGE (node)-[:IS_IN]->(location)
|
||||
RETURN location.id, node.id
|
||||
`,
|
||||
{ nodeId, locationId },
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -147,5 +155,3 @@ export const queryLocations = async ({ place, lang }) => {
|
||||
}
|
||||
return res.features
|
||||
}
|
||||
|
||||
export default createOrUpdateLocations
|
||||
|
||||
@ -33,8 +33,8 @@ type Group {
|
||||
groupType: GroupType!
|
||||
actionRadius: GroupActionRadius!
|
||||
|
||||
location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
||||
locationName: String
|
||||
location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
||||
|
||||
categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT")
|
||||
|
||||
@ -95,7 +95,7 @@ type Mutation {
|
||||
actionRadius: GroupActionRadius!
|
||||
categoryIds: [ID]
|
||||
# avatar: ImageInput # a group can not be created with an avatar
|
||||
locationName: String # test this as result
|
||||
locationName: String # empty string '' sets it to null
|
||||
): Group
|
||||
|
||||
UpdateGroup(
|
||||
@ -108,7 +108,7 @@ type Mutation {
|
||||
actionRadius: GroupActionRadius
|
||||
categoryIds: [ID]
|
||||
avatar: ImageInput # test this as result
|
||||
locationName: String # test this as result
|
||||
locationName: String # empty string '' sets it to null
|
||||
): Group
|
||||
|
||||
# DeleteGroup(id: ID!): Group
|
||||
|
||||
@ -33,8 +33,8 @@ type User {
|
||||
invitedBy: User @relation(name: "INVITED", direction: "IN")
|
||||
invited: [User] @relation(name: "INVITED", direction: "OUT")
|
||||
|
||||
location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
||||
locationName: String
|
||||
location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
||||
about: String
|
||||
socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN")
|
||||
|
||||
@ -212,7 +212,7 @@ type Mutation {
|
||||
email: String
|
||||
slug: String
|
||||
avatar: ImageInput
|
||||
locationName: String
|
||||
locationName: String # empty string '' sets it to null
|
||||
about: String
|
||||
termsAndConditionsAgreedVersion: String
|
||||
termsAndConditionsAgreedAt: String
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<base-button
|
||||
class="track-button"
|
||||
class="join-leave-button"
|
||||
:disabled="disabled"
|
||||
:loading="localLoading"
|
||||
:icon="icon"
|
||||
@ -108,7 +108,7 @@ export default {
|
||||
},
|
||||
async joinLeave() {
|
||||
const join = !this.isMember
|
||||
const mutation = join ? joinGroupMutation : leaveGroupMutation
|
||||
const mutation = join ? joinGroupMutation() : leaveGroupMutation()
|
||||
|
||||
this.hovered = false
|
||||
this.$emit('prepare', join)
|
||||
@ -129,7 +129,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.track-button {
|
||||
.join-leave-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@
|
||||
v-tooltip="{
|
||||
content: $t(`contribution.category.description.${category.slug}`),
|
||||
placement: 'bottom-start',
|
||||
delay: { show: 1500 },
|
||||
}"
|
||||
>
|
||||
{{ $t(`contribution.category.name.${category.slug}`) }}
|
||||
|
||||
@ -20,7 +20,6 @@
|
||||
v-tooltip="{
|
||||
content: $t(`contribution.category.description.${category.slug}`),
|
||||
placement: 'bottom-start',
|
||||
delay: { show: 1500 },
|
||||
}"
|
||||
/>
|
||||
</li>
|
||||
|
||||
@ -76,7 +76,7 @@ export default {
|
||||
const variables = { groupId: id, userId: this.$store.getters['auth/user'].id }
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: joinGroupMutation,
|
||||
mutation: joinGroupMutation(),
|
||||
variables,
|
||||
})
|
||||
this.$toast.success(this.$t('group.groupCreated'))
|
||||
|
||||
@ -71,7 +71,7 @@ export default {
|
||||
const newRole = event.target.value
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: changeGroupMemberRoleMutation,
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: { groupId: this.groupId, userId: id, roleInGroup: newRole },
|
||||
})
|
||||
this.$toast.success(this.$t('group.changeMemberRole', { role: newRole }))
|
||||
|
||||
@ -31,9 +31,8 @@
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"
|
||||
v-tooltip="{
|
||||
content: $t(`contribution.category.name.${category.slug}`),
|
||||
content: $t(`contribution.category.description.${category.slug}`),
|
||||
placement: 'bottom-start',
|
||||
delay: { show: 1500 },
|
||||
}"
|
||||
:icon="category.icon"
|
||||
/>
|
||||
|
||||
@ -29,6 +29,7 @@ describe('AvatarUploader', () => {
|
||||
profile: {
|
||||
avatar: { url: '/api/generic.jpg' },
|
||||
},
|
||||
updateMutation: jest.fn(),
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
@ -40,7 +41,7 @@ describe('AvatarUploader', () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it('sends a the UpdateUser mutation when vddrop is called', () => {
|
||||
it('sends the UpdateUser mutation when vddrop is called', () => {
|
||||
wrapper.vm.vddrop([{ filename: 'avatar.jpg' }])
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="avatar-uploader">
|
||||
<vue-dropzone
|
||||
id="customdropzone"
|
||||
:key="avatarUrl"
|
||||
@ -29,7 +29,7 @@ export default {
|
||||
},
|
||||
props: {
|
||||
profile: { type: Object, required: true },
|
||||
updateMutation: { type: Object, required: true },
|
||||
updateMutation: { type: Function, required: true },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -69,7 +69,7 @@ export default {
|
||||
const avatarUpload = file[0]
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: this.updateMutation,
|
||||
mutation: this.updateMutation(),
|
||||
variables: {
|
||||
avatar: {
|
||||
upload: avatarUpload,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<button
|
||||
:class="buttonClass"
|
||||
:disabled="loading"
|
||||
:disabled="disabled || loading"
|
||||
:type="type"
|
||||
@click.capture="(event) => $emit('click', event)"
|
||||
>
|
||||
@ -56,6 +56,10 @@ export default {
|
||||
return value.match(/(button|submit)/)
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
// type: Boolean, // makes some errors that an Object was passed instead a Boolean and could not find how to solve in a acceptable time
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
buttonClass() {
|
||||
|
||||
@ -12,6 +12,7 @@ export const userFragment = gql`
|
||||
deleted
|
||||
}
|
||||
`
|
||||
|
||||
export const locationAndBadgesFragment = (lang) => gql`
|
||||
fragment locationAndBadges on User {
|
||||
location {
|
||||
|
||||
@ -221,25 +221,25 @@ export const updateUserMutation = () => {
|
||||
$id: ID!
|
||||
$slug: String
|
||||
$name: String
|
||||
$locationName: String
|
||||
$about: String
|
||||
$allowEmbedIframes: Boolean
|
||||
$showShoutsPublicly: Boolean
|
||||
$sendNotificationEmails: Boolean
|
||||
$termsAndConditionsAgreedVersion: String
|
||||
$avatar: ImageInput
|
||||
$locationName: String # empty string '' sets it to null
|
||||
) {
|
||||
UpdateUser(
|
||||
id: $id
|
||||
slug: $slug
|
||||
name: $name
|
||||
locationName: $locationName
|
||||
about: $about
|
||||
allowEmbedIframes: $allowEmbedIframes
|
||||
showShoutsPublicly: $showShoutsPublicly
|
||||
sendNotificationEmails: $sendNotificationEmails
|
||||
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
|
||||
avatar: $avatar
|
||||
locationName: $locationName
|
||||
) {
|
||||
id
|
||||
slug
|
||||
|
||||
@ -2,171 +2,191 @@ import gql from 'graphql-tag'
|
||||
|
||||
// ------ mutations
|
||||
|
||||
export const createGroupMutation = gql`
|
||||
mutation (
|
||||
$id: ID
|
||||
$name: String!
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String!
|
||||
$groupType: GroupType!
|
||||
$actionRadius: GroupActionRadius!
|
||||
$categoryIds: [ID]
|
||||
$locationName: String
|
||||
) {
|
||||
CreateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
groupType: $groupType
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
locationName: $locationName
|
||||
export const createGroupMutation = () => {
|
||||
return gql`
|
||||
mutation (
|
||||
$id: ID
|
||||
$name: String!
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String!
|
||||
$groupType: GroupType!
|
||||
$actionRadius: GroupActionRadius!
|
||||
$categoryIds: [ID]
|
||||
$locationName: String # empty string '' sets it to null
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
CreateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
groupType: $groupType
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
locationName: $locationName
|
||||
) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
}
|
||||
locationName
|
||||
myRole
|
||||
}
|
||||
locationName # test this as result
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const updateGroupMutation = gql`
|
||||
mutation (
|
||||
$id: ID!
|
||||
$name: String
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String
|
||||
$actionRadius: GroupActionRadius
|
||||
$categoryIds: [ID]
|
||||
$avatar: ImageInput
|
||||
$locationName: String
|
||||
) {
|
||||
UpdateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
avatar: $avatar
|
||||
locationName: $locationName
|
||||
export const updateGroupMutation = () => {
|
||||
return gql`
|
||||
mutation (
|
||||
$id: ID!
|
||||
$name: String
|
||||
$slug: String
|
||||
$about: String
|
||||
$description: String
|
||||
$actionRadius: GroupActionRadius
|
||||
$categoryIds: [ID]
|
||||
$avatar: ImageInput
|
||||
$locationName: String # empty string '' sets it to null
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
UpdateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
slug: $slug
|
||||
about: $about
|
||||
description: $description
|
||||
actionRadius: $actionRadius
|
||||
categoryIds: $categoryIds
|
||||
avatar: $avatar
|
||||
locationName: $locationName
|
||||
) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
}
|
||||
# avatar # test this as result
|
||||
locationName
|
||||
myRole
|
||||
}
|
||||
# avatar # test this as result
|
||||
# locationName # test this as result
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const joinGroupMutation = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
JoinGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const joinGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
JoinGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const leaveGroupMutation = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
LeaveGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const leaveGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
LeaveGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const changeGroupMemberRoleMutation = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
|
||||
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const changeGroupMemberRoleMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
|
||||
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
// ------ queries
|
||||
|
||||
export const groupQuery = gql`
|
||||
query ($isMember: Boolean, $id: ID, $slug: String) {
|
||||
Group(isMember: $isMember, id: $id, slug: $slug) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
export const groupQuery = (i18n) => {
|
||||
const lang = i18n ? i18n.locale().toUpperCase() : 'EN'
|
||||
return gql`
|
||||
query ($isMember: Boolean, $id: ID, $slug: String) {
|
||||
Group(isMember: $isMember, id: $id, slug: $slug) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
slug
|
||||
createdAt
|
||||
updatedAt
|
||||
disabled
|
||||
deleted
|
||||
about
|
||||
description
|
||||
descriptionExcerpt
|
||||
groupType
|
||||
actionRadius
|
||||
categories {
|
||||
id
|
||||
slug
|
||||
name
|
||||
icon
|
||||
}
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
locationName
|
||||
location {
|
||||
name: name${lang}
|
||||
}
|
||||
myRole
|
||||
}
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
locationName # test this as result
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
export const groupMembersQuery = gql`
|
||||
query ($id: ID!) {
|
||||
GroupMembers(id: $id) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
export const groupMembersQuery = () => {
|
||||
return gql`
|
||||
query ($id: ID!) {
|
||||
GroupMembers(id: $id) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
}
|
||||
|
||||
@ -405,6 +405,7 @@
|
||||
},
|
||||
"actionRadius": "Aktionsradius",
|
||||
"back": "zurück",
|
||||
"categories": "Thema ::: Themen",
|
||||
"change-member-role": "Die Rolle wurde auf „{role}“ geändert!",
|
||||
"follow": "Folge",
|
||||
"foundation": "Gründung",
|
||||
@ -424,8 +425,9 @@
|
||||
},
|
||||
"long-description": "Beschreibung",
|
||||
"members": "Mitglieder",
|
||||
"membersCount": "Mitglieder",
|
||||
"membersCount": "Mitglied ::: Mitglieder",
|
||||
"membersListTitle": "Gruppenmitglieder",
|
||||
"membersListTitleNotAllowedSeeingGroupMembers": "Gruppenmitglieder unsichtbar",
|
||||
"myGroups": "Meine Gruppen",
|
||||
"newGroup": "Erstelle eine neue Gruppe",
|
||||
"radius": "Radius",
|
||||
|
||||
@ -405,6 +405,7 @@
|
||||
},
|
||||
"actionRadius": "Action radius",
|
||||
"back": "back",
|
||||
"categories": "Topic ::: Topics",
|
||||
"change-member-role": "The role has been changed to “{role}”!",
|
||||
"follow": "Follow",
|
||||
"foundation": "Foundation",
|
||||
@ -424,8 +425,9 @@
|
||||
},
|
||||
"long-description": "Description",
|
||||
"members": "Members",
|
||||
"membersCount": "Members",
|
||||
"membersCount": "Member ::: Members",
|
||||
"membersListTitle": "Group Members",
|
||||
"membersListTitleNotAllowedSeeingGroupMembers": "Group Members invisible",
|
||||
"myGroups": "My Groups",
|
||||
"newGroup": "Create a new Group",
|
||||
"radius": "Radius",
|
||||
|
||||
@ -1,95 +0,0 @@
|
||||
// import { config, mount } from '@vue/test-utils'
|
||||
// import ProfileSlug from './_slug.vue'
|
||||
|
||||
// const localVue = global.localVue
|
||||
|
||||
// localVue.filter('date', (d) => d)
|
||||
|
||||
// config.stubs['client-only'] = '<span><slot /></span>'
|
||||
// config.stubs['v-popover'] = '<span><slot /></span>'
|
||||
// config.stubs['nuxt-link'] = '<span><slot /></span>'
|
||||
// config.stubs['infinite-loading'] = '<span><slot /></span>'
|
||||
// config.stubs['follow-list'] = '<span><slot /></span>'
|
||||
|
||||
// describe('ProfileSlug', () => {
|
||||
// let wrapper
|
||||
// let Wrapper
|
||||
// let mocks
|
||||
|
||||
// beforeEach(() => {
|
||||
// mocks = {
|
||||
// post: {
|
||||
// id: 'p23',
|
||||
// name: 'It is a post',
|
||||
// },
|
||||
// $t: jest.fn(),
|
||||
// // If you're mocking router, then don't use VueRouter with localVue: https://vue-test-utils.vuejs.org/guides/using-with-vue-router.html
|
||||
// $route: {
|
||||
// params: {
|
||||
// id: '4711',
|
||||
// slug: 'john-doe',
|
||||
// },
|
||||
// },
|
||||
// $router: {
|
||||
// history: {
|
||||
// push: jest.fn(),
|
||||
// },
|
||||
// },
|
||||
// $toast: {
|
||||
// success: jest.fn(),
|
||||
// error: jest.fn(),
|
||||
// },
|
||||
// $apollo: {
|
||||
// loading: false,
|
||||
// mutate: jest.fn().mockResolvedValue(),
|
||||
// },
|
||||
// }
|
||||
// })
|
||||
|
||||
// describe('mount', () => {
|
||||
// Wrapper = () => {
|
||||
// return mount(ProfileSlug, {
|
||||
// mocks,
|
||||
// localVue,
|
||||
// })
|
||||
// }
|
||||
|
||||
// describe('given an authenticated user', () => {
|
||||
// beforeEach(() => {
|
||||
// mocks.$filters = {
|
||||
// removeLinks: (c) => c,
|
||||
// truncate: (a) => a,
|
||||
// }
|
||||
// mocks.$store = {
|
||||
// getters: {
|
||||
// 'auth/isModerator': () => false,
|
||||
// 'auth/user': {
|
||||
// id: 'u23',
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
// })
|
||||
|
||||
// describe('given a user for the profile', () => {
|
||||
// beforeEach(() => {
|
||||
// wrapper = Wrapper()
|
||||
// wrapper.setData({
|
||||
// User: [
|
||||
// {
|
||||
// id: 'u3',
|
||||
// name: 'Bob the builder',
|
||||
// contributionsCount: 6,
|
||||
// shoutedCount: 7,
|
||||
// commentedCount: 8,
|
||||
// },
|
||||
// ],
|
||||
// })
|
||||
// })
|
||||
|
||||
// it('displays name of the user', () => {
|
||||
// expect(wrapper.text()).toContain('Bob the builder')
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
1562
webapp/pages/group/_id/_slug.spec.js
Normal file
1562
webapp/pages/group/_id/_slug.spec.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="isGroupVisible">
|
||||
<ds-space />
|
||||
<ds-flex v-if="group" :width="{ base: '100%' }" gutter="base">
|
||||
<ds-flex-item :width="{ base: '100%', sm: 2, md: 2, lg: 1 }">
|
||||
@ -31,24 +31,29 @@
|
||||
/>
|
||||
</client-only> -->
|
||||
<ds-space margin="small">
|
||||
<!-- Group name -->
|
||||
<ds-heading tag="h3" align="center" no-margin>
|
||||
{{ groupName }}
|
||||
</ds-heading>
|
||||
<!-- Group slug -->
|
||||
<ds-text align="center" color="soft">
|
||||
{{ groupSlug }}
|
||||
</ds-text>
|
||||
<!-- <ds-text v-if="user.location" align="center" color="soft" size="small">
|
||||
<base-icon name="map-marker" />
|
||||
{{ user.location.name }}
|
||||
</ds-text> -->
|
||||
<!-- Group location -->
|
||||
<ds-text v-if="group && group.location" align="center" color="soft" size="small">
|
||||
<base-icon name="map-marker" data-test="map-marker" />
|
||||
{{ group && group.location ? group.location.name : '' }}
|
||||
</ds-text>
|
||||
<!-- Group created at -->
|
||||
<ds-text align="center" color="soft" size="small">
|
||||
{{ $t('group.foundation') }} {{ group.createdAt | date('MMMM yyyy') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<ds-flex>
|
||||
<ds-flex-item>
|
||||
<ds-flex v-if="isAllowedSeeingGroupMembers">
|
||||
<!-- Group members count -->
|
||||
<ds-flex-item v-if="isAllowedSeeingGroupMembers">
|
||||
<client-only>
|
||||
<ds-number :label="$t('group.membersCount')">
|
||||
<ds-number :label="$t('group.membersCount', {}, groupMembers.length)">
|
||||
<count-to
|
||||
slot="count"
|
||||
:start-val="membersCountStartValue"
|
||||
@ -90,6 +95,7 @@
|
||||
@optimistic="optimisticFollow"
|
||||
@update="updateFollow"
|
||||
/> -->
|
||||
<!-- Group join / leave -->
|
||||
<join-leave-button
|
||||
:group="group || {}"
|
||||
:userId="currentUser.id"
|
||||
@ -104,35 +110,82 @@
|
||||
</div>
|
||||
<hr />
|
||||
<ds-space margin-top="small" margin-bottom="small">
|
||||
<!-- Group my role in group -->
|
||||
<template v-if="isGroupMember">
|
||||
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
|
||||
{{ $t('group.role') }}
|
||||
</ds-text>
|
||||
<div class="chip" align="center">
|
||||
<ds-chip color="primary">{{ $t('group.roles.' + group.myRole) }}</ds-chip>
|
||||
<ds-chip color="primary">
|
||||
{{ group && group.myRole ? $t('group.roles.' + group.myRole) : '' }}
|
||||
</ds-chip>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Group type -->
|
||||
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
|
||||
{{ $t('group.type') }}
|
||||
</ds-text>
|
||||
<div class="chip" align="center">
|
||||
<ds-chip color="primary">{{ $t('group.types.' + group.groupType) }}</ds-chip>
|
||||
<ds-chip color="primary">
|
||||
{{ group && group.groupType ? $t('group.types.' + group.groupType) : '' }}
|
||||
</ds-chip>
|
||||
</div>
|
||||
<!-- Group action radius -->
|
||||
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
|
||||
{{ $t('group.actionRadius') }}
|
||||
</ds-text>
|
||||
<div class="chip" align="center">
|
||||
<ds-chip color="primary">{{ $t('group.actionRadii.' + group.actionRadius) }}</ds-chip>
|
||||
<ds-chip color="primary">
|
||||
{{
|
||||
group && group.actionRadius ? $t('group.actionRadii.' + group.actionRadius) : ''
|
||||
}}
|
||||
</ds-chip>
|
||||
</div>
|
||||
<ds-space margin="x-small" />
|
||||
</ds-space>
|
||||
<template v-if="group.about">
|
||||
<!-- Group categories -->
|
||||
<template v-if="categoriesActive">
|
||||
<hr />
|
||||
<ds-space margin-top="small" margin-bottom="small">
|
||||
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
|
||||
{{
|
||||
$t(
|
||||
'group.categories',
|
||||
{},
|
||||
group && group.categories ? group.categories.length : 0,
|
||||
)
|
||||
}}
|
||||
</ds-text>
|
||||
<ds-space margin="xx-small" />
|
||||
<div class="categories">
|
||||
<div
|
||||
v-for="(category, index) in group.categories"
|
||||
:key="category.id"
|
||||
align="center"
|
||||
>
|
||||
<category
|
||||
:icon="category.icon"
|
||||
:name="$t(`contribution.category.name.${category.slug}`)"
|
||||
v-tooltip="{
|
||||
content: $t(`contribution.category.description.${category.slug}`),
|
||||
placement: 'bottom-start',
|
||||
}"
|
||||
/>
|
||||
<ds-space v-if="index < group.categories.length - 1" margin="xxx-small" />
|
||||
</div>
|
||||
</div>
|
||||
</ds-space>
|
||||
</template>
|
||||
<!-- Group goal -->
|
||||
<template v-if="group && group.about">
|
||||
<hr />
|
||||
<ds-space margin-top="small" margin-bottom="small">
|
||||
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
|
||||
{{ $t('group.goal') }}
|
||||
</ds-text>
|
||||
<ds-space margin="xx-small" />
|
||||
<div class="chip" align="center">
|
||||
<ds-chip>{{ group.about }}</ds-chip>
|
||||
<ds-chip>{{ group ? group.about : '' }}</ds-chip>
|
||||
</div>
|
||||
</ds-space>
|
||||
</template>
|
||||
@ -143,10 +196,15 @@
|
||||
</ds-heading>
|
||||
<!-- Group members list -->
|
||||
<profile-list
|
||||
:uniqueName="`groupMembersFilter`"
|
||||
:uniqueName="'groupMembersFilter'"
|
||||
:title="$t('group.membersListTitle')"
|
||||
:allProfilesCount="groupMembers.length"
|
||||
:profiles="groupMembers"
|
||||
:titleNobody="
|
||||
!isAllowedSeeingGroupMembers
|
||||
? $t('group.membersListTitleNotAllowedSeeingGroupMembers')
|
||||
: null
|
||||
"
|
||||
:allProfilesCount="isAllowedSeeingGroupMembers ? groupMembers.length : 0"
|
||||
:profiles="isAllowedSeeingGroupMembers ? groupMembers : []"
|
||||
:loading="$apollo.loading"
|
||||
@fetchAllProfiles="fetchAllMembers"
|
||||
/>
|
||||
@ -168,31 +226,48 @@
|
||||
</ds-flex-item>
|
||||
|
||||
<ds-flex-item :width="{ base: '100%', sm: 3, md: 5, lg: 3 }">
|
||||
<!-- Group description -->
|
||||
<ds-space>
|
||||
<base-card class="group-description">
|
||||
<!-- TODO: replace editor content with tiptap render view -->
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div
|
||||
v-if="isDescriptionCollapsed"
|
||||
class="content hyphenate-text"
|
||||
v-html="groupDescriptionExcerpt"
|
||||
/>
|
||||
<content-viewer v-else class="content hyphenate-text" :content="group.description" />
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
<base-button
|
||||
class="collaps-button"
|
||||
size="small"
|
||||
ghost
|
||||
@click="isDescriptionCollapsed = !isDescriptionCollapsed"
|
||||
>
|
||||
{{ isDescriptionCollapsed ? $t('comment.show.more') : $t('comment.show.less') }}
|
||||
</base-button>
|
||||
</base-card>
|
||||
</ds-space>
|
||||
<ds-space v-if="isGroupMemberNonePending" centered>
|
||||
<nuxt-link :to="{ name: 'post-create' }">
|
||||
<base-button
|
||||
class="profile-post-add-button"
|
||||
:path="{ name: 'post-create' }"
|
||||
icon="plus"
|
||||
circle
|
||||
filled
|
||||
v-tooltip="{
|
||||
content: $t('contribution.newPost'),
|
||||
placement: 'left',
|
||||
}"
|
||||
/>
|
||||
</nuxt-link>
|
||||
</ds-space>
|
||||
<masonry-grid>
|
||||
<!-- TapNavigation -->
|
||||
<!-- <tab-navigation :tabs="tabOptions" :activeTab="tabActive" @switch-tab="handleTab" /> -->
|
||||
|
||||
<!-- feed -->
|
||||
<ds-grid-item :row-span="2" column-span="fullWidth">
|
||||
<ds-space centered>
|
||||
<nuxt-link :to="{ name: 'post-create' }">
|
||||
<base-button
|
||||
v-if="isGroupMember"
|
||||
v-tooltip="{
|
||||
content: $t('contribution.newPost'),
|
||||
placement: 'left',
|
||||
delay: { show: 500 },
|
||||
}"
|
||||
:path="{ name: 'post-create' }"
|
||||
class="profile-post-add-button"
|
||||
icon="plus"
|
||||
circle
|
||||
filled
|
||||
/>
|
||||
</nuxt-link>
|
||||
</ds-space>
|
||||
</ds-grid-item>
|
||||
|
||||
<!-- Group post feed -->
|
||||
<template v-if="posts && posts.length">
|
||||
<masonry-grid-item
|
||||
v-for="post in posts"
|
||||
@ -217,7 +292,7 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<ds-grid-item column-span="fullWidth">
|
||||
<empty margin="xx-large" icon="file" />
|
||||
<empty margin="xx-large" icon="file" data-test="icon-empty" />
|
||||
</ds-grid-item>
|
||||
</template>
|
||||
</masonry-grid>
|
||||
@ -238,7 +313,9 @@ import { updateGroupMutation, groupQuery, groupMembersQuery } from '~/graphql/gr
|
||||
// import UpdateQuery from '~/components/utils/UpdateQuery'
|
||||
import postListActions from '~/mixins/postListActions'
|
||||
import AvatarUploader from '~/components/Uploader/AvatarUploader'
|
||||
import Category from '~/components/Category'
|
||||
// import ContentMenu from '~/components/ContentMenu/ContentMenu'
|
||||
import ContentViewer from '~/components/Editor/ContentViewer'
|
||||
import CountTo from '~/components/CountTo.vue'
|
||||
import Empty from '~/components/Empty/Empty'
|
||||
// import FollowButton from '~/components/Button/FollowButton'
|
||||
@ -263,7 +340,9 @@ import ProfileList from '~/components/features/ProfileList/ProfileList'
|
||||
export default {
|
||||
components: {
|
||||
AvatarUploader,
|
||||
Category,
|
||||
// ContentMenu,
|
||||
ContentViewer,
|
||||
CountTo,
|
||||
Empty,
|
||||
// FollowButton,
|
||||
@ -290,8 +369,10 @@ export default {
|
||||
data() {
|
||||
// const filter = tabToFilterMapping({ tab: 'post', id: this.$route.params.id })
|
||||
return {
|
||||
categoriesActive: this.$env.CATEGORIES_ACTIVE,
|
||||
Group: [],
|
||||
GroupMembers: [],
|
||||
loadGroupMembers: false,
|
||||
posts: [],
|
||||
// hasMore: true,
|
||||
// offset: 0,
|
||||
@ -304,6 +385,7 @@ export default {
|
||||
membersCountStartValue: 0,
|
||||
membersCountToLoad: Infinity,
|
||||
updateGroupMutation,
|
||||
isDescriptionCollapsed: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -311,16 +393,7 @@ export default {
|
||||
return this.$store.getters['auth/user']
|
||||
},
|
||||
group() {
|
||||
return this.Group[0] ? this.Group[0] : {}
|
||||
},
|
||||
groupMembers() {
|
||||
return this.GroupMembers ? this.GroupMembers : []
|
||||
},
|
||||
isGroupOwner() {
|
||||
return this.group ? this.group.myRole === 'owner' : false
|
||||
},
|
||||
isGroupMember() {
|
||||
return this.group ? !!this.group.myRole : false
|
||||
return this.Group && this.Group[0] ? this.Group[0] : {}
|
||||
},
|
||||
groupName() {
|
||||
const { name } = this.group || {}
|
||||
@ -330,6 +403,31 @@ export default {
|
||||
const { slug } = this.group || {}
|
||||
return slug && `@${slug}`
|
||||
},
|
||||
groupDescriptionExcerpt() {
|
||||
return this.group ? this.$filters.removeLinks(this.group.descriptionExcerpt) : ''
|
||||
},
|
||||
isGroupOwner() {
|
||||
return this.group ? this.group.myRole === 'owner' : false
|
||||
},
|
||||
isGroupMember() {
|
||||
return this.group ? !!this.group.myRole : false
|
||||
},
|
||||
isGroupMemberNonePending() {
|
||||
return this.group ? ['usual', 'admin', 'owner'].includes(this.group.myRole) : false
|
||||
},
|
||||
isGroupVisible() {
|
||||
return this.group && !(this.group.groupType === 'hidden' && !this.isGroupMemberNonePending)
|
||||
},
|
||||
groupMembers() {
|
||||
return this.GroupMembers ? this.GroupMembers : []
|
||||
},
|
||||
isAllowedSeeingGroupMembers() {
|
||||
return (
|
||||
this.group &&
|
||||
(this.group.groupType === 'public' ||
|
||||
(['closed', 'hidden'].includes(this.group.groupType) && this.isGroupMemberNonePending))
|
||||
)
|
||||
},
|
||||
// tabOptions() {
|
||||
// return [
|
||||
// {
|
||||
@ -353,6 +451,11 @@ export default {
|
||||
// ]
|
||||
// },
|
||||
},
|
||||
watch: {
|
||||
isAllowedSeeingGroupMembers(to, _from) {
|
||||
this.loadGroupMembers = to
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// handleTab(tab) {
|
||||
// if (this.tabActive !== tab) {
|
||||
@ -463,7 +566,11 @@ export default {
|
||||
},
|
||||
updateJoinLeave({ myRoleInGroup }) {
|
||||
this.Group[0].myRole = myRoleInGroup
|
||||
this.$apollo.queries.GroupMembers.refetch()
|
||||
if (this.isAllowedSeeingGroupMembers) {
|
||||
this.$apollo.queries.GroupMembers.refetch()
|
||||
} else {
|
||||
this.GroupMembers = []
|
||||
}
|
||||
},
|
||||
fetchAllMembers() {
|
||||
this.membersCountToLoad = Infinity
|
||||
@ -489,8 +596,7 @@ export default {
|
||||
// },
|
||||
Group: {
|
||||
query() {
|
||||
// return groupQuery(this.$i18n) // language will be needed for locations
|
||||
return groupQuery
|
||||
return groupQuery(this.$i18n)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
@ -499,17 +605,26 @@ export default {
|
||||
// followingCount: this.followingCount,
|
||||
}
|
||||
},
|
||||
error(error) {
|
||||
this.$toast.error(error.message)
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
GroupMembers: {
|
||||
query() {
|
||||
return groupMembersQuery
|
||||
return groupMembersQuery()
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
id: this.$route.params.id,
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
return !this.loadGroupMembers
|
||||
},
|
||||
error(error) {
|
||||
this.$toast.error(error.message)
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
},
|
||||
@ -547,4 +662,17 @@ export default {
|
||||
.chip {
|
||||
margin-bottom: $space-x-small;
|
||||
}
|
||||
.group-description > .base-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
> .content {
|
||||
flex-grow: 1;
|
||||
margin-bottom: $space-small;
|
||||
}
|
||||
}
|
||||
.collaps-button {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -41,7 +41,7 @@ export default {
|
||||
}
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: createGroupMutation,
|
||||
mutation: createGroupMutation(),
|
||||
variables,
|
||||
})
|
||||
this.$toast.success(this.$t('group.groupCreated'))
|
||||
|
||||
@ -56,7 +56,7 @@ export default {
|
||||
Group: [group],
|
||||
},
|
||||
} = await client.query({
|
||||
query: groupQuery,
|
||||
query: groupQuery(), // "this.$i18n" is undefined here, so we use default lang
|
||||
variables: { id },
|
||||
})
|
||||
if (group.myRole !== 'owner') {
|
||||
|
||||
@ -37,7 +37,7 @@ export default {
|
||||
}
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: updateGroupMutation,
|
||||
mutation: updateGroupMutation(),
|
||||
variables,
|
||||
})
|
||||
this.$toast.success(this.$t('group.group-updated'))
|
||||
|
||||
@ -28,7 +28,7 @@ export default {
|
||||
async groupMembersQueryList() {
|
||||
try {
|
||||
const response = await this.$apollo.query({
|
||||
query: groupMembersQuery,
|
||||
query: groupMembersQuery(),
|
||||
variables: { id: this.group.id },
|
||||
})
|
||||
this.responseGroupMembersQuery = response.data.GroupMembers
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
v-tooltip="{
|
||||
content: $t('contribution.newPost'),
|
||||
placement: 'left',
|
||||
delay: { show: 500 },
|
||||
}"
|
||||
class="post-add-button"
|
||||
icon="plus"
|
||||
|
||||
@ -40,11 +40,12 @@ export default {
|
||||
async groupListQuery() {
|
||||
try {
|
||||
const response = await this.$apollo.query({
|
||||
query: groupQuery,
|
||||
query: groupQuery(this.$i18n),
|
||||
})
|
||||
this.responseGroupListQuery = response.data.Group
|
||||
} catch (error) {
|
||||
this.responseGroupListQuery = []
|
||||
this.$toast.error(error.message)
|
||||
} finally {
|
||||
this.pending = false
|
||||
}
|
||||
|
||||
@ -46,7 +46,6 @@
|
||||
<content-viewer class="content hyphenate-text" :content="post.content" />
|
||||
<!-- Categories -->
|
||||
<div v-if="categoriesActive" class="categories">
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
<ds-space margin="xx-large" />
|
||||
<ds-space margin="xx-small" />
|
||||
<hc-category
|
||||
@ -57,7 +56,6 @@
|
||||
v-tooltip="{
|
||||
content: $t(`contribution.category.description.${category.slug}`),
|
||||
placement: 'bottom-start',
|
||||
delay: { show: 1500 },
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -120,7 +120,6 @@
|
||||
v-tooltip="{
|
||||
content: $t('contribution.newPost'),
|
||||
placement: 'left',
|
||||
delay: { show: 500 },
|
||||
}"
|
||||
:path="{ name: 'post-create' }"
|
||||
class="profile-post-add-button"
|
||||
@ -238,7 +237,7 @@ export default {
|
||||
followedByCountStartValue: 0,
|
||||
followedByCount: followListVisibleCount,
|
||||
followingCount: followListVisibleCount,
|
||||
updateUserMutation: updateUserMutation(),
|
||||
updateUserMutation,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@ -25,6 +25,7 @@ import { VERSION } from '~/constants/terms-and-conditions-version.js'
|
||||
import { updateUserMutation } from '~/graphql/User.js'
|
||||
|
||||
export default {
|
||||
name: 'TermsAndConditionsConfirm',
|
||||
layout: 'default',
|
||||
head() {
|
||||
return {
|
||||
|
||||
@ -3,7 +3,7 @@ import VTooltip from 'v-tooltip'
|
||||
|
||||
Vue.use(VTooltip, {
|
||||
defaultDelay: {
|
||||
show: 500,
|
||||
show: 1500,
|
||||
hide: 50,
|
||||
},
|
||||
defaultOffset: 2,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user