Files
calendar/packages/trpc/server/routers/viewer/organizations/bulkDeleteUsers.handler.ts
T
392757fb55 fix: Remove user from managed event type when removing from org (#17369)
* Remove user from managed event type when removing from org

* added test for admin check, correct changes for membership, user info, profiles

* remove host assignment for removed members

* expand test to cover  event types removal

* chore: use var

* chore

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit222001@gmail.com>
2024-12-03 17:54:04 +01:00

120 lines
3.1 KiB
TypeScript

import { TeamBilling } from "@calcom/ee/billing/teams";
import { isOrganisationAdmin } from "@calcom/lib/server/queries/organisations";
import { ProfileRepository } from "@calcom/lib/server/repository/profile";
import { prisma } from "@calcom/prisma";
import { TRPCError } from "@trpc/server";
import type { TrpcSessionUser } from "../../../trpc";
import type { TBulkUsersDelete } from "./bulkDeleteUsers.schema.";
type BulkDeleteUsersHandler = {
ctx: {
user: NonNullable<TrpcSessionUser>;
};
input: TBulkUsersDelete;
};
export async function bulkDeleteUsersHandler({ ctx, input }: BulkDeleteUsersHandler) {
const currentUser = ctx.user;
const currentUserOrgId = currentUser.organizationId ?? currentUser.profiles[0].organizationId;
if (!currentUserOrgId) throw new TRPCError({ code: "UNAUTHORIZED" });
// check if user is admin of organization
if (!(await isOrganisationAdmin(currentUser?.id, currentUserOrgId)))
throw new TRPCError({ code: "UNAUTHORIZED" });
// Loop over all users in input.userIds and remove all memberships for the organization including child teams
const deleteMany = prisma.membership.deleteMany({
where: {
userId: {
in: input.userIds,
},
team: {
OR: [
{
parentId: currentUserOrgId,
},
{ id: currentUserOrgId },
],
},
},
});
const removeOrgrelation = prisma.user.updateMany({
where: {
id: {
in: input.userIds,
},
},
data: {
organizationId: null,
// Set username to null - to make sure there is no conflicts
username: null,
// Set completedOnboarding to false - to make sure the user has to complete onboarding again -> Setup a new username
completedOnboarding: false,
},
});
const removeManagedEventTypes = prisma.eventType.deleteMany({
where: {
userId: {
in: input.userIds,
},
parent: {
team: {
OR: [
{
parentId: currentUserOrgId,
},
{ id: currentUserOrgId },
],
},
},
},
});
const removeHostAssignment = prisma.host.deleteMany({
where: {
userId: {
in: input.userIds,
},
eventType: {
team: {
OR: [
{
parentId: currentUserOrgId,
},
{ id: currentUserOrgId },
],
},
},
},
});
const removeProfiles = ProfileRepository.deleteMany({
userIds: input.userIds,
});
// We do this in a transaction to make sure that all memberships are removed before we remove the organization relation from the user
// We also do this to make sure that if one of the queries fail, the whole transaction fails
await prisma.$transaction([
removeProfiles,
deleteMany,
removeOrgrelation,
removeManagedEventTypes,
removeHostAssignment,
]);
const teamBilling = await TeamBilling.findAndInit(currentUserOrgId);
await teamBilling.updateQuantity();
return {
success: true,
usersDeleted: input.userIds.length,
};
}
export default bulkDeleteUsersHandler;