Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/gentle-dingos-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': major
---

Removes deprecated `setAdminStatus` method
1 change: 0 additions & 1 deletion apps/meteor/app/lib/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import './methods/saveSetting';
import './methods/saveSettings';
import './methods/sendMessage';
import './methods/sendSMTPTestEmail';
import './methods/setAdminStatus';
import './methods/setEmail';
import './methods/setRealName';
import './methods/unarchiveRoom';
Expand Down
48 changes: 0 additions & 48 deletions apps/meteor/app/lib/server/methods/setAdminStatus.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const UsersTableRow = ({
const isActive = user.active;
const isFederatedUser = !!user.federated;

const changeAdminStatusAction = useChangeAdminStatusAction(userId, isAdmin, onReload);
const changeAdminStatusAction = useChangeAdminStatusAction(username, isAdmin, onReload);
const changeUserStatusAction = useChangeUserStatusAction(userId, isActive, onReload);
const deleteUserAction = useDeleteUserAction(userId, onReload, onReload);
const resetTOTPAction = useResetTOTPAction(userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const useAdminUserInfoActions = ({
const canDirectMessage = usePermission('create-d');
const canEditOtherUserInfo = usePermission('edit-other-user-info');

const changeAdminStatusAction = useChangeAdminStatusAction(userId, isAdmin, onChange);
const changeAdminStatusAction = useChangeAdminStatusAction(username, isAdmin, onChange);
const changeUserStatusAction = useChangeUserStatusAction(userId, isActive, onChange);
const deleteUserAction = useDeleteUserAction(userId, onChange, onReload);
const resetTOTPAction = useResetTOTPAction(userId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
import type { IUser } from '@rocket.chat/core-typings';
import { useToastMessageDispatch, useMethod, useTranslation, usePermission } from '@rocket.chat/ui-contexts';
import { useToastMessageDispatch, usePermission, useEndpoint } from '@rocket.chat/ui-contexts';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';

import type { AdminUserAction } from './useAdminUserInfoActions';

export const useChangeAdminStatusAction = (userId: IUser['_id'], isAdmin: boolean, onChange: () => void): AdminUserAction | undefined => {
const t = useTranslation();
export const useChangeAdminStatusAction = (
username: IUser['username'] = '',
isAdmin: boolean,
onChange: () => void,
): AdminUserAction | undefined => {
Comment on lines +8 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add validation for username parameter.

The username parameter is typed as IUser['username'], which is string | undefined based on the IUser type definition. While it defaults to an empty string, the function should validate that username is non-empty before attempting to call the role endpoints.

Apply this diff to add validation:

 export const useChangeAdminStatusAction = (
 	username: IUser['username'] = '',
 	isAdmin: boolean,
 	onChange: () => void,
 ): AdminUserAction | undefined => {
 	const { t } = useTranslation();
 	const dispatchToastMessage = useToastMessageDispatch();
 	const addUserToRoleEndpoint = useEndpoint('POST', '/v1/roles.addUserToRole');
 	const removeUserFromRoleEndpoint = useEndpoint('POST', '/v1/roles.removeUserFromRole');

 	const canAssignAdminRole = usePermission('assign-admin-role');

 	const changeAdminStatus = useCallback(async () => {
+		if (!username) {
+			dispatchToastMessage({ type: 'error', message: t('error-invalid-user') });
+			return;
+		}
+
 		try {
 			if (isAdmin) {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/meteor/client/views/admin/users/hooks/useChangeAdminStatusAction.ts
around lines 8–12, the function accepts username typed as IUser['username']
(string | undefined) and defaults to '' but does not validate it; add an
explicit guard that treats empty string or undefined username as invalid and
return undefined (no action) before constructing or calling any role endpoints,
and update any internal usage to rely on that guard so no network calls are
attempted with a falsy username.

const { t } = useTranslation();
const dispatchToastMessage = useToastMessageDispatch();
const setAdminStatus = useMethod('setAdminStatus');
const addUserToRoleEndpoint = useEndpoint('POST', '/v1/roles.addUserToRole');
const removeUserFromRoleEndpoint = useEndpoint('POST', '/v1/roles.removeUserFromRole');

const canAssignAdminRole = usePermission('assign-admin-role');

const changeAdminStatus = useCallback(async () => {
try {
await setAdminStatus(userId, !isAdmin);
const message = isAdmin ? 'User_is_no_longer_an_admin' : 'User_is_now_an_admin';
dispatchToastMessage({ type: 'success', message: t(message) });
if (isAdmin) {
await removeUserFromRoleEndpoint({ roleId: 'admin', username });
dispatchToastMessage({ type: 'info', message: t('User_is_no_longer_an_admin') });
onChange();
return;
}
await addUserToRoleEndpoint({ roleId: 'admin', username });
dispatchToastMessage({ type: 'success', message: t('User_is_now_an_admin') });
onChange();
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
}, [userId, dispatchToastMessage, isAdmin, onChange, setAdminStatus, t]);
}, [isAdmin, removeUserFromRoleEndpoint, username, dispatchToastMessage, addUserToRoleEndpoint, t, onChange]);
Comment on lines 13 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix error message handling in catch block.

At line 32, the error object is passed directly to dispatchToastMessage as the message. Toast messages expect a string, but error might be an Error object or have a different structure.

Apply this diff to properly extract the error message:

 		} catch (error) {
-			dispatchToastMessage({ type: 'error', message: error });
+			dispatchToastMessage({ type: 'error', message: error instanceof Error ? error.message : String(error) });
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const changeAdminStatus = useCallback(async () => {
try {
await setAdminStatus(userId, !isAdmin);
const message = isAdmin ? 'User_is_no_longer_an_admin' : 'User_is_now_an_admin';
dispatchToastMessage({ type: 'success', message: t(message) });
if (isAdmin) {
await removeUserFromRoleEndpoint({ roleId: 'admin', username });
dispatchToastMessage({ type: 'info', message: t('User_is_no_longer_an_admin') });
onChange();
return;
}
await addUserToRoleEndpoint({ roleId: 'admin', username });
dispatchToastMessage({ type: 'success', message: t('User_is_now_an_admin') });
onChange();
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
}, [userId, dispatchToastMessage, isAdmin, onChange, setAdminStatus, t]);
}, [isAdmin, removeUserFromRoleEndpoint, username, dispatchToastMessage, addUserToRoleEndpoint, t, onChange]);
const changeAdminStatus = useCallback(async () => {
try {
if (isAdmin) {
await removeUserFromRoleEndpoint({ roleId: 'admin', username });
dispatchToastMessage({ type: 'info', message: t('User_is_no_longer_an_admin') });
onChange();
return;
}
await addUserToRoleEndpoint({ roleId: 'admin', username });
dispatchToastMessage({ type: 'success', message: t('User_is_now_an_admin') });
onChange();
} catch (error) {
dispatchToastMessage({ type: 'error', message: error instanceof Error ? error.message : String(error) });
}
}, [isAdmin, removeUserFromRoleEndpoint, username, dispatchToastMessage, addUserToRoleEndpoint, t, onChange]);
🤖 Prompt for AI Agents
In apps/meteor/client/views/admin/users/hooks/useChangeAdminStatusAction.ts
around lines 20 to 34, the catch block passes the raw error object to
dispatchToastMessage which expects a string; change it to extract a safe message
string (for example use error?.message ?? String(error) ??
t('Something_went_wrong')) and pass that as the message value in
dispatchToastMessage({ type: 'error', message: <extracted string> }) so the
toast always receives a string; keep the rest of the catch logic unchanged.


return canAssignAdminRole
? {
Expand Down
Loading