diff --git a/src/actions/userManagement.js b/src/actions/userManagement.js index c5f008167b..5ec1161f6a 100644 --- a/src/actions/userManagement.js +++ b/src/actions/userManagement.js @@ -203,8 +203,7 @@ export const buildUpdatedUserLifecycleDetails = (user, payload) => { }; const buildBackendPayload = (userDetails, action) => { - console.log('Building backend payload with:', { userDetails, action }); - switch (action){ + switch (action) { case UserStatusOperations.ACTIVATE: return { action: action, @@ -225,7 +224,7 @@ const buildBackendPayload = (userDetails, action) => { case UserStatusOperations.PAUSE: return { action: action, - reactivationDate: userDetails.reactivationDate + reactivationDate: userDetails.reactivationDate, }; default: throw new Error(`Unknown lifecycle action: ${action}`); @@ -233,21 +232,61 @@ const buildBackendPayload = (userDetails, action) => { }; export const updateUserLifecycle = (updatedUser, payload) => { - return async dispatch => { + return async (dispatch, getState) => { + const { auth } = getState(); dispatch(userProfileUpdateAction(updatedUser)); - - const backendPayload = buildBackendPayload(updatedUser, payload.action); + const requestor = { + requestorId: auth.user.userid, + role: auth.user.role, + permissions: auth.user.permissions, + }; + const backendPayload = { + ...buildBackendPayload(updatedUser, payload.action), + requestor, + }; try { - // console.log('Sending PATCH request to update user lifecycle'); - await axios.patch(ENDPOINTS.USER_PROFILE(updatedUser._id), backendPayload); - + await axios.patch(ENDPOINTS.USER_PROFILE_FIXED(updatedUser._id), backendPayload); } catch (error) { toast.error('Error updating user lifecycle:', error); dispatch(userProfileUpdateAction(payload.originalUser)); throw error; } }; -} +}; + +/** + * Update the pause/resume status of a user via the dedicated pause endpoint. + * Requires the 'interactWithPauseUserButton' permission. + * @param {*} user - the user to be paused or resumed + * @param {string} status - UserStatus.Active or UserStatus.Inactive + * @param {*} reactivationDate - the date on which the user should be reactivated + */ +export const updateUserPauseStatus = (user, status, reactivationDate) => { + return async (dispatch, getState) => { + const userProfile = { ...user }; + userProfile.isActive = status === UserStatus.Active; + userProfile.reactivationDate = reactivationDate; + const auth = getState().auth; + const requestor = { + requestorId: auth.user.userid, + role: auth.user.role, + permissions: auth.user.permissions, + email: auth.user.email, + }; + const patchData = { + status, + reactivationDate: status === UserStatus.Active ? undefined : reactivationDate, + requestor, + }; + try { + await axios.patch(ENDPOINTS.USER_PAUSE(user._id), patchData); + dispatch(userProfileUpdateAction(userProfile)); + } catch (error) { + toast.error('Error updating user pause status:', error); + throw error; + } + }; +}; /** * Update the rehireable status of a user @@ -406,4 +445,4 @@ export const changePagination = value => dispatch => { export const updateUserInfomation = value => dispatch => { dispatch({ type: START_USER_INFO_UPDATE, payload: value }); -}; \ No newline at end of file +}; diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 30588b3099..6115656e20 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -111,7 +111,8 @@ export function Header(props) { props.hasPermission('deleteUserProfile', !isAuthUser ) || props.hasPermission('changeUserStatus', !isAuthUser ) || props.hasPermission('getUserProfiles', !isAuthUser ) || - props.hasPermission('setFinalDay', !isAuthUser); + props.hasPermission('setFinalDay', !isAuthUser) || + props.hasPermission('interactWithPauseUserButton', !isAuthUser); // Badges const canAccessBadgeManagement = diff --git a/src/components/PermissionsManagement/Permissions.json b/src/components/PermissionsManagement/Permissions.json index 6505d78da8..73db6fcbc7 100644 --- a/src/components/PermissionsManagement/Permissions.json +++ b/src/components/PermissionsManagement/Permissions.json @@ -100,6 +100,11 @@ "key": "toggleInvisibility", "description": "Gives the user permission to change the invisibility toggle for themselves and others" }, + { + "label": "Interact with Pause User button", + "key": "interactWithPauseUserButton", + "description": "Allows the user to view and interact with the Pause/Resume button on a user profile. \"User Profile\" -> \"Basic Information\" -> \"Status\" -> \"Pause/Resume\"" + }, { "label": "Assign Blue Squares", "key": "addInfringements", @@ -140,11 +145,6 @@ "key": "changeUserRehireableStatus", "description": "Gives the user permission to change the user status of rehireable or not." }, - { - "label": "Pause User Activity", - "key": "pauseUserActivity", - "description": "Gives the user permission to use the \"Pause\" button to pause user activity on their profile page." - }, { "label": "Set Final Day", "key": "setFinalDay", diff --git a/src/components/UserManagement/PauseAndResumeButton.jsx b/src/components/UserManagement/PauseAndResumeButton.jsx index 8f1b94befa..6789123b6e 100644 --- a/src/components/UserManagement/PauseAndResumeButton.jsx +++ b/src/components/UserManagement/PauseAndResumeButton.jsx @@ -6,7 +6,7 @@ import { PAUSE, RESUME, PROCESSING } from '../../languages/en/ui'; import { UserStatus } from '../../utils/enums'; import ActivationDatePopup from './ActivationDatePopup'; import { boxStyle, boxStyleDark } from '../../styles'; -import { pauseUserAction, activateUserAction } from '../../actions/userLifecycleActions'; +import { updateUserPauseStatus } from '../../actions/userManagement'; /** * @param {*} props @@ -34,21 +34,19 @@ function PauseAndResumeButton(props) { * Call back on Pause confirmation button click to trigger the action to update user status */ const pauseUser = async reActivationDate => { - setIsLoading(true); // Start loading indicator + setIsLoading(true); try { - await pauseUserAction(dispatch, props.userProfile, reActivationDate, props.loadUserProfile); + await dispatch(updateUserPauseStatus(props.userProfile, UserStatus.Inactive, reActivationDate)); setIsActive(false); setActivationDateOpen(false); - - // Optimistically update the UI toast.success('Your Changes were saved successfully.'); } catch (error) { toast.error('Failed to update the user status.'); // eslint-disable-next-line no-console console.error(error); } finally { - setIsLoading(false); // Stop loading indicator - await props.loadUserProfile(); // Ensure state sync + setIsLoading(false); + await props.loadUserProfile(); } }; @@ -57,20 +55,18 @@ function PauseAndResumeButton(props) { */ const onPauseResumeClick = async (user, status) => { if (status === UserStatus.Active) { - setIsLoading(true); // Start loading indicator + setIsLoading(true); try { - await activateUserAction(dispatch, props.userProfile, props.loadUserProfile); + await dispatch(updateUserPauseStatus(props.userProfile, UserStatus.Active, Date.now())); setIsActive(true); - - // Optimistically update the UI toast.success('Your Changes were saved successfully.'); } catch (error) { toast.error('Failed to update the user status.'); // eslint-disable-next-line no-console console.error(error); } finally { - setIsLoading(false); // Stop loading indicator - await props.loadUserProfile(); // Ensure state sync + setIsLoading(false); + await props.loadUserProfile(); } } else { setActivationDateOpen(true); diff --git a/src/components/UserManagement/UserManagement.jsx b/src/components/UserManagement/UserManagement.jsx index 676ef2554e..59f19c0db7 100644 --- a/src/components/UserManagement/UserManagement.jsx +++ b/src/components/UserManagement/UserManagement.jsx @@ -21,6 +21,7 @@ import { deleteUser, enableEditUserInfo, disableEditUserInfo, + updateUserPauseStatus, } from '../../actions/userManagement'; import UserTableHeader from './UserTableHeader'; import UserTableData from './UserTableData'; @@ -41,8 +42,6 @@ import SetupNewUserPopup from './setupNewUserPopup'; import { getAllTimeOffRequests } from '../../actions/timeOffRequestAction'; import { scheduleDeactivationAction, - activateUserAction, - pauseUserAction, deactivateImmediatelyAction, } from '../../actions/userLifecycleActions'; @@ -217,12 +216,8 @@ class UserManagement extends React.PureComponent { activeInactivePopupOpen: false, }); }} - onCancelScheduledDeactivation={() => - activateUserAction(this.props.dispatch, this.state.selectedUser, this.props.getAllUserProfile) - } - onReactivateUser={() => - activateUserAction(this.props.dispatch, this.state.selectedUser, this.props.getAllUserProfile) - } + onCancelScheduledDeactivation={this.reactivateUser} + onReactivateUser={this.reactivateUser} /> { + await this.props.dispatch(updateUserPauseStatus(user, UserStatus.Active, Date.now())); + await this.props.getAllUserProfile(); + }; + onUserUpdate = (updatedUser) => { const { userProfiles } = this.props.state.allUserProfiles; @@ -466,7 +466,7 @@ class UserManagement extends React.PureComponent { return; } if (status === FinalDay.RemoveFinalDay) { - await activateUserAction(this.props.dispatch, user, this.props.getAllUserProfile); + await this.reactivateUser(user); } else { this.setState({ finalDayDateOpen: true, @@ -494,14 +494,10 @@ class UserManagement extends React.PureComponent { }; pauseUser = async (reactivationDate) => { - // eslint-disable-next-line no-console - console.log('Pausing user with reactivation date:', reactivationDate); - await pauseUserAction( - this.props.dispatch, - this.state.selectedUser, - reactivationDate, - this.props.getAllUserProfile, + await this.props.dispatch( + updateUserPauseStatus(this.state.selectedUser, UserStatus.Inactive, reactivationDate), ); + await this.props.getAllUserProfile(); this.setState({ activationDateOpen: false, diff --git a/src/components/UserManagement/UserTableData.jsx b/src/components/UserManagement/UserTableData.jsx index 624081f941..1a7c2719ca 100644 --- a/src/components/UserManagement/UserTableData.jsx +++ b/src/components/UserManagement/UserTableData.jsx @@ -83,6 +83,7 @@ const UserTableDataComponent = props => { const canDeleteUsers = props.hasPermission('deleteUserProfile'); const resetPasswordStatus = props.hasPermission('updatePassword'); const canChangeUserStatus = props.hasPermission('changeUserStatus'); + const canInteractWithPauseUserButton = props.hasPermission('interactWithPauseUserButton'); const canSetFinalDay = props.hasPermission('setFinalDay'); const canSeeReports = props.hasPermission('getReports'); @@ -416,7 +417,7 @@ const UserTableDataComponent = props => { if (numericValue < 0) { toast.error( - 'If negative hours worked, we’d all be on vacation already. Try again, and be sure weekly hours are set to zero or more.', + "If negative hours worked, we'd all be on vacation already. Try again, and be sure weekly hours are set to zero or more.", ); return; } @@ -434,7 +435,7 @@ const UserTableDataComponent = props => { {/* PAUSE/RESUME */} - {!canChangeUserStatus ? ( + {!canInteractWithPauseUserButton ? ( { onClick={() => { if (cantUpdateDevAdminDetails(props.user.email, props.authEmail)) { // eslint-disable-next-line no-alert - alert('STOP! YOU SHOULDN’T BE TRYING TO CHANGE THIS. Please reconsider your choices.'); + alert("STOP! YOU SHOULDN'T BE TRYING TO CHANGE THIS. Please reconsider your choices."); return; } onReset(true); @@ -462,7 +463,7 @@ const UserTableDataComponent = props => { ...(darkMode ? { boxShadow: '0 0 0 0', fontWeight: 'bold' } : boxStyle), padding: '5px', }} - disabled={!canChangeUserStatus} + disabled={!canInteractWithPauseUserButton} id={`btn-pause-profile-${props.user._id}`} > {getButtonText()} diff --git a/src/components/UserManagement/__tests__/PauseAndResumeButton.test.jsx b/src/components/UserManagement/__tests__/PauseAndResumeButton.test.jsx index 77ee9b08d5..f9dda981f4 100644 --- a/src/components/UserManagement/__tests__/PauseAndResumeButton.test.jsx +++ b/src/components/UserManagement/__tests__/PauseAndResumeButton.test.jsx @@ -1,19 +1,15 @@ -import { screen, waitFor } from '@testing-library/react'; +import { screen, waitFor , render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import PauseAndResumeButton from '../PauseAndResumeButton'; import { PAUSE, RESUME } from '../../../languages/en/ui'; import { userProfileMock } from '../../../__tests__/mockStates'; -import { renderWithProvider } from '../../../__tests__/utils'; import { vi } from 'vitest'; +import { Provider } from 'react-redux'; -import { - pauseUserAction, - activateUserAction, -} from '../../../actions/userLifecycleActions'; +import { updateUserPauseStatus } from '../../../actions/userManagement'; -vi.mock('../../../actions/userLifecycleActions', () => ({ - pauseUserAction: vi.fn(() => Promise.resolve()), - activateUserAction: vi.fn(() => Promise.resolve()), +vi.mock('../../../actions/userManagement', () => ({ + updateUserPauseStatus: vi.fn(() => async () => Promise.resolve()), })); vi.mock('react-toastify', () => ({ @@ -23,11 +19,43 @@ vi.mock('react-toastify', () => ({ }, })); +const createThunkStore = () => ({ + getState: () => ({ + theme: { + darkMode: false, + }, + auth: { + user: { + userid: userProfileMock._id, + role: 'Administrator', + permissions: ['interactWithPauseUserButton'], + email: 'test@example.com', + }, + }, + }), + dispatch: action => + typeof action === 'function' + ? action(() => {}, () => ({})) + : action, + subscribe: () => () => {}, +}); + describe('PauseAndResumeButton', () => { const loadUserProfile = vi.fn(() => Promise.resolve()); + beforeEach(() => { + vi.clearAllMocks(); + }); + + const renderPauseButton = ui => + render(ui, { + wrapper: ({ children }) => ( + {children} + ), + }); + it('renders pause button when user is active', () => { - renderWithProvider( + renderPauseButton( { }); it('opens activation date popup when clicking pause', async () => { - renderWithProvider( + renderPauseButton( { }); it('pauses user and switches button to RESUME', async () => { - renderWithProvider( + renderPauseButton( { ); await waitFor(() => { - expect(pauseUserAction).toHaveBeenCalledTimes(1); + expect(updateUserPauseStatus).toHaveBeenCalled(); expect( screen.getByRole('button', { name: RESUME }) ).toBeInTheDocument(); - }); + }) + expect(updateUserPauseStatus).toHaveBeenCalledWith( + expect.objectContaining({ _id: userProfileMock._id }), + 'Inactive', + expect.anything() + );; }); it('resumes user and switches button back to PAUSE', async () => { - renderWithProvider( + renderPauseButton( { ); await waitFor(() => { - expect(activateUserAction).toHaveBeenCalledTimes(1); + expect(updateUserPauseStatus).toHaveBeenCalled(); expect( screen.getByRole('button', { name: PAUSE }) ).toBeInTheDocument(); - }); + }) + expect(updateUserPauseStatus).toHaveBeenCalledWith( + expect.objectContaining({ _id: userProfileMock._id }), + 'Active', + expect.any(Number) + );; }); }); diff --git a/src/components/UserManagement/__tests__/UserManagement.test.jsx b/src/components/UserManagement/__tests__/UserManagement.test.jsx index 87d472b567..4b8e9c197d 100644 --- a/src/components/UserManagement/__tests__/UserManagement.test.jsx +++ b/src/components/UserManagement/__tests__/UserManagement.test.jsx @@ -1,49 +1,78 @@ import { createBaseProps } from './UserManagementTestSetup.jsx'; -import { screen, fireEvent } from '@testing-library/react'; +import { screen, fireEvent , render } from '@testing-library/react'; import { renderWithProvider } from '../../../__tests__/utils'; import '@testing-library/jest-dom'; +import { Provider } from 'react-redux'; import UserManagement from '../UserManagement'; -import { activateUserAction } from '../../../actions/userLifecycleActions'; +import { updateUserPauseStatus } from '../../../actions/userManagement'; -vi.mock('../../../actions/userLifecycleActions', () => ({ - activateUserAction: vi.fn(), -})); +vi.mock('../../../actions/userManagement', async () => { + const actual = await vi.importActual('../../../actions/userManagement'); + return { + ...actual, + updateUserPauseStatus: vi.fn(() => async () => Promise.resolve()), + }; +}); + +const createThunkStore = () => ({ + getState: () => ({ + theme: { + darkMode: false, + }, + timeOffRequests: { + requests: [], + }, + }), + dispatch: action => + typeof action === 'function' + ? action(() => {}, () => ({})) + : action, + subscribe: () => () => {}, +}); describe('UserManagement Component', () => { let props; beforeEach(() => { props = createBaseProps(); + vi.clearAllMocks(); }); + const renderUserManagement = ui => + render(ui, { + wrapper: ({ children }) => ( + {children} + ), + }); + it('renders without errors', () => { - renderWithProvider(); + renderUserManagement(); expect(screen.getByTestId('user-table-header')).toBeInTheDocument(); expect(screen.getByTestId('user-table-data-0')).toBeInTheDocument(); }); it('calls getAllUserProfile and getAllTimeOffRequests on mount', () => { - renderWithProvider(); + renderUserManagement(); expect(props.getAllUserProfile).toHaveBeenCalled(); expect(props.getAllTimeOffRequests).toHaveBeenCalled(); }); it('opens activation date popup when pausing user', () => { - renderWithProvider(); + renderUserManagement(); fireEvent.click(screen.getByTestId('inactive-button-0')); expect(screen.getByTestId('activation-date-popup')).toBeInTheDocument(); }); - it('calls activateUserAction when resuming user', () => { - renderWithProvider(); + it('calls updateUserPauseStatus when resuming user', () => { + renderUserManagement(); fireEvent.click(screen.getByTestId('pause-resume-button-0')); - expect(activateUserAction).toHaveBeenCalled(); + expect(updateUserPauseStatus).toHaveBeenCalled(); }); it('handles final day action when clicked', () => { - renderWithProvider(); + renderUserManagement(); expect(() => fireEvent.click(screen.getByTestId('final-day-button-0')) @@ -51,7 +80,7 @@ describe('UserManagement Component', () => { }); it('opens new user popup', () => { - renderWithProvider(); + renderUserManagement(); fireEvent.click(screen.getByTestId('new-user-button')); expect(screen.getByTestId('new-user-popup')).toBeInTheDocument(); }); diff --git a/src/components/UserManagement/__tests__/UserTableData.test.jsx b/src/components/UserManagement/__tests__/UserTableData.test.jsx index 77b1010ab8..887a5ae275 100644 --- a/src/components/UserManagement/__tests__/UserTableData.test.jsx +++ b/src/components/UserManagement/__tests__/UserTableData.test.jsx @@ -21,7 +21,7 @@ const jaeAccountMock = { iat: 1597272666, userid: '1', permissions: { - frontPermissions: ['deleteUserProfile', 'updatePassword', 'changeUserStatus'], + frontPermissions: ['deleteUserProfile', 'updatePassword', 'changeUserStatus', 'interactWithPauseUserButton'], backPermissions: [], }, role: 'Administrator', @@ -42,7 +42,7 @@ const nonJaeAccountMock = { iat: 1597272666, userid: '2', permissions: { - frontPermissions: ['deleteUserProfile', 'updatePassword', 'changeUserStatus'], + frontPermissions: ['deleteUserProfile', 'updatePassword', 'changeUserStatus', 'interactWithPauseUserButton'], backPermissions: [], }, role: 'Administrator', @@ -66,7 +66,7 @@ const ownerAccountMock = { iat: 1597272666, userid: '3', permissions: { - frontPermissions: ['deleteUserProfile', 'updatePassword', 'changeUserStatus'], + frontPermissions: ['deleteUserProfile', 'updatePassword', 'changeUserStatus', 'interactWithPauseUserButton'], backPermissions: [], }, role: 'Owner', @@ -78,27 +78,6 @@ const ownerAccountMock = { email: 'devadmin@hgn.net', }; -const setupAxios = (mode) => { - if (mode === 'non-jae') { - axios.get.mockResolvedValue({ - data: [ - { id: 1, name: 'Administrator' }, - { id: 2, name: 'User' }, - ], - }); - } else { - axios.get.mockResolvedValue({ - data: { - _id: jaeAccountMock._id, - firstName: jaeAccountMock.firstName, - lastName: jaeAccountMock.lastName, - role: jaeAccountMock.role, - email: jaeAccountMock.email, - }, - }); - } -}; - const createStore = ({ authState, profileState, roleName }) => mockStore({ auth: authState, @@ -107,7 +86,12 @@ const createStore = ({ authState, profileState, roleName }) => roles: [ { roleName, - permissions: ['deleteUserProfile', 'updatePassword', 'changeUserStatus'], + permissions: [ + 'deleteUserProfile', + 'updatePassword', + 'changeUserStatus', + 'interactWithPauseUserButton', + ], }, ], }, @@ -120,6 +104,28 @@ const createHandlers = () => ({ onActiveInactiveClick: vi.fn(), }); +const setupAxios = mode => { + if (mode === 'non-jae') { + axios.get.mockResolvedValue({ + data: [ + { id: 1, name: 'Administrator' }, + { id: 2, name: 'User' }, + ], + }); + return; + } + + axios.get.mockResolvedValue({ + data: { + _id: jaeAccountMock._id, + firstName: jaeAccountMock.firstName, + lastName: jaeAccountMock.lastName, + role: jaeAccountMock.role, + email: jaeAccountMock.email, + }, + }); +}; + const renderUserRow = ({ store, user, handlers }) => { renderWithProvider( @@ -282,4 +288,4 @@ describe.each([ }); } }); -}); \ No newline at end of file +}); diff --git a/src/components/UserProfile/BasicInformationTab/BasicInformationTab.jsx b/src/components/UserProfile/BasicInformationTab/BasicInformationTab.jsx index d62f1c5197..5e91f7edfa 100644 --- a/src/components/UserProfile/BasicInformationTab/BasicInformationTab.jsx +++ b/src/components/UserProfile/BasicInformationTab/BasicInformationTab.jsx @@ -496,8 +496,7 @@ const BasicInformationTab = props => { const [errorOccurred, setErrorOccurred] = useState(false); const dispatch = useDispatch(); const rolesAllowedToEditStatusFinalDay = ['Administrator', 'Owner']; - const canEditStatus = - rolesAllowedToEditStatusFinalDay.includes(role) || dispatch(hasPermission('pauseUserActivity')); + const canEditStatus = dispatch(hasPermission('interactWithPauseUserButton')); const canEditEndDate = rolesAllowedToEditStatusFinalDay.includes(role) || dispatch(hasPermission('setFinalDay')); @@ -878,7 +877,6 @@ const BasicInformationTab = props => { /> ); - const statusComponent = ( <> diff --git a/src/components/UserProfile/UserProfile.jsx b/src/components/UserProfile/UserProfile.jsx index 081148ff77..84918a7410 100644 --- a/src/components/UserProfile/UserProfile.jsx +++ b/src/components/UserProfile/UserProfile.jsx @@ -2429,4 +2429,3 @@ export default connect( mapStateToProps, { hasPermission, updateUserProfile, getTimeEntriesForWeek } )(UserProfile); - diff --git a/src/utils/URL.js b/src/utils/URL.js index 27204eab5d..8105c76b81 100644 --- a/src/utils/URL.js +++ b/src/utils/URL.js @@ -6,6 +6,7 @@ export const ENDPOINTS = { USER_PROFILE: userId => `${APIEndpoint}/userprofile/${userId}`, USER_PROFILE_FIXED: userId => `${APIEndpoint}/userProfile/${userId}`, USER_PROFILE_PROPERTY: userId => `${APIEndpoint}/userprofile/${userId}/property`, + USER_PAUSE: userId => `${APIEndpoint}/userProfile/${userId}/pause`, USER_PROFILES: `${APIEndpoint}/userprofile/`, UPDATE_REHIREABLE_STATUS: userId => `${APIEndpoint}/userprofile/${userId}/rehireable`, TOGGLE_VISIBILITY: userId => `${APIEndpoint}/userprofile/${userId}/toggleInvisibility`, diff --git a/src/utils/routePermissions.js b/src/utils/routePermissions.js index a3c38f14fa..21c9b24ebd 100644 --- a/src/utils/routePermissions.js +++ b/src/utils/routePermissions.js @@ -5,7 +5,13 @@ const RoutePermissions = { weeklySummariesReport: ['getWeeklySummaries'], prDashboard: ['accessPRTeamDashboard'], weeklyVolunteerSummary: ['getWeeklyVolunteerSummary'], - userManagement: ['getUserProfiles', 'postUserProfile', 'deleteUserProfile', 'changeUserStatus'], + userManagement: [ + 'getUserProfiles', + 'postUserProfile', + 'deleteUserProfile', + 'changeUserStatus', + 'interactWithPauseUserButton', + ], badgeManagement: ['seeBadges', 'createBadges', 'updateBadges', 'deleteBadges', 'assignBadges'], projects: [ 'postProject',