fix: show only relevant userInfoActions for mentioned non-members (#31525)
parent
58c0efc732
commit
b764c415dc
@ -0,0 +1,7 @@ |
||||
--- |
||||
'@rocket.chat/rest-typings': patch |
||||
'@rocket.chat/meteor': patch |
||||
'@rocket.chat/i18n': patch |
||||
--- |
||||
|
||||
Fix: Show correct user info actions for non-members in channels. |
||||
@ -0,0 +1,10 @@ |
||||
import { useEndpoint } from '@rocket.chat/ui-contexts'; |
||||
import { useQuery } from '@tanstack/react-query'; |
||||
|
||||
type UseMemberExistsProps = { roomId: string; username: string }; |
||||
|
||||
export const useMemberExists = ({ roomId, username }: UseMemberExistsProps) => { |
||||
const checkMember = useEndpoint('GET', '/v1/rooms.isMember'); |
||||
|
||||
return useQuery(['rooms/isMember', roomId, username], () => checkMember({ roomId, username })); |
||||
}; |
||||
@ -0,0 +1,95 @@ |
||||
import type { IRoom, IUser } from '@rocket.chat/core-typings'; |
||||
import { isRoomFederated } from '@rocket.chat/core-typings'; |
||||
import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; |
||||
import { |
||||
useTranslation, |
||||
useUser, |
||||
useUserRoom, |
||||
useUserSubscription, |
||||
useToastMessageDispatch, |
||||
useAtLeastOnePermission, |
||||
useEndpoint, |
||||
} from '@rocket.chat/ui-contexts'; |
||||
import { useMemo } from 'react'; |
||||
|
||||
import * as Federation from '../../../../../lib/federation/Federation'; |
||||
import { useAddMatrixUsers } from '../../../contextualBar/RoomMembers/AddUsers/AddMatrixUsers/useAddMatrixUsers'; |
||||
import { getRoomDirectives } from '../../../lib/getRoomDirectives'; |
||||
import type { UserInfoAction } from '../useUserInfoActions'; |
||||
|
||||
const inviteUserEndpoints = { |
||||
c: '/v1/channels.invite', |
||||
p: '/v1/groups.invite', |
||||
} as const; |
||||
|
||||
export const useAddUserAction = ( |
||||
user: Pick<IUser, '_id' | 'username'>, |
||||
rid: IRoom['_id'], |
||||
reload?: () => void, |
||||
): UserInfoAction | undefined => { |
||||
const t = useTranslation(); |
||||
const room = useUserRoom(rid); |
||||
const currentUser = useUser(); |
||||
const subscription = useUserSubscription(rid); |
||||
const dispatchToastMessage = useToastMessageDispatch(); |
||||
|
||||
const { username, _id: uid } = user; |
||||
|
||||
if (!room) { |
||||
throw Error('Room not provided'); |
||||
} |
||||
|
||||
const hasPermissionToAddUsers = useAtLeastOnePermission( |
||||
useMemo(() => [room?.t === 'p' ? 'add-user-to-any-p-room' : 'add-user-to-any-c-room', 'add-user-to-joined-room'], [room?.t]), |
||||
rid, |
||||
); |
||||
|
||||
const userCanAdd = |
||||
room && user && isRoomFederated(room) |
||||
? Federation.isEditableByTheUser(currentUser || undefined, room, subscription) |
||||
: hasPermissionToAddUsers; |
||||
|
||||
const { roomCanInvite } = getRoomDirectives({ room, showingUserId: uid, userSubscription: subscription }); |
||||
|
||||
const inviteUser = useEndpoint('POST', inviteUserEndpoints[room.t === 'p' ? 'p' : 'c']); |
||||
|
||||
const handleAddUser = useEffectEvent(async ({ users }) => { |
||||
const [username] = users; |
||||
await inviteUser({ roomId: rid, username }); |
||||
reload?.(); |
||||
}); |
||||
|
||||
const addClickHandler = useAddMatrixUsers(); |
||||
|
||||
const addUserOptionAction = useEffectEvent(async () => { |
||||
try { |
||||
const users = [username as string]; |
||||
if (isRoomFederated(room)) { |
||||
addClickHandler.mutate({ |
||||
users, |
||||
handleSave: handleAddUser, |
||||
}); |
||||
} else { |
||||
await handleAddUser({ users }); |
||||
} |
||||
dispatchToastMessage({ type: 'success', message: t('User_added') }); |
||||
} catch (error) { |
||||
dispatchToastMessage({ type: 'error', message: error as Error }); |
||||
} |
||||
}); |
||||
|
||||
const addUserOption = useMemo( |
||||
() => |
||||
roomCanInvite && userCanAdd && room.archived !== true |
||||
? { |
||||
content: t('add-to-room'), |
||||
icon: 'user-plus' as const, |
||||
onClick: addUserOptionAction, |
||||
type: 'management' as const, |
||||
} |
||||
: undefined, |
||||
[roomCanInvite, userCanAdd, room.archived, t, addUserOptionAction], |
||||
); |
||||
|
||||
return addUserOption; |
||||
}; |
||||
@ -0,0 +1,90 @@ |
||||
import { Users } from './fixtures/userStates'; |
||||
import { HomeChannel } from './page-objects'; |
||||
import { createTargetChannel, deleteChannel } from './utils'; |
||||
import { expect, test } from './utils/test'; |
||||
|
||||
test.use({ storageState: Users.user3.state }); |
||||
|
||||
test.describe.parallel('Mention User Card [To Member]', () => { |
||||
let poHomeChannel: HomeChannel; |
||||
let targetChannel: string; |
||||
|
||||
test.beforeAll(async ({ api }) => { |
||||
targetChannel = await createTargetChannel(api, { members: [Users.user1.data.username, Users.user3.data.username] }); |
||||
|
||||
await api.post(`/chat.postMessage`, { |
||||
text: `Hello @${Users.user1.data.username} @${Users.user2.data.username}`, |
||||
channel: targetChannel, |
||||
}); |
||||
}); |
||||
|
||||
test.beforeEach(async ({ page }) => { |
||||
poHomeChannel = new HomeChannel(page); |
||||
|
||||
await page.goto('/home'); |
||||
}); |
||||
|
||||
test.afterAll(({ api }) => deleteChannel(api, targetChannel)); |
||||
|
||||
test('should show correct userinfo actions for a member of the room to a non-privileged member', async ({ page }) => { |
||||
await poHomeChannel.sidenav.openChat(targetChannel); |
||||
const mentionSpan = page.locator(`span[title="Mentions user"][data-uid="${Users.user1.data.username}"]`); |
||||
await mentionSpan.click(); |
||||
|
||||
await expect(page.locator('div[aria-label="User card actions"]')).toBeVisible(); |
||||
const moreButton = await page.locator('div[aria-label="User card actions"] button[title="More"]'); |
||||
if (await moreButton.isVisible()) { |
||||
await moreButton.click(); |
||||
} |
||||
|
||||
const isAddToRoomVisible = |
||||
(await page.locator('button[title="Add to room"]').isVisible()) || (await page.locator('label[data-key="Add to room"]').isVisible()); |
||||
await expect(isAddToRoomVisible).toBeFalsy(); |
||||
|
||||
const isRemoveFromRoomVisible = |
||||
(await page.locator('button[title="Remove from room"]').isVisible()) || |
||||
(await page.locator('label[data-key="Remove from room"]').isVisible()); |
||||
await expect(isRemoveFromRoomVisible).toBeFalsy(); |
||||
|
||||
const isSetAsLeaderVisible = |
||||
(await page.locator('button[title="Set as leader"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as leader"]').isVisible()); |
||||
await expect(isSetAsLeaderVisible).toBeFalsy(); |
||||
|
||||
const isSetAsModeratorVisible = |
||||
(await page.locator('button[title="Set as moderator"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as moderator"]').isVisible()); |
||||
await expect(isSetAsModeratorVisible).toBeFalsy(); |
||||
}); |
||||
|
||||
test('should show correct userinfo actions for a non-member of the room to a non-privileged member', async ({ page }) => { |
||||
await poHomeChannel.sidenav.openChat(targetChannel); |
||||
const mentionSpan = page.locator(`span[title="Mentions user"][data-uid="${Users.user2.data.username}"]`); |
||||
await mentionSpan.click(); |
||||
|
||||
await expect(page.locator('div[aria-label="User card actions"]')).toBeVisible(); |
||||
const moreButton = await page.locator('div[aria-label="User card actions"] button[title="More"]'); |
||||
if (await moreButton.isVisible()) { |
||||
await moreButton.click(); |
||||
} |
||||
|
||||
const isAddToRoomVisible = |
||||
(await page.locator('button[title="Add to room"]').isVisible()) || (await page.locator('label[data-key="Add to room"]').isVisible()); |
||||
await expect(isAddToRoomVisible).toBeFalsy(); |
||||
|
||||
const isRemoveFromRoomVisible = |
||||
(await page.locator('button[title="Remove from room"]').isVisible()) || |
||||
(await page.locator('label[data-key="Remove from room"]').isVisible()); |
||||
await expect(isRemoveFromRoomVisible).toBeFalsy(); |
||||
|
||||
const isSetAsLeaderVisible = |
||||
(await page.locator('button[title="Set as leader"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as leader"]').isVisible()); |
||||
await expect(isSetAsLeaderVisible).toBeFalsy(); |
||||
|
||||
const isSetAsModeratorVisible = |
||||
(await page.locator('button[title="Set as moderator"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as moderator"]').isVisible()); |
||||
await expect(isSetAsModeratorVisible).toBeFalsy(); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,90 @@ |
||||
import { Users } from './fixtures/userStates'; |
||||
import { HomeChannel } from './page-objects'; |
||||
import { createTargetChannel, deleteChannel } from './utils'; |
||||
import { expect, test } from './utils/test'; |
||||
|
||||
test.use({ storageState: Users.admin.state }); |
||||
test.describe.parallel('Mention User Card [To Room Owner]', () => { |
||||
let poHomeChannel: HomeChannel; |
||||
let targetChannel: string; |
||||
|
||||
test.beforeAll(async ({ api }) => { |
||||
targetChannel = await createTargetChannel(api, { members: [Users.user1.data.username] }); |
||||
|
||||
await api.post(`/chat.postMessage`, { |
||||
text: `Hello @${Users.user1.data.username} @${Users.user2.data.username}`, |
||||
channel: targetChannel, |
||||
}); |
||||
}); |
||||
|
||||
test.beforeEach(async ({ page }) => { |
||||
poHomeChannel = new HomeChannel(page); |
||||
|
||||
await page.goto('/home'); |
||||
}); |
||||
|
||||
test.afterAll(({ api }) => deleteChannel(api, targetChannel)); |
||||
|
||||
test('should show correct userinfo actions for a member of the room to the room owner', async ({ page }) => { |
||||
await poHomeChannel.sidenav.openChat(targetChannel); |
||||
const mentionSpan = page.locator(`span[title="Mentions user"][data-uid="${Users.user1.data.username}"]`); |
||||
await mentionSpan.click(); |
||||
|
||||
await expect(page.locator('div[aria-label="User card actions"]')).toBeVisible(); |
||||
const moreButton = await page.locator('div[aria-label="User card actions"] button[title="More"]'); |
||||
|
||||
if (await moreButton.isVisible()) { |
||||
await moreButton.click(); |
||||
} |
||||
|
||||
const isAddToRoomVisible = |
||||
(await page.locator('button[title="Add to room"]').isVisible()) || (await page.locator('label[data-key="Add to room"]').isVisible()); |
||||
await expect(isAddToRoomVisible).toBeFalsy(); |
||||
|
||||
const isRemoveFromRoomVisible = |
||||
(await page.locator('button[title="Remove from room"]').isVisible()) || |
||||
(await page.locator('label[data-key="Remove from room"]').isVisible()); |
||||
await expect(isRemoveFromRoomVisible).toBeTruthy(); |
||||
|
||||
const isSetAsLeaderVisible = |
||||
(await page.locator('button[title="Set as leader"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as leader"]').isVisible()); |
||||
await expect(isSetAsLeaderVisible).toBeTruthy(); |
||||
|
||||
const isSetAsModeratorVisible = |
||||
(await page.locator('button[title="Set as moderator"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as moderator"]').isVisible()); |
||||
await expect(isSetAsModeratorVisible).toBeTruthy(); |
||||
}); |
||||
|
||||
test('should show correct userinfo actions for a non-member of the room to the room owner', async ({ page }) => { |
||||
await poHomeChannel.sidenav.openChat(targetChannel); |
||||
const mentionSpan = page.locator(`span[title="Mentions user"][data-uid="${Users.user2.data.username}"]`); |
||||
await mentionSpan.click(); |
||||
|
||||
await expect(page.locator('div[aria-label="User card actions"]')).toBeVisible(); |
||||
const moreButton = await page.locator('div[aria-label="User card actions"] button[title="More"]'); |
||||
if (await moreButton.isVisible()) { |
||||
await moreButton.click(); |
||||
} |
||||
|
||||
const isAddToRoomVisible = |
||||
(await page.locator('button[title="Add to room"]').isVisible()) || (await page.locator('label[data-key="Add to room"]').isVisible()); |
||||
await expect(isAddToRoomVisible).toBeTruthy(); |
||||
|
||||
const isRemoveFromRoomVisible = |
||||
(await page.locator('button[title="Remove from room"]').isVisible()) || |
||||
(await page.locator('label[data-key="Remove from room"]').isVisible()); |
||||
await expect(isRemoveFromRoomVisible).toBeFalsy(); |
||||
|
||||
const isSetAsLeaderVisible = |
||||
(await page.locator('button[title="Set as leader"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as leader"]').isVisible()); |
||||
await expect(isSetAsLeaderVisible).toBeFalsy(); |
||||
|
||||
const isSetAsModeratorVisible = |
||||
(await page.locator('button[title="Set as moderator"]').isVisible()) || |
||||
(await page.locator('label[data-key="Set as moderator"]').isVisible()); |
||||
await expect(isSetAsModeratorVisible).toBeFalsy(); |
||||
}); |
||||
}); |
||||
Loading…
Reference in new issue