Skip to content

Commit

Permalink
fix: Change users room role action message not being displayed correc…
Browse files Browse the repository at this point in the history
…tly (#34503)
  • Loading branch information
dougfabris authored Dec 24, 2024
1 parent c7eedf8 commit 86a21b5
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 83 deletions.
5 changes: 5 additions & 0 deletions .changeset/healthy-coins-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes an issue where changing user role in a room displays the wrong message
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import type { IRoom, IUser } from '@rocket.chat/core-typings';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useTranslation, usePermission, useUserRoom, useUserSubscription } from '@rocket.chat/ui-contexts';
import { useMemo } from 'react';
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
import {
useTranslation,
usePermission,
useUserRoom,
useUserSubscription,
useEndpoint,
useToastMessageDispatch,
} from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';

import { useEndpointAction } from '../../../../../hooks/useEndpointAction';
import { getRoomDirectives } from '../../../lib/getRoomDirectives';
import { useUserHasRoomRole } from '../../useUserHasRoomRole';
import type { UserInfoAction, UserInfoActionType } from '../useUserInfoActions';

const getEndpoint = (roomType: string, isLeader: boolean) => {
if (roomType === 'p') {
return isLeader ? '/v1/groups.removeLeader' : '/v1/groups.addLeader';
}
return isLeader ? '/v1/channels.removeLeader' : '/v1/channels.addLeader';
};

export const useChangeLeaderAction = (user: Pick<IUser, '_id' | 'username'>, rid: IRoom['_id']): UserInfoAction | undefined => {
const t = useTranslation();
const room = useUserRoom(rid);
const { _id: uid } = user;
const { _id: uid, username } = user;
const userCanSetLeader = usePermission('set-leader', rid);
const userSubscription = useUserSubscription(rid);
const dispatchToastMessage = useToastMessageDispatch();

if (!room) {
throw Error('Room not provided');
Expand All @@ -22,13 +37,27 @@ export const useChangeLeaderAction = (user: Pick<IUser, '_id' | 'username'>, rid
const { roomCanSetLeader } = getRoomDirectives({ room, showingUserId: uid, userSubscription });
const isLeader = useUserHasRoomRole(uid, rid, 'leader');

const endpointPrefix = room.t === 'p' ? '/v1/groups' : '/v1/channels';
const changeLeaderEndpoint = isLeader ? 'removeLeader' : 'addLeader';
const changeLeaderMessage = isLeader ? 'removed__username__as__role_' : 'set__username__as__role_';
const changeLeader = useEndpointAction('POST', `${endpointPrefix}.${changeLeaderEndpoint}`, {
successMessage: t(changeLeaderMessage, { username: user.username, role: 'leader' }),
const toggleLeaderEndpoint = useEndpoint('POST', getEndpoint(room.t, isLeader));

const toggleOwnerMutation = useMutation({
mutationFn: useCallback(
async ({ roomId, userId }) => {
await toggleLeaderEndpoint({ roomId, userId });

return t(isLeader ? 'removed__username__as__role_' : 'set__username__as__role_', { username, role: 'leader' });
},
[t, isLeader, toggleLeaderEndpoint, username],
),
onSuccess: (message) => {
dispatchToastMessage({ type: 'success', message });
},
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
});
const changeLeaderAction = useMutableCallback(() => changeLeader({ roomId: rid, userId: uid }));

const changeLeaderAction = useEffectEvent(async () => toggleOwnerMutation.mutateAsync({ roomId: rid, userId: uid }));

const changeLeaderOption = useMemo(
() =>
roomCanSetLeader && userCanSetLeader
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import type { IRoom, IUser } from '@rocket.chat/core-typings';
import { isRoomFederated } from '@rocket.chat/core-typings';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
import { escapeHTML } from '@rocket.chat/string-helpers';
import { useTranslation, usePermission, useUserRoom, useUserSubscription, useUser, useSetModal } from '@rocket.chat/ui-contexts';
import {
useTranslation,
usePermission,
useUserRoom,
useUserSubscription,
useUser,
useSetModal,
useEndpoint,
useToastMessageDispatch,
} from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import type { ReactElement } from 'react';
import React, { useCallback, useMemo } from 'react';

import GenericModal from '../../../../../components/GenericModal';
import { useEndpointAction } from '../../../../../hooks/useEndpointAction';
import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator';
import { getRoomDirectives } from '../../../lib/getRoomDirectives';
import { useUserHasRoomRole } from '../../useUserHasRoomRole';
Expand All @@ -32,6 +41,13 @@ const getWarningModalForFederatedRooms = (
</GenericModal>
);

const getEndpoint = (roomType: string, isModerator: boolean) => {
if (roomType === 'p') {
return isModerator ? '/v1/groups.removeModerator' : '/v1/groups.addModerator';
}
return isModerator ? '/v1/channels.removeModerator' : '/v1/channels.addModerator';
};

export const useChangeModeratorAction = (user: Pick<IUser, '_id' | 'username'>, rid: IRoom['_id']): UserInfoAction | undefined => {
const t = useTranslation();
const room = useUserRoom(rid);
Expand All @@ -44,7 +60,7 @@ export const useChangeModeratorAction = (user: Pick<IUser, '_id' | 'username'>,
const loggedUserIsModerator = useUserHasRoomRole(loggedUserId, rid, 'moderator');
const loggedUserIsOwner = useUserHasRoomRole(loggedUserId, rid, 'owner');
const setModal = useSetModal();
const closeModal = useCallback(() => setModal(null), [setModal]);
const dispatchToastMessage = useToastMessageDispatch();

if (!room) {
throw Error('Room not provided');
Expand All @@ -53,27 +69,42 @@ export const useChangeModeratorAction = (user: Pick<IUser, '_id' | 'username'>,
const { roomCanSetModerator } = getRoomDirectives({ room, showingUserId: uid, userSubscription });
const roomName = room?.t && escapeHTML(roomCoordinator.getRoomName(room.t, room));

const endpointPrefix = room.t === 'p' ? '/v1/groups' : '/v1/channels';
const changeModeratorEndpoint = isModerator ? 'removeModerator' : 'addModerator';
const changeModeratorMessage = isModerator
? 'User__username__removed_from__room_name__moderators'
: 'User__username__is_now_a_moderator_of__room_name_';

const changeModerator = useEndpointAction('POST', `${endpointPrefix}.${changeModeratorEndpoint}`, {
successMessage: t(changeModeratorMessage, { username: user.username, room_name: roomName }),
const toggleModeratorEndpoint = useEndpoint('POST', getEndpoint(room.t, isModerator));
const toggleModerator = useMutation({
mutationFn: useCallback(
async ({ roomId, userId }) => {
await toggleModeratorEndpoint({ roomId, userId });

return t(
isModerator ? 'User__username__removed_from__room_name__moderators' : 'User__username__is_now_a_moderator_of__room_name_',
{
username: user.username,
room_name: roomName,
},
);
},
[toggleModeratorEndpoint, t, isModerator, user.username, roomName],
),
onSuccess: (message) => {
dispatchToastMessage({ type: 'success', message });
},
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
});

const handleConfirm = useCallback(() => {
changeModerator({ roomId: rid, userId: uid });
closeModal();
}, [changeModerator, rid, uid, closeModal]);

const handleChangeModerator = useCallback(
({ userId }) => {
if (!isRoomFederated(room)) {
return changeModerator({ roomId: rid, userId: uid });
return toggleModerator.mutateAsync({ roomId: rid, userId: uid });
}

const closeModal = () => setModal(null);
const handleConfirm = async () => {
await toggleModerator.mutateAsync({ roomId: rid, userId: uid });
closeModal();
};

const changingOwnRole = userId === loggedUserId;
if (changingOwnRole && loggedUserIsModerator) {
return setModal(() =>
Expand Down Expand Up @@ -111,12 +142,13 @@ export const useChangeModeratorAction = (user: Pick<IUser, '_id' | 'username'>,
);
}

changeModerator({ roomId: rid, userId: uid });
toggleModerator.mutateAsync({ roomId: rid, userId: uid });
},
[setModal, loggedUserId, loggedUserIsModerator, loggedUserIsOwner, t, rid, uid, changeModerator, closeModal, handleConfirm, room],
[setModal, loggedUserId, loggedUserIsModerator, loggedUserIsOwner, t, rid, uid, toggleModerator, room],
);

const changeModeratorAction = useMutableCallback(() => handleChangeModerator({ roomId: rid, userId: uid }));
const changeModeratorAction = useEffectEvent(() => handleChangeModerator({ roomId: rid, userId: uid }));

const changeModeratorOption = useMemo(
() =>
(isRoomFederated(room) && roomCanSetModerator) || (!isRoomFederated(room) && roomCanSetModerator && userCanSetModerator)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import type { IRoom, IUser } from '@rocket.chat/core-typings';
import { isRoomFederated } from '@rocket.chat/core-typings';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
import { escapeHTML } from '@rocket.chat/string-helpers';
import { useTranslation, usePermission, useUserRoom, useUserSubscription, useSetModal, useUser } from '@rocket.chat/ui-contexts';
import {
useTranslation,
usePermission,
useUserRoom,
useUserSubscription,
useSetModal,
useUser,
useToastMessageDispatch,
useEndpoint,
} from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import type { ReactElement } from 'react';
import React, { useCallback, useMemo } from 'react';

import GenericModal from '../../../../../components/GenericModal';
import { useEndpointAction } from '../../../../../hooks/useEndpointAction';
import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator';
import { getRoomDirectives } from '../../../lib/getRoomDirectives';
import { useUserHasRoomRole } from '../../useUserHasRoomRole';
Expand All @@ -32,17 +41,24 @@ const getWarningModalForFederatedRooms = (
</GenericModal>
);

const getEndpoint = (roomType: string, isOwner: boolean) => {
if (roomType === 'p') {
return isOwner ? '/v1/groups.removeOwner' : '/v1/groups.addOwner';
}
return isOwner ? '/v1/channels.removeOwner' : '/v1/channels.addOwner';
};

export const useChangeOwnerAction = (user: Pick<IUser, '_id' | 'username'>, rid: IRoom['_id']): UserInfoAction | undefined => {
const t = useTranslation();
const room = useUserRoom(rid);
const { _id: uid } = user;
const { _id: uid, username } = user;
const userCanSetOwner = usePermission('set-owner', rid);
const isOwner = useUserHasRoomRole(uid, rid, 'owner');
const userSubscription = useUserSubscription(rid);
const setModal = useSetModal();
const { _id: loggedUserId = '' } = useUser() || {};
const loggedUserIsOwner = useUserHasRoomRole(loggedUserId, rid, 'owner');
const closeModal = useCallback(() => setModal(null), [setModal]);
const dispatchToastMessage = useToastMessageDispatch();

if (!room) {
throw Error('Room not provided');
Expand All @@ -51,55 +67,73 @@ export const useChangeOwnerAction = (user: Pick<IUser, '_id' | 'username'>, rid:
const { roomCanSetOwner } = getRoomDirectives({ room, showingUserId: uid, userSubscription });
const roomName = room?.t && escapeHTML(roomCoordinator.getRoomName(room.t, room));

const endpointPrefix = room.t === 'p' ? '/v1/groups' : '/v1/channels';
const changeOwnerEndpoint = isOwner ? 'removeOwner' : 'addOwner';
const changeOwnerMessage = isOwner ? 'User__username__removed_from__room_name__owners' : 'User__username__is_now_an_owner_of__room_name_';
const changeOwner = useEndpointAction('POST', `${endpointPrefix}.${changeOwnerEndpoint}`, {
successMessage: t(changeOwnerMessage, { username: user.username, room_name: roomName }),
});
const toggleOwnerEndpoint = useEndpoint('POST', getEndpoint(room.t, isOwner));

const handleConfirm = useCallback(() => {
changeOwner({ roomId: rid, userId: uid });
closeModal();
}, [changeOwner, rid, uid, closeModal]);

const handleChangeOwner = useCallback(
({ userId }) => {
if (!isRoomFederated(room)) {
return changeOwner({ roomId: rid, userId: uid });
}
const changingOwnRole = userId === loggedUserId;

if (changingOwnRole && loggedUserIsOwner) {
return setModal(() =>
getWarningModalForFederatedRooms(
closeModal,
handleConfirm,
t('Federation_Matrix_losing_privileges'),
t('Yes_continue'),
t('Federation_Matrix_losing_privileges_warning'),
),
);
}

if (!changingOwnRole && loggedUserIsOwner) {
return setModal(() =>
getWarningModalForFederatedRooms(
closeModal,
handleConfirm,
t('Warning'),
t('Yes_continue'),
t('Federation_Matrix_giving_same_permission_warning'),
),
);
}

changeOwner({ roomId: rid, userId: uid });
const toggleOwnerMutation = useMutation({
mutationFn: useCallback(
async ({ roomId, userId }) => {
await toggleOwnerEndpoint({ roomId, userId });

return t(isOwner ? 'User__username__removed_from__room_name__owners' : 'User__username__is_now_an_owner_of__room_name_', {
username,
room_name: roomName,
});
},
[toggleOwnerEndpoint, t, isOwner, username, roomName],
),
onSuccess: (message) => {
dispatchToastMessage({ type: 'success', message });
},
[setModal, loggedUserId, loggedUserIsOwner, t, rid, uid, changeOwner, closeModal, handleConfirm, room],
);
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
});

const handleChangeOwner = useCallback(() => {
if (!isRoomFederated(room)) {
return toggleOwnerMutation.mutateAsync({ roomId: rid, userId: uid });
}

const changingOwnRole = uid === loggedUserId;

const closeModal = () => {
setModal(null);
};

const handleConfirm = () => {
toggleOwnerMutation.mutateAsync({ roomId: rid, userId: uid });
closeModal();
};

if (changingOwnRole && loggedUserIsOwner) {
return setModal(() =>
getWarningModalForFederatedRooms(
closeModal,
handleConfirm,
t('Federation_Matrix_losing_privileges'),
t('Yes_continue'),
t('Federation_Matrix_losing_privileges_warning'),
),
);
}

if (!changingOwnRole && loggedUserIsOwner) {
return setModal(() =>
getWarningModalForFederatedRooms(
closeModal,
handleConfirm,
t('Warning'),
t('Yes_continue'),
t('Federation_Matrix_giving_same_permission_warning'),
),
);
}

toggleOwnerMutation.mutateAsync({ roomId: rid, userId: uid });
}, [room, loggedUserId, loggedUserIsOwner, toggleOwnerMutation, rid, uid, t, setModal]);

const changeOwnerAction = useEffectEvent(async () => handleChangeOwner());

const changeOwnerAction = useMutableCallback(async () => handleChangeOwner({ roomId: rid, userId: uid }));
const changeOwnerOption = useMemo(
() =>
(isRoomFederated(room) && roomCanSetOwner) || (!isRoomFederated(room) && roomCanSetOwner && userCanSetOwner)
Expand Down

0 comments on commit 86a21b5

Please sign in to comment.