Merge branch 'heads/main' into daniel/srp-removal-round-2

This commit is contained in:
Daniel Hougaard
2025-08-05 22:17:01 +04:00
446 changed files with 13524 additions and 3367 deletions
+16
View File
@@ -513,6 +513,21 @@ export const orgDALFactory = (db: TDbClient) => {
}
};
const deleteMembershipsById = async (ids: string[], orgId: string, tx?: Knex) => {
try {
const memberships = await (tx || db)(TableName.OrgMembership)
.where({
orgId
})
.whereIn("id", ids)
.delete()
.returning("*");
return memberships;
} catch (error) {
throw new DatabaseError({ error, name: "Delete org memberships" });
}
};
const findMembership = async (
filter: TFindFilter<TOrgMemberships>,
{ offset, limit, sort, tx }: TFindOpt<TOrgMemberships> = {}
@@ -634,6 +649,7 @@ export const orgDALFactory = (db: TDbClient) => {
createMembership,
updateMembershipById,
deleteMembershipById,
deleteMembershipsById,
updateMembership
});
};
+106 -1
View File
@@ -1,5 +1,6 @@
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TProjectUserAdditionalPrivilegeDALFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-dal";
import { BadRequestError } from "@app/lib/errors";
import { TOrgDALFactory } from "@app/services/org/org-dal";
import { TProjectKeyDALFactory } from "@app/services/project-key/project-key-dal";
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
@@ -14,6 +15,19 @@ type TDeleteOrgMembership = {
userAliasDAL: Pick<TUserAliasDALFactory, "delete">;
licenseService: Pick<TLicenseServiceFactory, "updateSubscriptionOrgMemberCount">;
projectUserAdditionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "delete">;
userId?: string;
};
type TDeleteOrgMemberships = {
orgMembershipIds: string[];
orgId: string;
orgDAL: Pick<TOrgDALFactory, "findMembership" | "deleteMembershipsById" | "transaction">;
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "delete" | "findProjectMembershipsByUserIds">;
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "delete">;
userAliasDAL: Pick<TUserAliasDALFactory, "delete">;
licenseService: Pick<TLicenseServiceFactory, "updateSubscriptionOrgMemberCount">;
projectUserAdditionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "delete">;
userId?: string;
};
export const deleteOrgMembershipFn = async ({
@@ -24,11 +38,17 @@ export const deleteOrgMembershipFn = async ({
projectUserAdditionalPrivilegeDAL,
projectKeyDAL,
userAliasDAL,
licenseService
licenseService,
userId
}: TDeleteOrgMembership) => {
const deletedMembership = await orgDAL.transaction(async (tx) => {
const orgMembership = await orgDAL.deleteMembershipById(orgMembershipId, orgId, tx);
if (userId && orgMembership.userId === userId) {
// scott: this is temporary, we will add a leave org endpoint with proper handling to ensure org isn't abandoned/broken
throw new BadRequestError({ message: "You cannot remove yourself from an organization" });
}
if (!orgMembership.userId) {
await licenseService.updateSubscriptionOrgMemberCount(orgId);
return orgMembership;
@@ -86,3 +106,88 @@ export const deleteOrgMembershipFn = async ({
return deletedMembership;
};
export const deleteOrgMembershipsFn = async ({
orgMembershipIds,
orgId,
orgDAL,
projectMembershipDAL,
projectUserAdditionalPrivilegeDAL,
projectKeyDAL,
userAliasDAL,
licenseService,
userId
}: TDeleteOrgMemberships) => {
const deletedMemberships = await orgDAL.transaction(async (tx) => {
const orgMemberships = await orgDAL.deleteMembershipsById(orgMembershipIds, orgId, tx);
const membershipUserIds = orgMemberships
.filter((member) => Boolean(member.userId))
.map((member) => member.userId) as string[];
if (userId && membershipUserIds.includes(userId)) {
// scott: this is temporary, we will add a leave org endpoint with proper handling to ensure org isn't abandoned/broken
throw new BadRequestError({ message: "You cannot remove yourself from an organization" });
}
if (!membershipUserIds.length) {
await licenseService.updateSubscriptionOrgMemberCount(orgId);
return orgMemberships;
}
await userAliasDAL.delete(
{
$in: {
userId: membershipUserIds
},
orgId
},
tx
);
await projectUserAdditionalPrivilegeDAL.delete(
{
$in: {
userId: membershipUserIds
}
},
tx
);
// Get all the project memberships of the users in the organization
const projectMemberships = await projectMembershipDAL.findProjectMembershipsByUserIds(orgId, membershipUserIds);
// Delete all the project memberships of the users in the organization
await projectMembershipDAL.delete(
{
$in: {
id: projectMemberships.map((membership) => membership.id)
}
},
tx
);
// Get all the project keys of the user in the organization
const projectKeys = await projectKeyDAL.find({
$in: {
projectId: projectMemberships.map((membership) => membership.projectId),
receiverId: membershipUserIds
}
});
// Delete all the project keys of the user in the organization
await projectKeyDAL.delete(
{
$in: {
id: projectKeys.map((key) => key.id)
}
},
tx
);
await licenseService.updateSubscriptionOrgMemberCount(orgId);
return orgMemberships;
});
return deletedMemberships;
};
+42 -4
View File
@@ -72,10 +72,11 @@ import { TUserDALFactory } from "../user/user-dal";
import { TIncidentContactsDALFactory } from "./incident-contacts-dal";
import { TOrgBotDALFactory } from "./org-bot-dal";
import { TOrgDALFactory } from "./org-dal";
import { deleteOrgMembershipFn } from "./org-fns";
import { deleteOrgMembershipFn, deleteOrgMembershipsFn } from "./org-fns";
import { TOrgRoleDALFactory } from "./org-role-dal";
import {
TDeleteOrgMembershipDTO,
TDeleteOrgMembershipsDTO,
TFindAllWorkspacesDTO,
TFindOrgMembersByEmailDTO,
TGetOrgGroupsDTO,
@@ -103,7 +104,13 @@ type TOrgServiceFactoryDep = {
identityMetadataDAL: Pick<TIdentityMetadataDALFactory, "delete" | "insertMany" | "transaction">;
projectMembershipDAL: Pick<
TProjectMembershipDALFactory,
"findProjectMembershipsByUserId" | "delete" | "create" | "find" | "insertMany" | "transaction"
| "findProjectMembershipsByUserId"
| "delete"
| "create"
| "find"
| "insertMany"
| "transaction"
| "findProjectMembershipsByUserIds"
>;
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "delete" | "insertMany" | "findLatestProjectKey" | "create">;
orgMembershipDAL: Pick<
@@ -1227,12 +1234,42 @@ export const orgServiceFactory = ({
projectUserAdditionalPrivilegeDAL,
projectKeyDAL,
userAliasDAL,
licenseService
licenseService,
userId
});
return deletedMembership;
};
const bulkDeleteOrgMemberships = async ({
orgId,
userId,
membershipIds,
actorAuthMethod,
actorOrgId
}: TDeleteOrgMembershipsDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorAuthMethod, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member);
if (membershipIds.includes(userId)) {
throw new BadRequestError({ message: "You cannot delete your own organization membership" });
}
const deletedMemberships = await deleteOrgMembershipsFn({
orgMembershipIds: membershipIds,
orgId,
orgDAL,
projectMembershipDAL,
projectUserAdditionalPrivilegeDAL,
projectKeyDAL,
userAliasDAL,
licenseService,
userId
});
return deletedMemberships;
};
const listProjectMembershipsByOrgMembershipId = async ({
orgMembershipId,
orgId,
@@ -1386,6 +1423,7 @@ export const orgServiceFactory = ({
findOrgBySlug,
resendOrgMemberInvitation,
upgradePrivilegeSystem,
notifyInvitedUsers
notifyInvitedUsers,
bulkDeleteOrgMemberships
};
};
+8
View File
@@ -25,6 +25,14 @@ export type TDeleteOrgMembershipDTO = {
actorAuthMethod: ActorAuthMethod;
};
export type TDeleteOrgMembershipsDTO = {
userId: string;
orgId: string;
membershipIds: string[];
actorOrgId: string | undefined;
actorAuthMethod: ActorAuthMethod;
};
export type TInviteUserToOrgDTO = {
inviteeEmails: string[];
organizationRoleSlug: string;