Add DELETE /users/:identifier endpoint

This commit is contained in:
ricardo 2022-03-28 15:49:03 -04:00
parent 1eb5c4dacf
commit 97603b99ee
5 changed files with 119 additions and 8 deletions

View file

@ -49,6 +49,8 @@ export const connectionName = (): string => {
return 'default';
};
export const clean = (users: User[]): Array<Partial<User>> => {
return users.map((user) => pick(user, getSelectableProperties('user')));
export const clean = (users: User[], keepRole = false): Array<Partial<User>> => {
return users.map((user) =>
pick(user, getSelectableProperties('user').concat(keepRole ? ['globalRole'] : [])),
);
};

View file

@ -173,11 +173,19 @@ paths:
- name: transferId
in: query
description: ID of the user to transfer workflows and credentials to.
required: true
required: false
style: form
explode: true
schema:
type: string
- name: includeRole
in: query
required: false
style: form
explode: true
schema:
type: string
example: true
responses:
"200":
description: User deleted successfully

View file

@ -19,9 +19,17 @@ import config = require('../../../../../config');
import * as UserManagementMailer from '../../../../UserManagement/email/UserManagementMailer';
import { Db, ResponseHelper, InternalHooksManager } from '../../../..';
import {
Db,
ResponseHelper,
InternalHooksManager,
ActiveWorkflowRunner,
ITelemetryUserDeletionData,
} from '../../../..';
import { Role } from '../../../../databases/entities/Role';
import { getInstanceBaseUrl } from '../../../../UserManagement/UserManagementHelper';
import { SharedWorkflow } from '../../../../databases/entities/SharedWorkflow';
import { SharedCredentials } from '../../../../databases/entities/SharedCredentials';
export = {
createUsers: async (req: UserRequest.Invite, res: express.Response): Promise<void> => {
@ -156,7 +164,100 @@ export = {
res.json([...clean(existingUsers ?? []), ...clean(savedUsers)]);
},
deleteUser: async (req: UserRequest.Delete, res: express.Response): Promise<void> => {
res.json({ success: true });
const { identifier: idToDelete } = req.params;
const includeRole = req.query?.includeRole?.toLowerCase() === 'true' || false;
if (req.user.id === idToDelete) {
throw new ResponseHelper.ResponseError('Cannot delete your own user', undefined, 400);
}
const { transferId } = req.query;
if (transferId === idToDelete) {
throw new ResponseHelper.ResponseError(
'Request to delete a user failed because the user to delete and the transferee are the same user',
undefined,
400,
);
}
const users = await Db.collections.User?.find({
where: { id: In([transferId, idToDelete]) },
relations: includeRole ? ['globalRole'] : undefined,
});
if (!users?.length || (transferId && users.length !== 2)) {
throw new ResponseHelper.ResponseError(
'Request to delete a user failed because the ID of the user to delete and/or the ID of the transferee were not found in DB',
undefined,
404,
);
}
const userToDelete = users.find((user) => user.id === req.params.identifier) as User;
if (transferId) {
const transferee = users.find((user) => user.id === transferId);
await Db.transaction(async (transactionManager) => {
await transactionManager.update(
SharedWorkflow,
{ user: userToDelete },
{ user: transferee },
);
await transactionManager.update(
SharedCredentials,
{ user: userToDelete },
{ user: transferee },
);
await transactionManager.delete(User, { id: userToDelete.id });
});
res.json(clean([userToDelete], true)[0]);
}
const [ownedSharedWorkflows = [], ownedSharedCredentials = []] = await Promise.all([
Db.collections.SharedWorkflow?.find({
relations: ['workflow'],
where: { user: userToDelete },
}),
Db.collections.SharedCredentials?.find({
relations: ['credentials'],
where: { user: userToDelete },
}),
]);
await Db.transaction(async (transactionManager) => {
const ownedWorkflows = await Promise.all(
ownedSharedWorkflows.map(async ({ workflow }) => {
if (workflow.active) {
const activeWorkflowRunner = ActiveWorkflowRunner.getInstance();
// deactivate before deleting
void activeWorkflowRunner.remove(workflow.id.toString());
}
return workflow;
}),
);
await transactionManager.remove(ownedWorkflows);
await transactionManager.remove(ownedSharedCredentials.map(({ credentials }) => credentials));
await transactionManager.delete(User, { id: userToDelete.id });
});
const telemetryData: ITelemetryUserDeletionData = {
user_id: req.user.id,
target_user_old_status: userToDelete.isPending ? 'invited' : 'active',
target_user_id: idToDelete,
};
telemetryData.migration_strategy = transferId ? 'transfer_data' : 'delete_data';
if (transferId) {
telemetryData.migration_user_id = transferId;
}
void InternalHooksManager.getInstance().onUserDeletion(req.user.id, telemetryData);
res.json(clean([userToDelete], true)[0]);
},
getUser: async (req: UserRequest.Get, res: express.Response): Promise<void> => {
const includeRole = req.query?.includeRole?.toLowerCase() === 'true' || false;

View file

@ -132,7 +132,7 @@ export function sendErrorResponse(res: Response, error: ResponseError, shouldLog
// @ts-ignore
response.stack = error.stack;
}
console.log('se esta llmando al error');
res.status(httpStatusCode).json(response);
}

View file

@ -197,10 +197,10 @@ export declare namespace UserRequest {
>;
export type Delete = AuthenticatedRequest<
{ id: string; email: string },
{ id: string; email: string; identifier: string },
{},
{},
{ transferId?: string }
{ transferId?: string; includeRole: string }
>;
export type Get = AuthenticatedRequest<