mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge branch 'master' into fix-deploy-branded
This commit is contained in:
commit
9075798027
@ -150,6 +150,19 @@ export const changeGroupMemberRoleMutation = () => {
|
||||
`
|
||||
}
|
||||
|
||||
export const removeUserFromGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
RemoveUserFromGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
// ------ queries
|
||||
|
||||
export const groupQuery = () => {
|
||||
|
||||
@ -253,6 +253,42 @@ const isMemberOfGroup = rule({
|
||||
}
|
||||
})
|
||||
|
||||
const canRemoveUserFromGroup = rule({
|
||||
cache: 'no_cache',
|
||||
})(async (_parent, args, { user, driver }) => {
|
||||
if (!(user && user.id)) return false
|
||||
const { groupId, userId } = args
|
||||
const currentUserId = user.id
|
||||
if (currentUserId === userId) return false
|
||||
const session = driver.session()
|
||||
const readTxPromise = session.readTransaction(async (transaction) => {
|
||||
const transactionResponse = await transaction.run(
|
||||
`
|
||||
MATCH (User {id: $currentUserId})-[currentUserMembership:MEMBER_OF]->(group:Group {id: $groupId})
|
||||
OPTIONAL MATCH (group)<-[userMembership:MEMBER_OF]-(user:User { id: $userId })
|
||||
RETURN currentUserMembership.role AS currentUserRole, userMembership.role AS userRole
|
||||
`,
|
||||
{ currentUserId, groupId, userId },
|
||||
)
|
||||
return {
|
||||
currentUserRole: transactionResponse.records.map((record) =>
|
||||
record.get('currentUserRole'),
|
||||
)[0],
|
||||
userRole: transactionResponse.records.map((record) => record.get('userRole'))[0],
|
||||
}
|
||||
})
|
||||
try {
|
||||
const { currentUserRole, userRole } = await readTxPromise
|
||||
return (
|
||||
currentUserRole && ['owner'].includes(currentUserRole) && userRole && userRole !== 'owner'
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
})
|
||||
|
||||
const canCommentPost = rule({
|
||||
cache: 'no_cache',
|
||||
})(async (_parent, args, { user, driver }) => {
|
||||
@ -382,6 +418,7 @@ export default shield(
|
||||
JoinGroup: isAllowedToJoinGroup,
|
||||
LeaveGroup: isAllowedToLeaveGroup,
|
||||
ChangeGroupMemberRole: isAllowedToChangeGroupMemberRole,
|
||||
RemoveUserFromGroup: canRemoveUserFromGroup,
|
||||
CreatePost: and(isAuthenticated, isMemberOfGroup),
|
||||
UpdatePost: isAuthor,
|
||||
DeletePost: isAuthor,
|
||||
|
||||
@ -295,25 +295,8 @@ export default {
|
||||
LeaveGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
const { groupId, userId } = params
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
|
||||
const leaveGroupCypher = `
|
||||
MATCH (member:User {id: $userId})-[membership:MEMBER_OF]->(group:Group {id: $groupId})
|
||||
DELETE membership
|
||||
WITH member, group
|
||||
OPTIONAL MATCH (p:Post)-[:IN]->(group)
|
||||
WHERE NOT group.groupType = 'public'
|
||||
WITH member, group, collect(p) AS posts
|
||||
FOREACH (post IN posts |
|
||||
MERGE (member)-[:CANNOT_SEE]->(post))
|
||||
RETURN member {.*, myRoleInGroup: NULL}
|
||||
`
|
||||
|
||||
const transactionResponse = await transaction.run(leaveGroupCypher, { groupId, userId })
|
||||
const [member] = await transactionResponse.records.map((record) => record.get('member'))
|
||||
return member
|
||||
})
|
||||
try {
|
||||
return await writeTxResultPromise
|
||||
return await removeUserFromGroupWriteTxResultPromise(session, groupId, userId)
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
@ -368,6 +351,17 @@ export default {
|
||||
session.close()
|
||||
}
|
||||
},
|
||||
RemoveUserFromGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
const { groupId, userId } = params
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
return await removeUserFromGroupWriteTxResultPromise(session, groupId, userId)
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
},
|
||||
},
|
||||
Group: {
|
||||
...Resolver('Group', {
|
||||
@ -383,3 +377,27 @@ export default {
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
const removeUserFromGroupWriteTxResultPromise = async (session, groupId, userId) => {
|
||||
return session.writeTransaction(async (transaction) => {
|
||||
const removeUserFromGroupCypher = `
|
||||
MATCH (user:User {id: $userId})-[membership:MEMBER_OF]->(group:Group {id: $groupId})
|
||||
DELETE membership
|
||||
WITH user, group
|
||||
OPTIONAL MATCH (author:User)-[:WROTE]->(p:Post)-[:IN]->(group)
|
||||
WHERE NOT group.groupType = 'public'
|
||||
AND NOT author.id = $userId
|
||||
WITH user, collect(p) AS posts
|
||||
FOREACH (post IN posts |
|
||||
MERGE (user)-[:CANNOT_SEE]->(post))
|
||||
RETURN user {.*, myRoleInGroup: NULL}
|
||||
`
|
||||
|
||||
const transactionResponse = await transaction.run(removeUserFromGroupCypher, {
|
||||
groupId,
|
||||
userId,
|
||||
})
|
||||
const [user] = await transactionResponse.records.map((record) => record.get('user'))
|
||||
return user
|
||||
})
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
joinGroupMutation,
|
||||
leaveGroupMutation,
|
||||
changeGroupMemberRoleMutation,
|
||||
removeUserFromGroupMutation,
|
||||
groupMembersQuery,
|
||||
groupQuery,
|
||||
} from '../../graphql/groups'
|
||||
@ -196,7 +197,6 @@ const seedComplexScenarioAndClearAuthentication = async () => {
|
||||
},
|
||||
})
|
||||
// hidden-group
|
||||
authenticatedUser = await adminMemberUser.toJson()
|
||||
await mutate({
|
||||
mutation: createGroupMutation(),
|
||||
variables: {
|
||||
@ -214,32 +214,17 @@ const seedComplexScenarioAndClearAuthentication = async () => {
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'admin-member-user',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'second-owner-member-user',
|
||||
userId: 'usual-member-user',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'admin-member-user',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'second-owner-member-user',
|
||||
roleInGroup: 'usual',
|
||||
roleInGroup: 'admin',
|
||||
},
|
||||
})
|
||||
|
||||
@ -2982,4 +2967,192 @@ describe('in mode', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('RemoveUserFromGroup', () => {
|
||||
beforeAll(async () => {
|
||||
await seedComplexScenarioAndClearAuthentication()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'usual-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
message: 'Not Authorized!',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('authenticated', () => {
|
||||
describe('as usual member', () => {
|
||||
it('throws an error', async () => {
|
||||
authenticatedUser = await usualMemberUser.toJson()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'admin-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
message: 'Not Authorized!',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('as owner', () => {
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = await ownerMemberUser.toJson()
|
||||
})
|
||||
|
||||
it('removes the user from the group', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'usual-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
RemoveUserFromGroup: expect.objectContaining({
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: null,
|
||||
}),
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('cannot remove self', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'owner-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
message: 'Not Authorized!',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('as admin', () => {
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = await adminMemberUser.toJson()
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'usual-member-user',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
authenticatedUser = await usualMemberUser.toJson()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'admin-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
message: 'Not Authorized!',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
it('removes the user from the group', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'usual-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
RemoveUserFromGroup: expect.objectContaining({
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: null,
|
||||
}),
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('cannot remove self', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'admin-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
message: 'Not Authorized!',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
|
||||
it('cannot remove owner', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'owner-member-user',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
message: 'Not Authorized!',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
*/
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1524,9 +1524,9 @@ describe('Posts in Groups', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('does not show the posts of the closed group anymore', async () => {
|
||||
it('stil shows the posts of the closed group', async () => {
|
||||
const result = await query({ query: filterPosts(), variables: {} })
|
||||
expect(result.data.Post).toHaveLength(3)
|
||||
expect(result.data.Post).toHaveLength(4)
|
||||
expect(result).toMatchObject({
|
||||
data: {
|
||||
Post: expect.arrayContaining([
|
||||
@ -1540,6 +1540,11 @@ describe('Posts in Groups', () => {
|
||||
title: 'A post without a group',
|
||||
content: 'I am a user who does not belong to a group yet.',
|
||||
},
|
||||
{
|
||||
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',
|
||||
@ -1564,9 +1569,9 @@ describe('Posts in Groups', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('does only show the public posts', async () => {
|
||||
it('still shows the post of the hidden group', async () => {
|
||||
const result = await query({ query: filterPosts(), variables: {} })
|
||||
expect(result.data.Post).toHaveLength(2)
|
||||
expect(result.data.Post).toHaveLength(4)
|
||||
expect(result).toMatchObject({
|
||||
data: {
|
||||
Post: expect.arrayContaining([
|
||||
@ -1580,6 +1585,16 @@ describe('Posts in Groups', () => {
|
||||
title: 'A post without a group',
|
||||
content: 'I am a user who does not belong to a group yet.',
|
||||
},
|
||||
{
|
||||
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,
|
||||
@ -1603,9 +1618,9 @@ describe('Posts in Groups', () => {
|
||||
authenticatedUser = await allGroupsUser.toJson()
|
||||
})
|
||||
|
||||
it('does not show the posts of the closed group', async () => {
|
||||
it('shows the posts of the closed group', async () => {
|
||||
const result = await query({ query: filterPosts(), variables: {} })
|
||||
expect(result.data.Post).toHaveLength(3)
|
||||
expect(result.data.Post).toHaveLength(4)
|
||||
expect(result).toMatchObject({
|
||||
data: {
|
||||
Post: expect.arrayContaining([
|
||||
@ -1624,6 +1639,11 @@ describe('Posts in Groups', () => {
|
||||
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,
|
||||
|
||||
@ -132,4 +132,9 @@ type Mutation {
|
||||
userId: ID!
|
||||
roleInGroup: GroupMemberRole!
|
||||
): User
|
||||
|
||||
RemoveUserFromGroup(
|
||||
groupId: ID!
|
||||
userId: ID!
|
||||
): User
|
||||
}
|
||||
|
||||
@ -1,26 +1,65 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import GroupMember from './GroupMember.vue'
|
||||
import { changeGroupMemberRoleMutation, removeUserFromGroupMutation } from '~/graphql/groups.js'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const propsData = {
|
||||
groupId: '',
|
||||
groupMembers: [],
|
||||
groupId: 'group-id',
|
||||
groupMembers: [
|
||||
{
|
||||
slug: 'owner',
|
||||
id: 'owner',
|
||||
myRoleInGroup: 'owner',
|
||||
},
|
||||
{
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
myRoleInGroup: 'usual',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const stubs = {
|
||||
'nuxt-link': true,
|
||||
}
|
||||
|
||||
const apolloMock = jest
|
||||
.fn()
|
||||
.mockRejectedValueOnce({ message: 'Oh no!' })
|
||||
.mockResolvedValue({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
myRoleInGroup: 'admin',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const toastErrorMock = jest.fn()
|
||||
const toastSuccessMock = jest.fn()
|
||||
|
||||
describe('GroupMember', () => {
|
||||
let wrapper
|
||||
let mocks
|
||||
|
||||
beforeEach(() => {
|
||||
mocks = {
|
||||
$t: jest.fn(),
|
||||
$t: jest.fn((t) => t),
|
||||
$apollo: {
|
||||
mutate: apolloMock,
|
||||
},
|
||||
$toast: {
|
||||
error: toastErrorMock,
|
||||
success: toastSuccessMock,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
const Wrapper = () => {
|
||||
return mount(GroupMember, { propsData, mocks, localVue })
|
||||
return mount(GroupMember, { propsData, mocks, localVue, stubs })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
@ -30,5 +69,120 @@ describe('GroupMember', () => {
|
||||
it('renders', () => {
|
||||
expect(wrapper.findAll('.group-member')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('has two users in table', () => {
|
||||
expect(wrapper.find('tbody').findAll('tr')).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('has no modal', () => {
|
||||
expect(wrapper.find('div.ds-modal-wrapper').exists()).toBe(false)
|
||||
})
|
||||
|
||||
describe('change user role', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
wrapper
|
||||
.find('tbody')
|
||||
.findAll('tr')
|
||||
.at(1)
|
||||
.find('select')
|
||||
.findAll('option')
|
||||
.at(2)
|
||||
.setSelected()
|
||||
wrapper.find('tbody').findAll('tr').at(1).find('select').trigger('change')
|
||||
})
|
||||
|
||||
describe('with server error', () => {
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorMock).toBeCalledWith('Oh no!')
|
||||
})
|
||||
})
|
||||
|
||||
describe('with server success', () => {
|
||||
it('calls the API', () => {
|
||||
expect(apolloMock).toBeCalledWith({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: { groupId: 'group-id', userId: 'user', roleInGroup: 'admin' },
|
||||
})
|
||||
})
|
||||
|
||||
it('toasts a success message', () => {
|
||||
expect(toastSuccessMock).toBeCalledWith('group.changeMemberRole')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('click remove user', () => {
|
||||
beforeAll(() => {
|
||||
apolloMock.mockRejectedValueOnce({ message: 'Oh no!!' }).mockResolvedValue({
|
||||
data: {
|
||||
RemoveUserFromGroup: {
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
myRoleInGroup: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
wrapper.find('tbody').findAll('tr').at(1).find('button').trigger('click')
|
||||
})
|
||||
|
||||
it('opens the modal', () => {
|
||||
expect(wrapper.find('div.ds-modal-wrapper').isVisible()).toBe(true)
|
||||
})
|
||||
|
||||
describe('click on cancel', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('div.ds-modal-wrapper').find('button.ds-button-ghost').trigger('click')
|
||||
})
|
||||
|
||||
it('closes the modal', () => {
|
||||
expect(wrapper.find('div.ds-modal-wrapper').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('click on confirm with server error', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('div.ds-modal-wrapper').find('button.ds-button-primary').trigger('click')
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorMock).toBeCalledWith('Oh no!!')
|
||||
})
|
||||
|
||||
it('closes the modal', () => {
|
||||
expect(wrapper.find('div.ds-modal-wrapper').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('click on confirm with success', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
wrapper.find('div.ds-modal-wrapper').find('button.ds-button-primary').trigger('click')
|
||||
})
|
||||
|
||||
it('calls the API', () => {
|
||||
expect(apolloMock).toBeCalledWith({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: { groupId: 'group-id', userId: 'user' },
|
||||
})
|
||||
})
|
||||
|
||||
it('emits load group members', () => {
|
||||
expect(wrapper.emitted('loadGroupMembers')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('toasts a success message', () => {
|
||||
expect(toastSuccessMock).toBeCalledWith('group.memberRemoved')
|
||||
})
|
||||
|
||||
it('closes the modal', () => {
|
||||
expect(wrapper.find('div.ds-modal-wrapper').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -53,30 +53,33 @@
|
||||
</ds-chip>
|
||||
</template>
|
||||
<template #edit="scope">
|
||||
<ds-button v-if="scope.row.myRoleInGroup !== 'owner'" size="small" primary disabled>
|
||||
<!-- TODO: implement removal of group members -->
|
||||
<!-- :disabled="scope.row.myRoleInGroup === 'owner'"
|
||||
-->
|
||||
<base-button
|
||||
v-if="scope.row.myRoleInGroup !== 'owner'"
|
||||
size="small"
|
||||
primary
|
||||
@click="
|
||||
isOpen = true
|
||||
userId = scope.row.id
|
||||
"
|
||||
>
|
||||
{{ $t('group.removeMemberButton') }}
|
||||
</ds-button>
|
||||
</base-button>
|
||||
</template>
|
||||
</ds-table>
|
||||
<!-- TODO: implement removal of group members -->
|
||||
<!-- TODO: change to ocelot.social modal -->
|
||||
<!-- <ds-modal
|
||||
v-if="isOpen"
|
||||
v-model="isOpen"
|
||||
:title="`${$t('group.removeMember')}`"
|
||||
force
|
||||
extended
|
||||
:confirm-label="$t('group.removeMember')"
|
||||
:cancel-label="$t('actions.cancel')"
|
||||
@confirm="deleteMember(memberId)"
|
||||
/> -->
|
||||
<ds-modal
|
||||
v-if="isOpen"
|
||||
v-model="isOpen"
|
||||
:title="`${$t('group.removeMember')}`"
|
||||
force
|
||||
extended
|
||||
:confirm-label="$t('group.removeMember')"
|
||||
:cancel-label="$t('actions.cancel')"
|
||||
@confirm="removeUser()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { changeGroupMemberRoleMutation } from '~/graphql/groups.js'
|
||||
import { changeGroupMemberRoleMutation, removeUserFromGroupMutation } from '~/graphql/groups.js'
|
||||
|
||||
export default {
|
||||
name: 'GroupMember',
|
||||
@ -96,6 +99,8 @@ export default {
|
||||
query: '',
|
||||
searchProcess: null,
|
||||
user: {},
|
||||
isOpen: false,
|
||||
userId: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -139,6 +144,25 @@ export default {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
},
|
||||
removeUser() {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: removeUserFromGroupMutation(),
|
||||
variables: { groupId: this.groupId, userId: this.userId },
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.$emit('loadGroupMembers')
|
||||
this.$toast.success(
|
||||
this.$t('group.memberRemoved', { name: data.RemoveUserFromGroup.slug }),
|
||||
)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(error.message)
|
||||
})
|
||||
.finally(() => {
|
||||
this.userId = null
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -143,6 +143,19 @@ export const changeGroupMemberRoleMutation = () => {
|
||||
`
|
||||
}
|
||||
|
||||
export const removeUserFromGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
RemoveUserFromGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
// ------ queries
|
||||
|
||||
export const groupQuery = (i18n) => {
|
||||
|
||||
@ -455,6 +455,7 @@
|
||||
"message": "Eine Gruppe zu verlassen ist möglicherweise nicht rückgängig zu machen!<br>Gruppe <b>„{name}“</b> verlassen!",
|
||||
"title": "Möchtest du wirklich die Gruppe verlassen?"
|
||||
},
|
||||
"memberRemoved": "Nutzer „{name}“ wurde aus der Gruppe entfernt!",
|
||||
"members": "Mitglieder",
|
||||
"membersAdministrationList": {
|
||||
"avatar": "Avatar",
|
||||
|
||||
@ -455,6 +455,7 @@
|
||||
"message": "Leaving a group may be irreversible!<br>Leave group <b>“{name}”</b>!",
|
||||
"title": "Do you really want to leave the group?"
|
||||
},
|
||||
"memberRemoved": "User “{name}” was removed from group!",
|
||||
"members": "Members",
|
||||
"membersAdministrationList": {
|
||||
"avatar": "Avatar",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user