mirror of
https://github.com/documenso/documenso.git
synced 2026-07-23 00:13:46 +10:00
feat: unlink documents from deleted organization (#2006)
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { DocumentStatus, EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { deletedAccountServiceAccount } from '../user/service-accounts/deleted-account';
|
||||
|
||||
export type OrphanEnvelopesOptions = {
|
||||
teamId: number;
|
||||
};
|
||||
|
||||
export const orphanEnvelopes = async ({ teamId }: OrphanEnvelopesOptions) => {
|
||||
const serviceAccount = await deletedAccountServiceAccount();
|
||||
|
||||
// Transfer all inflight and completed envelopes to the service account.
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
teamId,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
status: {
|
||||
in: [DocumentStatus.PENDING, DocumentStatus.REJECTED, DocumentStatus.COMPLETED],
|
||||
},
|
||||
deletedAt: null,
|
||||
},
|
||||
data: {
|
||||
userId: serviceAccount.id,
|
||||
teamId: serviceAccount.ownedOrganisations[0].teams[0].id,
|
||||
deletedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// Transfer any remaining deleted envelopes to the service account.
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
teamId,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
status: {
|
||||
in: [DocumentStatus.PENDING, DocumentStatus.REJECTED, DocumentStatus.COMPLETED],
|
||||
},
|
||||
},
|
||||
data: {
|
||||
userId: serviceAccount.id,
|
||||
teamId: serviceAccount.ownedOrganisations[0].teams[0].id,
|
||||
},
|
||||
});
|
||||
|
||||
// Then delete anything remaining across documents and templates.
|
||||
await prisma.envelope.deleteMany({
|
||||
where: {
|
||||
teamId,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type TransferTeamEnvelopesOptions = {
|
||||
sourceTeamId: number;
|
||||
targetTeamId: number;
|
||||
};
|
||||
|
||||
export const transferTeamEnvelopes = async ({
|
||||
sourceTeamId,
|
||||
targetTeamId,
|
||||
}: TransferTeamEnvelopesOptions) => {
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
teamId: sourceTeamId,
|
||||
},
|
||||
data: {
|
||||
teamId: targetTeamId,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,9 +1,7 @@
|
||||
import { DocumentStatus, EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { deletedAccountServiceAccount } from './service-accounts/deleted-account';
|
||||
import { orphanEnvelopes } from '../envelope/orphan-envelopes';
|
||||
|
||||
export type DeleteUserOptions = {
|
||||
id: number;
|
||||
@@ -14,6 +12,30 @@ export const deleteUser = async ({ id }: DeleteUserOptions) => {
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
include: {
|
||||
ownedOrganisations: {
|
||||
include: {
|
||||
teams: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
organisationMember: {
|
||||
include: {
|
||||
organisation: {
|
||||
include: {
|
||||
teams: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
@@ -22,22 +44,36 @@ export const deleteUser = async ({ id }: DeleteUserOptions) => {
|
||||
});
|
||||
}
|
||||
|
||||
const serviceAccount = await deletedAccountServiceAccount();
|
||||
// Get team IDs from organisations the user owns.
|
||||
const ownedTeamIds = user.ownedOrganisations.flatMap((org) => org.teams.map((team) => team.id));
|
||||
|
||||
// TODO: Send out cancellations for all pending docs
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
status: {
|
||||
in: [DocumentStatus.PENDING, DocumentStatus.REJECTED, DocumentStatus.COMPLETED],
|
||||
},
|
||||
},
|
||||
data: {
|
||||
userId: serviceAccount.id,
|
||||
deletedAt: new Date(),
|
||||
},
|
||||
});
|
||||
// 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 teams where user is the org owner - orphan their envelopes.
|
||||
await Promise.all(ownedTeamIds.map(async (teamId) => orphanEnvelopes({ teamId })));
|
||||
|
||||
// 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: {
|
||||
|
||||
@@ -5,6 +5,20 @@ export const deletedAccountServiceAccount = async () => {
|
||||
where: {
|
||||
email: 'deleted-account@documenso.com',
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
ownedOrganisations: {
|
||||
select: {
|
||||
id: true,
|
||||
teams: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!serviceAccount) {
|
||||
|
||||
Reference in New Issue
Block a user