Remove transactions from delete organization, workspace, user

This commit is contained in:
Tuan Dang
2023-11-01 11:06:36 +02:00
parent 1be46b5e57
commit 7622a3f518
3 changed files with 366 additions and 588 deletions
+204 -300
View File
@@ -1,4 +1,4 @@
import mongoose, { Types, mongo } from "mongoose"; import { Types } from "mongoose";
import { import {
Bot, Bot,
BotKey, BotKey,
@@ -55,7 +55,7 @@ import {
import { import {
createBotOrg createBotOrg
} from "./botOrg"; } from "./botOrg";
import { InternalServerError, ResourceNotFoundError } from "../utils/errors"; import { ResourceNotFoundError } from "../utils/errors";
/** /**
* Create an organization with name [name] * Create an organization with name [name]
@@ -111,311 +111,215 @@ export const createOrganization = async ({
* @returns * @returns
*/ */
export const deleteOrganization = async ({ export const deleteOrganization = async ({
organizationId, organizationId
existingSession
}: { }: {
organizationId: Types.ObjectId; organizationId: Types.ObjectId;
existingSession?: mongo.ClientSession;
}) => { }) => {
let session; const organization = await Organization.findByIdAndDelete(
organizationId
if (existingSession) { );
session = existingSession;
} else {
session = await mongoose.startSession();
session.startTransaction();
}
try { if (!organization) throw ResourceNotFoundError();
const organization = await Organization.findByIdAndDelete(
organizationId, await MembershipOrg.deleteMany({
{ organization: organization._id
session });
}
await BotOrg.deleteMany({
organization: organization._id
});
await SSOConfig.deleteMany({
organization: organization._id
});
await Role.deleteMany({
organization: organization._id
});
await IncidentContactOrg.deleteMany({
organization: organization._id
});
await GitRisks.deleteMany({
organization: organization._id
});
await GitAppInstallationSession.deleteMany({
organization: organization._id
});
await GitAppOrganizationInstallation.deleteMany({
organization: organization._id
});
const workspaceIds = await Workspace.distinct("_id", {
organization: organization._id
});
await Workspace.deleteMany({
organization: organization._id
});
await Membership.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Key.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Bot.deleteMany({
workspace: {
$in: workspaceIds
}
});
await BotKey.deleteMany({
workspace: {
$in: workspaceIds
}
});
await SecretBlindIndexData.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Secret.deleteMany({
workspace: {
$in: workspaceIds
}
});
await SecretVersion.deleteMany({
workspace: {
$in: workspaceIds
}
});
await SecretSnapshot.deleteMany({
workspace: {
$in: workspaceIds
}
});
await SecretImport.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Folder.deleteMany({
workspace: {
$in: workspaceIds
}
});
await FolderVersion.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Webhook.deleteMany({
workspace: {
$in: workspaceIds
}
});
await TrustedIP.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Tag.deleteMany({
workspace: {
$in: workspaceIds
}
});
await IntegrationAuth.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Integration.deleteMany({
workspace: {
$in: workspaceIds
}
});
await ServiceToken.deleteMany({
workspace: {
$in: workspaceIds
}
});
await ServiceTokenData.deleteMany({
workspace: {
$in: workspaceIds
}
});
await ServiceTokenDataV3.deleteMany({
workspace: {
$in: workspaceIds
}
});
await ServiceTokenDataV3Key.deleteMany({
workspace: {
$in: workspaceIds
}
});
await AuditLog.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Log.deleteMany({
workspace: {
$in: workspaceIds
}
});
await Action.deleteMany({
workspace: {
$in: workspaceIds
}
});
await SecretApprovalPolicy.deleteMany({
workspace: {
$in: workspaceIds
}
});
await SecretApprovalRequest.deleteMany({
workspace: {
$in: workspaceIds
}
});
if (organization.customerId) {
// delete from stripe here
await licenseServerKeyRequest.delete(
`${await getLicenseServerUrl()}/api/license-server/v1/customers/${organization.customerId}`
); );
if (!organization) throw ResourceNotFoundError();
await MembershipOrg.deleteMany({
organization: organization._id
}, {
session
});
await BotOrg.deleteMany({
organization: organization._id
}, {
session
});
await SSOConfig.deleteMany({
organization: organization._id
}, {
session
});
await Role.deleteMany({
organization: organization._id
}, {
session
});
await IncidentContactOrg.deleteMany({
organization: organization._id
}, {
session
});
await GitRisks.deleteMany({
organization: organization._id
}, {
session
});
await GitAppInstallationSession.deleteMany({
organization: organization._id
}, {
session
});
await GitAppOrganizationInstallation.deleteMany({
organization: organization._id
}, {
session
});
const workspaceIds = await Workspace.distinct("_id", {
organization: organization._id
});
await Workspace.deleteMany({
organization: organization._id
}, {
session
});
await Membership.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Key.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Bot.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await BotKey.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await SecretBlindIndexData.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Secret.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await SecretVersion.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await SecretSnapshot.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await SecretImport.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Folder.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await FolderVersion.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Webhook.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await TrustedIP.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Tag.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await IntegrationAuth.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Integration.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await ServiceToken.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await ServiceTokenData.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await ServiceTokenDataV3.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await ServiceTokenDataV3Key.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await AuditLog.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Log.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await Action.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await SecretApprovalPolicy.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
await SecretApprovalRequest.deleteMany({
workspace: {
$in: workspaceIds
}
}, {
session
});
if (organization.customerId) {
// delete from stripe here
await licenseServerKeyRequest.delete(
`${await getLicenseServerUrl()}/api/license-server/v1/customers/${organization.customerId}`
);
}
return organization;
} catch (err) {
if (!existingSession) {
await session.abortTransaction();
}
throw InternalServerError({
message: "Failed to delete organization"
});
} finally {
if (!existingSession) {
await session.commitTransaction();
session.endSession();
}
} }
return organization;
} }
/** /**
+76 -125
View File
@@ -1,4 +1,4 @@
import mongoose, { Types, mongo } from "mongoose"; import { Types } from "mongoose";
import { import {
APIKeyData, APIKeyData,
BackupPrivateKey, BackupPrivateKey,
@@ -222,141 +222,92 @@ const checkDeleteUserConditions = async ({
* @returns {User} user - deleted user * @returns {User} user - deleted user
*/ */
export const deleteUser = async ({ export const deleteUser = async ({
userId, userId
existingSession
}: { }: {
userId: Types.ObjectId; userId: Types.ObjectId;
existingSession?: mongo.ClientSession;
}) => { }) => {
const user = await User.findByIdAndDelete(userId);
let session; if (!user) throw ResourceNotFoundError();
await checkDeleteUserConditions({
userId: user._id
});
if (existingSession) { await UserAction.deleteMany({
session = existingSession; user: user._id
} else { });
session = await mongoose.startSession();
session.startTransaction(); await BackupPrivateKey.deleteMany({
user: user._id
});
await APIKeyData.deleteMany({
user: user._id
});
await Action.deleteMany({
user: user._id
});
await Log.deleteMany({
user: user._id
});
await TokenVersion.deleteMany({
user: user._id
});
await Key.deleteMany({
receiver: user._id
});
const membershipOrgs = await MembershipOrg.find({
user: userId
});
// delete organizations where user is only member
for await (const membershipOrg of membershipOrgs) {
const memberCount = await MembershipOrg.countDocuments({
organization: membershipOrg.organization
});
if (memberCount === 1) {
// organization only has 1 member (the current user)
await deleteOrganization({
organizationId: membershipOrg.organization
});
}
} }
try { const memberships = await Membership.find({
const user = await User.findByIdAndDelete(userId, { user: userId
session });
// delete workspaces where user is only member
for await (const membership of memberships) {
const memberCount = await Membership.countDocuments({
workspace: membership.workspace
}); });
if (!user) throw ResourceNotFoundError(); if (memberCount === 1) {
// workspace only has 1 member (the current user) -> delete workspace
await checkDeleteUserConditions({ await deleteWorkspace({
userId: user._id workspaceId: membership.workspace
});
await UserAction.deleteMany({
user: user._id
}, {
session
});
await BackupPrivateKey.deleteMany({
user: user._id
}, {
session
});
await APIKeyData.deleteMany({
user: user._id
}, {
session
});
await Action.deleteMany({
user: user._id
}, {
session
});
await Log.deleteMany({
user: user._id
}, {
session
});
await TokenVersion.deleteMany({
user: user._id
});
await Key.deleteMany({
receiver: user._id
}, {
session
});
const membershipOrgs = await MembershipOrg.find({
user: userId
}, null, {
session
});
// delete organizations where user is only member
for await (const membershipOrg of membershipOrgs) {
const memberCount = await MembershipOrg.countDocuments({
organization: membershipOrg.organization
}); });
if (memberCount === 1) {
// organization only has 1 member (the current user)
await deleteOrganization({
organizationId: membershipOrg.organization,
existingSession: session
});
}
}
const memberships = await Membership.find({
user: userId
}, null, {
session
});
// delete workspaces where user is only member
for await (const membership of memberships) {
const memberCount = await Membership.countDocuments({
workspace: membership.workspace
});
if (memberCount === 1) {
// workspace only has 1 member (the current user) -> delete workspace
await deleteWorkspace({
workspaceId: membership.workspace,
existingSession: session
});
}
}
await MembershipOrg.deleteMany({
user: userId
}, {
session
});
await Membership.deleteMany({
user: userId
}, {
session
});
return user;
} catch (err) {
if (!existingSession) {
await session.abortTransaction();
}
throw InternalServerError({
message: "Failed to delete account"
})
} finally {
if (!existingSession) {
await session.commitTransaction();
session.endSession();
} }
} }
await MembershipOrg.deleteMany({
user: userId
});
await Membership.deleteMany({
user: userId
});
return user;
} }
+86 -163
View File
@@ -1,4 +1,4 @@
import mongoose, { Types, mongo } from "mongoose"; import { Types } from "mongoose";
import { import {
Bot, Bot,
BotKey, BotKey,
@@ -33,8 +33,7 @@ import {
import { createBot } from "../helpers/bot"; import { createBot } from "../helpers/bot";
import { EELicenseService } from "../ee/services"; import { EELicenseService } from "../ee/services";
import { SecretService } from "../services"; import { SecretService } from "../services";
import { import {
InternalServerError,
ResourceNotFoundError ResourceNotFoundError
} from "../utils/errors"; } from "../utils/errors";
@@ -102,189 +101,113 @@ export const createWorkspace = async ({
* @param {String} obj.id - id of workspace to delete * @param {String} obj.id - id of workspace to delete
*/ */
export const deleteWorkspace = async ({ export const deleteWorkspace = async ({
workspaceId, workspaceId
existingSession
}: { }: {
workspaceId: Types.ObjectId; workspaceId: Types.ObjectId;
existingSession?: mongo.ClientSession;
}) => { }) => {
const workspace = await Workspace.findByIdAndDelete(workspaceId);
let session;
if (existingSession) {
session = existingSession;
} else {
session = await mongoose.startSession();
session.startTransaction();
}
try { if (!workspace) throw ResourceNotFoundError();
const workspace = await Workspace.findByIdAndDelete(workspaceId, { session });
await Membership.deleteMany({
if (!workspace) throw ResourceNotFoundError(); workspace: workspace._id
});
await Membership.deleteMany({
workspace: workspace._id await Key.deleteMany({
}, { workspace: workspace._id
session });
});
await Bot.deleteMany({
await Key.deleteMany({ workspace: workspace._id
workspace: workspace._id });
}, {
session
});
await Bot.deleteMany({
workspace: workspace._id
}, {
session
});
await BotKey.deleteMany({ await BotKey.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await SecretBlindIndexData.deleteMany({ await SecretBlindIndexData.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await Secret.deleteMany({ await Secret.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
}); await SecretVersion.deleteMany({
workspace: workspace._id
await SecretVersion.deleteMany({ });
workspace: workspace._id
}, {
session
});
await SecretSnapshot.deleteMany({ await SecretSnapshot.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await SecretImport.deleteMany({ await SecretImport.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await Folder.deleteMany({ await Folder.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await FolderVersion.deleteMany({ await FolderVersion.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await Webhook.deleteMany({ await Webhook.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await TrustedIP.deleteMany({ await TrustedIP.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await Tag.deleteMany({ await Tag.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await IntegrationAuth.deleteMany({ await IntegrationAuth.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await Integration.deleteMany({ await Integration.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await ServiceToken.deleteMany({ await ServiceToken.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await ServiceTokenData.deleteMany({ await ServiceTokenData.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await ServiceTokenDataV3.deleteMany({ await ServiceTokenDataV3.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await ServiceTokenDataV3Key.deleteMany({ await ServiceTokenDataV3Key.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await AuditLog.deleteMany({ await AuditLog.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await Log.deleteMany({ await Log.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await Action.deleteMany({ await Action.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await SecretApprovalPolicy.deleteMany({ await SecretApprovalPolicy.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
});
await SecretApprovalRequest.deleteMany({ await SecretApprovalRequest.deleteMany({
workspace: workspace._id workspace: workspace._id
}, { });
session
}); return workspace;
return workspace;
} catch (err) {
if (!existingSession) {
await session.abortTransaction();
}
throw InternalServerError({
message: "Failed to delete organization"
});
} finally {
if (!existingSession) {
await session.commitTransaction();
session.endSession();
}
}
}; };