The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Rocket.Chat/apps/meteor/app/lib/server/functions/deleteUser.ts

183 lines
6.0 KiB

import { Apps, AppEvents } from '@rocket.chat/apps';
import { api } from '@rocket.chat/core-services';
import { isUserFederated, type IUser } from '@rocket.chat/core-typings';
import {
Integrations,
FederationServers,
LivechatVisitors,
LivechatDepartmentAgents,
Messages,
Rooms,
Subscriptions,
Users,
ReadReceipts,
LivechatUnitMonitors,
ModerationReports,
} from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import { getSubscribedRoomsForUserWithDetails, shouldRemoveOrChangeOwner } from './getRoomsWithSingleOwner';
import { getUserSingleOwnedRooms } from './getUserSingleOwnedRooms';
import { relinquishRoomOwnerships } from './relinquishRoomOwnerships';
import { updateGroupDMsName } from './updateGroupDMsName';
import { callbacks } from '../../../../server/lib/callbacks';
import { i18n } from '../../../../server/lib/i18n';
import { FileUpload } from '../../../file-upload/server';
import { settings } from '../../../settings/server';
import {
notifyOnRoomChangedById,
notifyOnIntegrationChangedByUserId,
notifyOnLivechatDepartmentAgentChanged,
notifyOnUserChange,
} from '../lib/notifyListener';
export async function deleteUser(userId: string, confirmRelinquish = false, deletedBy?: IUser['_id']): Promise<{ deletedRooms: string[] }> {
if (userId === 'rocket.cat') {
throw new Meteor.Error('error-action-not-allowed', 'Deleting the rocket.cat user is not allowed', {
method: 'deleteUser',
action: 'Delete_user',
});
}
const user = await Users.findOneById(userId, {
projection: { username: 1, avatarOrigin: 1, roles: 1, federated: 1 },
[NEW][BREAK] Message retention policy and pruning (#11236) Closes #6749 Closes #8321 Closes #9374 Closes #2700 Closes #2639 Closes #2355 Closes #1861 Closes #8757 Closes #7228 Closes #10870 Closes #6193 Closes #11299 Closes #11468 Closes #9317 Closes #11300 (will incorporate a fix to this PR's issue) Closes #11046 (will incorporate a fix to this PR's issue) Contributes to #5944 Contributes to #11475 _...and possibly more!_ This PR makes deleting messages (automatically and manually) a lot easier on Rocket.Chat. - [X] Implement a bulk message deletion notification, to quickly push large message deletions to users without reload - [X] Use it in `rooms.cleanHistory` - [X] Use it in user deletions - [X] Completely remove cleanChannelHistory as required by v0.67 - [X] Remove server method `cleanChannelHistory` - [X] Remove REST API `channels.cleanHistory` - [x] Implement a sidebar option to clean history - [x] Basic implementation - [x] Allow excluding pinned messages - [x] Allow attachment-only mode - [x] Allow specifying user(s) to narrow down to - [x] Also update REST API - [x] Also update docs - [x] Break the deletion into multiple different requests, so the client can keep track of progress - [x] Clear animation / progress bar for deleting - [x] Retention policy - [X] Global, set by admin - [X] Global timer that runs every second and deletes messages over the set limit - [X] Can change its timer's resolution to prevent insane CPU overhead - [X] Admin can decide what room types to target (channels, groups and/or DMs) - [X] Allow excluding pinned messages - [X] Allow attachment-only mode - [x] Per-channel, set by those with a new permission - [x] Disabled when master switch off - [x] Set in channel info - [x] Can override global policy with a switch that requires `edit-privileged-setting` - [x] Allow excluding pinned messages - [x] Allow attachment-only mode - [x] Uses same global timer for cleanup - [X] Message at start of channel history / in channel info if there is a retention policy set - [x] Message in channel info if there is a retention policy set on that channel specifically - [X] Make cleaning history also delete files (completely!) - [X] Manual purging - [X] Automatic purging - [x] Make other deletions also delete files - [x] User deletion - [X] Own messages - [x] DMs with them's partner messages - [x] Room deletion - [x] Cleanup - [x] Finish related [docs](https://github.com/RocketChat/docs/pull/815) - [x] Link to the docs in the settings Please suggest any cool changes/additions! Any support is greatly appreciated. **Breaking change:** This PR removes REST API endpoint `channels.cleanHistory` and Meteor callable `cleanChannelHistory` as per the protocol specified for them. ![bzzzzzzzz](https://user-images.githubusercontent.com/39674991/41799087-56d1dea0-7670-11e8-94c0-bc534b1f832d.png)
8 years ago
});
if (!user) {
return { deletedRooms: [] };
}
if (isUserFederated(user)) {
throw new Meteor.Error('error-not-allowed', 'User participated in federation, this user can only be deactivated permanently', {
method: 'deleteUser',
});
}
const subscribedRooms = await getSubscribedRoomsForUserWithDetails(userId);
if (shouldRemoveOrChangeOwner(subscribedRooms) && !confirmRelinquish) {
const rooms = await getUserSingleOwnedRooms(subscribedRooms);
throw new Meteor.Error('user-last-owner', '', rooms);
}
let deletedRooms: string[] = [];
// Users without username can't do anything, so there is nothing to remove
if (user.username != null) {
let userToReplaceWhenUnlinking: IUser | null = null;
const nameAlias = i18n.t('Removed_User');
deletedRooms = await relinquishRoomOwnerships(userId, subscribedRooms, true);
const messageErasureType = settings.get<'Delete' | 'Unlink' | 'Keep'>('Message_ErasureType');
switch (messageErasureType) {
[NEW][BREAK] Message retention policy and pruning (#11236) Closes #6749 Closes #8321 Closes #9374 Closes #2700 Closes #2639 Closes #2355 Closes #1861 Closes #8757 Closes #7228 Closes #10870 Closes #6193 Closes #11299 Closes #11468 Closes #9317 Closes #11300 (will incorporate a fix to this PR's issue) Closes #11046 (will incorporate a fix to this PR's issue) Contributes to #5944 Contributes to #11475 _...and possibly more!_ This PR makes deleting messages (automatically and manually) a lot easier on Rocket.Chat. - [X] Implement a bulk message deletion notification, to quickly push large message deletions to users without reload - [X] Use it in `rooms.cleanHistory` - [X] Use it in user deletions - [X] Completely remove cleanChannelHistory as required by v0.67 - [X] Remove server method `cleanChannelHistory` - [X] Remove REST API `channels.cleanHistory` - [x] Implement a sidebar option to clean history - [x] Basic implementation - [x] Allow excluding pinned messages - [x] Allow attachment-only mode - [x] Allow specifying user(s) to narrow down to - [x] Also update REST API - [x] Also update docs - [x] Break the deletion into multiple different requests, so the client can keep track of progress - [x] Clear animation / progress bar for deleting - [x] Retention policy - [X] Global, set by admin - [X] Global timer that runs every second and deletes messages over the set limit - [X] Can change its timer's resolution to prevent insane CPU overhead - [X] Admin can decide what room types to target (channels, groups and/or DMs) - [X] Allow excluding pinned messages - [X] Allow attachment-only mode - [x] Per-channel, set by those with a new permission - [x] Disabled when master switch off - [x] Set in channel info - [x] Can override global policy with a switch that requires `edit-privileged-setting` - [x] Allow excluding pinned messages - [x] Allow attachment-only mode - [x] Uses same global timer for cleanup - [X] Message at start of channel history / in channel info if there is a retention policy set - [x] Message in channel info if there is a retention policy set on that channel specifically - [X] Make cleaning history also delete files (completely!) - [X] Manual purging - [X] Automatic purging - [x] Make other deletions also delete files - [x] User deletion - [X] Own messages - [x] DMs with them's partner messages - [x] Room deletion - [x] Cleanup - [x] Finish related [docs](https://github.com/RocketChat/docs/pull/815) - [x] Link to the docs in the settings Please suggest any cool changes/additions! Any support is greatly appreciated. **Breaking change:** This PR removes REST API endpoint `channels.cleanHistory` and Meteor callable `cleanChannelHistory` as per the protocol specified for them. ![bzzzzzzzz](https://user-images.githubusercontent.com/39674991/41799087-56d1dea0-7670-11e8-94c0-bc534b1f832d.png)
8 years ago
case 'Delete':
const store = FileUpload.getStore('Uploads');
const cursor = Messages.findFilesByUserId(userId);
for await (const { file } of cursor) {
if (!file) {
continue;
}
await store.deleteById(file._id);
}
await Messages.removeByUserId(userId);
await ReadReceipts.removeByUserId(userId);
await ModerationReports.hideMessageReportsByUserId(
userId,
deletedBy || userId,
deletedBy === userId ? 'user deleted own account' : 'user account deleted',
'DELETE_USER',
);
break;
[NEW][BREAK] Message retention policy and pruning (#11236) Closes #6749 Closes #8321 Closes #9374 Closes #2700 Closes #2639 Closes #2355 Closes #1861 Closes #8757 Closes #7228 Closes #10870 Closes #6193 Closes #11299 Closes #11468 Closes #9317 Closes #11300 (will incorporate a fix to this PR's issue) Closes #11046 (will incorporate a fix to this PR's issue) Contributes to #5944 Contributes to #11475 _...and possibly more!_ This PR makes deleting messages (automatically and manually) a lot easier on Rocket.Chat. - [X] Implement a bulk message deletion notification, to quickly push large message deletions to users without reload - [X] Use it in `rooms.cleanHistory` - [X] Use it in user deletions - [X] Completely remove cleanChannelHistory as required by v0.67 - [X] Remove server method `cleanChannelHistory` - [X] Remove REST API `channels.cleanHistory` - [x] Implement a sidebar option to clean history - [x] Basic implementation - [x] Allow excluding pinned messages - [x] Allow attachment-only mode - [x] Allow specifying user(s) to narrow down to - [x] Also update REST API - [x] Also update docs - [x] Break the deletion into multiple different requests, so the client can keep track of progress - [x] Clear animation / progress bar for deleting - [x] Retention policy - [X] Global, set by admin - [X] Global timer that runs every second and deletes messages over the set limit - [X] Can change its timer's resolution to prevent insane CPU overhead - [X] Admin can decide what room types to target (channels, groups and/or DMs) - [X] Allow excluding pinned messages - [X] Allow attachment-only mode - [x] Per-channel, set by those with a new permission - [x] Disabled when master switch off - [x] Set in channel info - [x] Can override global policy with a switch that requires `edit-privileged-setting` - [x] Allow excluding pinned messages - [x] Allow attachment-only mode - [x] Uses same global timer for cleanup - [X] Message at start of channel history / in channel info if there is a retention policy set - [x] Message in channel info if there is a retention policy set on that channel specifically - [X] Make cleaning history also delete files (completely!) - [X] Manual purging - [X] Automatic purging - [x] Make other deletions also delete files - [x] User deletion - [X] Own messages - [x] DMs with them's partner messages - [x] Room deletion - [x] Cleanup - [x] Finish related [docs](https://github.com/RocketChat/docs/pull/815) - [x] Link to the docs in the settings Please suggest any cool changes/additions! Any support is greatly appreciated. **Breaking change:** This PR removes REST API endpoint `channels.cleanHistory` and Meteor callable `cleanChannelHistory` as per the protocol specified for them. ![bzzzzzzzz](https://user-images.githubusercontent.com/39674991/41799087-56d1dea0-7670-11e8-94c0-bc534b1f832d.png)
8 years ago
case 'Unlink':
userToReplaceWhenUnlinking = await Users.findOneById('rocket.cat');
if (!userToReplaceWhenUnlinking?._id || !userToReplaceWhenUnlinking?.username) {
break;
}
await Messages.unlinkUserId(userId, userToReplaceWhenUnlinking?._id, userToReplaceWhenUnlinking?.username, nameAlias);
break;
}
await Rooms.updateGroupDMsRemovingUsernamesByUsername(user.username, userId); // Remove direct rooms with the user
await Rooms.removeDirectRoomContainingUsername(user.username); // Remove direct rooms with the user
const rids = subscribedRooms.map((room) => room.rid);
void notifyOnRoomChangedById(rids);
await Subscriptions.removeByUserId(userId);
// Remove user as livechat agent
if (user.roles.includes('livechat-agent')) {
const departmentAgents = await LivechatDepartmentAgents.findByAgentId(userId).toArray();
const { deletedCount } = await LivechatDepartmentAgents.removeByAgentId(userId);
if (deletedCount > 0) {
departmentAgents.forEach((depAgent) => {
void notifyOnLivechatDepartmentAgentChanged(
{
_id: depAgent._id,
agentId: userId,
departmentId: depAgent.departmentId,
},
'removed',
);
});
}
}
if (user.roles.includes('livechat-monitor')) {
// Remove user as Unit Monitor
await LivechatUnitMonitors.removeByMonitorId(userId);
}
// This is for compatibility. Since we allowed any user to be contact manager b4, we need to have the same logic
// for deletion.
await LivechatVisitors.removeContactManagerByUsername(user.username);
// removes user's avatar
[FIX] User avatar reseting and getting random image (#25603) <!-- This is a pull request template, you do not need to uncomment or remove the comments, they won't show up in the PR text. --> <!-- Your Pull Request name should start with one of the following tags [NEW] For new features [IMPROVE] For an improvement (performance or little improvements) in existing features [FIX] For bug fixes that affect the end-user [BREAK] For pull requests including breaking changes Chore: For small tasks Doc: For documentation --> <!-- Checklist!!! If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code. - I have read the Contributing Guide - https://github.com/RocketChat/Rocket.Chat/blob/develop/.github/CONTRIBUTING.md#contributing-to-rocketchat doc - I have signed the CLA - https://cla-assistant.io/RocketChat/Rocket.Chat - Lint and unit tests pass locally with my changes - I have added tests that prove my fix is effective or that my feature works (if applicable) - I have added necessary documentation (if applicable) - Any dependent changes have been merged and published in downstream modules --> ## Proposed changes (including videos or screenshots) <!-- CHANGELOG --> <!-- Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue below. This description will appear in the release notes if we accept the contribution. --> - resolve user avatar not being saved after editing the user profile issue - resolve user avatar not getting another user picture due to database deletion error <!-- END CHANGELOG --> ## Issue(s) <!-- Link the issues being closed by or related to this PR. For example, you can use #594 if this PR closes issue number 594 --> ## Steps to test or reproduce <!-- Mention how you would reproduce the bug if not mentioned on the issue page already. Also mention which screens are going to have the changes if applicable --> 1. As a user log in to the app 2. Click on Avatar/My account 3. Change the username 4. Click on `Save changes` -> Should not change the avatar image 6. Logout and create a new user on the same server 7. Repeat steps 1 to 4 -> Should not change the avatar image as well ## Further comments <!-- If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... --> Co-authored-by: Filipe Marins <9275105+filipemarins@users.noreply.github.com> Co-authored-by: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com>
4 years ago
if (user.avatarOrigin === 'upload' || user.avatarOrigin === 'url' || user.avatarOrigin === 'rest') {
await FileUpload.getStore('Avatars').deleteByName(user.username);
}
// Disables all the integrations which rely on the user being deleted.
await Integrations.disableByUserId(userId);
void notifyOnIntegrationChangedByUserId(userId);
// Don't broadcast user.deleted for Erasure Type of 'Keep' so that messages don't disappear from logged in sessions
if (messageErasureType === 'Delete') {
void api.broadcast('user.deleted', user, {
messageErasureType,
});
}
if (messageErasureType === 'Unlink' && userToReplaceWhenUnlinking) {
void api.broadcast('user.deleted', user, {
messageErasureType,
replaceByUser: { _id: userToReplaceWhenUnlinking._id, username: userToReplaceWhenUnlinking?.username, alias: nameAlias },
});
}
}
Enhance outgoing webhooks and add history (#5823) * Convert the majority of the integrations package to JavaScript * Move the trigger handler to it's own class * Start trying to generalize integration items * Yay, additional events trigger outgoing webhooks * Silence codacy and fix eslint problems. * Started work on user created event for outgoing integrations * Finish the outgoing integration work on the user created event. * Add user join and leave room events for outgoing webhooks * Add fields to the rest api integration creation and clean up the processWebhookMessage * Add the HTTP to the incoming webhook context * Don't check for property on result if it isn't there. Closes #4175, #5762, and #5896. * Add archive room and file upload events for the webhooks * Disable integrations when the user to run/post as gets deleted. * Try to fix the tests failing due to the requird events property * Add history of integration which get fired * Add the missing file for the IntegrationHistory * Fix deleting users being broke due to my code * Add the outgoing webhook integration history viewing page along with v1 rest api to retrieve it * Integration history replays are now enabled along with advanced settings * Work on the advanced settings and enable paging on the integration history * Enable i18n for the history and advanced settings * Update the wording on the word placement * Move migration to be 88 now. * Add missing translations for the webhooks * Fix en.i18n.json identation * Fix integrations.html indentation * Fix more identations * Fix identation of integrationsOutgoing.html
9 years ago
// Remove user from users database
await Users.removeById(userId);
// App IPostUserDeleted event hook
if (deletedBy) {
await Apps.self?.triggerEvent(AppEvents.IPostUserDeleted, { user, performedBy: await Users.findOneById(deletedBy) });
}
// update name and fname of group direct messages
await updateGroupDMsName(user);
// Refresh the servers list
await FederationServers.refreshServers();
void notifyOnUserChange({ clientAction: 'removed', id: user._id });
await callbacks.run('afterDeleteUser', user);
return { deletedRooms };
}