Files

91 lines
2.2 KiB
TypeScript

import { prisma } from '@documenso/prisma';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { deleteOrganisation } from '../organisation/delete-organisation';
export type DeleteUserOptions = {
id: number;
};
export const deleteUser = async ({ id }: DeleteUserOptions) => {
const user = await prisma.user.findFirst({
where: {
id,
},
include: {
ownedOrganisations: {
include: {
teams: {
select: {
id: true,
},
},
subscription: {
select: {
planId: true,
},
},
},
},
organisationMember: {
include: {
organisation: {
include: {
teams: {
select: {
id: true,
},
},
},
},
},
},
},
});
if (!user) {
throw new AppError(AppErrorCode.NOT_FOUND, {
message: `User with ID ${id} not found`,
});
}
// Get team IDs from organisations the user is a member of (but not owner).
const memberTeams = user.organisationMember
.filter((member) => member.organisation.ownerUserId !== user.id)
.flatMap((member) =>
member.organisation.teams.map((team) => ({
teamId: team.id,
orgOwnerId: member.organisation.ownerUserId,
})),
);
// For organisations the user owns - fully tear them down (orphan envelopes,
// delete the organisation, and cancel any Stripe subscription). Without this
// the organisations would only cascade away when the user row is deleted,
// leaving their subscriptions billing and account rows behind.
for (const organisation of user.ownedOrganisations) {
await deleteOrganisation({ organisation });
}
// For teams where user is a member (not owner) - transfer envelopes to team owner.
await Promise.all(
memberTeams.map(async ({ teamId, orgOwnerId }) => {
return prisma.envelope.updateMany({
where: {
userId: user.id,
teamId,
},
data: {
userId: orgOwnerId,
},
});
}),
);
return await prisma.user.delete({
where: {
id: user.id,
},
});
};