fix: Consistently remove a member from organization/sub-team/team - through all the APIs and webapp actions (#22806)
* Fix membership deletion handling and add tests * fixes * revert api-v2 specific changes * Add more tests * refactor: Move removeMember function into TeamService as private static methods - Moved removeMember and all related helper functions from separate file into TeamService class - Made all functions private static methods instead of exporting them - Deleted the original removeMember.ts file since it's no longer needed - Updated imports to use the new location - All integration tests pass successfully * refactor: Rename memberId to userId in TeamService methods - Renamed memberId parameter to userId in removeMember private method - Renamed memberIds parameter to userIds in removeMembers public method - Updated all calls to removeMembers to use userIds instead of memberIds - Parameter names now accurately reflect that they are user IDs, not membership IDs * test: add service unit tests and simplify e2e tests for membership deletion - Add unit tests for membership deletion services - Remove redundant deletion behavior tests from controllers - Keep only happy path tests in e2e controller tests - Fix unused imports and variables * package.json version * fix unit teswtes * No specs file * fix unit tests * fix: Add platform-libraries build step to E2E API v2 workflow The E2E API v2 tests were failing with TypeScript compilation errors because TeamService imports from @calcom/platform-libraries require the package to be built first to generate the dist/ folder with compiled exports. This adds the same build step that was added to unit-tests.yml to resolve the module resolution errors. Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * Making tests clearer and easier to undestand * chore: bump platform libs * chore: bump platform libs --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Co-authored-by: cal.com <morgan@cal.com>
This commit is contained in:
co-authored by
hariom@cal.com <hariombalhara@gmail.com>
Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Morgan
cal.com
parent
f74434a282
commit
88bbab216e
+17
-1
@@ -2,6 +2,8 @@ import { CreateOrgMembershipDto } from "@/modules/organizations/memberships/inpu
|
||||
import { OrganizationsMembershipRepository } from "@/modules/organizations/memberships/organizations-membership.repository";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
|
||||
import { TeamService } from "@calcom/platform-libraries";
|
||||
|
||||
import { UpdateOrgMembershipDto } from "../inputs/update-organization-membership.input";
|
||||
import { OrganizationsMembershipOutputService } from "./organizations-membership-output.service";
|
||||
|
||||
@@ -62,10 +64,24 @@ export class OrganizationsMembershipService {
|
||||
}
|
||||
|
||||
async deleteOrgMembership(organizationId: number, membershipId: number) {
|
||||
const membership = await this.organizationsMembershipRepository.deleteOrgMembership(
|
||||
// Get the membership first to get the userId
|
||||
const membership = await this.organizationsMembershipRepository.findOrgMembership(
|
||||
organizationId,
|
||||
membershipId
|
||||
);
|
||||
|
||||
if (!membership) {
|
||||
throw new NotFoundException(
|
||||
`Membership with id ${membershipId} within organization id ${organizationId} not found`
|
||||
);
|
||||
}
|
||||
|
||||
await TeamService.removeMembers({
|
||||
teamIds: [organizationId],
|
||||
userIds: [membership.userId],
|
||||
isOrg: true,
|
||||
});
|
||||
|
||||
return this.organizationsMembershipOutputService.getOrgMembershipOutput(membership);
|
||||
}
|
||||
|
||||
|
||||
-4
@@ -20,7 +20,6 @@ import {
|
||||
OrgTeamMembershipOutputResponseDto,
|
||||
} from "@/modules/organizations/teams/memberships/outputs/organization-teams-memberships.output";
|
||||
import { OrganizationsTeamsMembershipsService } from "@/modules/organizations/teams/memberships/services/organizations-teams-memberships.service";
|
||||
import { TeamsEventTypesService } from "@/modules/teams/event-types/services/teams-event-types.service";
|
||||
import { TeamMembershipOutput } from "@/modules/teams/memberships/outputs/team-membership.output";
|
||||
import {
|
||||
Controller,
|
||||
@@ -59,7 +58,6 @@ export class OrganizationsTeamsMembershipsController {
|
||||
|
||||
constructor(
|
||||
private organizationsTeamsMembershipsService: OrganizationsTeamsMembershipsService,
|
||||
private teamsEventTypesService: TeamsEventTypesService,
|
||||
private readonly organizationsRepository: OrganizationsRepository
|
||||
) {}
|
||||
|
||||
@@ -127,8 +125,6 @@ export class OrganizationsTeamsMembershipsController {
|
||||
membershipId
|
||||
);
|
||||
|
||||
await this.teamsEventTypesService.deleteUserTeamEventTypesAndHosts(membership.userId, teamId);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: plainToClass(TeamMembershipOutput, membership, { strategy: "excludeAll" }),
|
||||
|
||||
+13
-1
@@ -3,6 +3,8 @@ import { UpdateOrgTeamMembershipDto } from "@/modules/organizations/teams/member
|
||||
import { OrganizationsTeamsMembershipsRepository } from "@/modules/organizations/teams/memberships/organizations-teams-memberships.repository";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
|
||||
import { TeamService } from "@calcom/platform-libraries";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsTeamsMembershipsService {
|
||||
constructor(
|
||||
@@ -58,11 +60,21 @@ export class OrganizationsTeamsMembershipsService {
|
||||
}
|
||||
|
||||
async deleteOrgTeamMembership(organizationId: number, teamId: number, membershipId: number) {
|
||||
const teamMembership = await this.organizationsTeamsMembershipsRepository.deleteOrgTeamMembershipById(
|
||||
// First get the membership to get the userId
|
||||
const teamMembership = await this.organizationsTeamsMembershipsRepository.findOrgTeamMembership(
|
||||
organizationId,
|
||||
teamId,
|
||||
membershipId
|
||||
);
|
||||
|
||||
if (!teamMembership) {
|
||||
throw new NotFoundException(
|
||||
`Membership with id ${membershipId} not found in team ${teamId} of organization ${organizationId}`
|
||||
);
|
||||
}
|
||||
|
||||
await TeamService.removeMembers({ teamIds: [teamId], userIds: [teamMembership.userId], isOrg: false });
|
||||
|
||||
return teamMembership;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,17 +156,4 @@ export class TeamsEventTypesService {
|
||||
|
||||
return this.eventTypesRepository.deleteEventType(eventTypeId);
|
||||
}
|
||||
|
||||
async deleteUserTeamEventTypesAndHosts(userId: number, teamId: number) {
|
||||
try {
|
||||
await this.teamsEventTypesRepository.deleteUserManagedTeamEventTypes(userId, teamId);
|
||||
await this.teamsEventTypesRepository.removeUserFromTeamEventTypesHosts(userId, teamId);
|
||||
} catch (err) {
|
||||
this.logger.error("Could not remove user from all team event-types.", {
|
||||
error: err,
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-8
@@ -3,7 +3,6 @@ import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { RolesGuard } from "@/modules/auth/guards/roles/roles.guard";
|
||||
import { TeamsEventTypesService } from "@/modules/teams/event-types/services/teams-event-types.service";
|
||||
import { CreateTeamMembershipInput } from "@/modules/teams/memberships/inputs/create-team-membership.input";
|
||||
import { UpdateTeamMembershipInput } from "@/modules/teams/memberships/inputs/update-team-membership.input";
|
||||
import { CreateTeamMembershipOutput } from "@/modules/teams/memberships/outputs/create-team-membership.output";
|
||||
@@ -45,10 +44,7 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
export class TeamsMembershipsController {
|
||||
private logger = new Logger("TeamsMembershipsController");
|
||||
|
||||
constructor(
|
||||
private teamsMembershipsService: TeamsMembershipsService,
|
||||
private teamsEventTypesService: TeamsEventTypesService
|
||||
) {}
|
||||
constructor(private teamsMembershipsService: TeamsMembershipsService) {}
|
||||
|
||||
@Roles("TEAM_ADMIN")
|
||||
@Post("/")
|
||||
@@ -127,7 +123,6 @@ export class TeamsMembershipsController {
|
||||
membershipId,
|
||||
body
|
||||
);
|
||||
|
||||
if (!currentMembership.accepted && updatedMembership.accepted) {
|
||||
try {
|
||||
await updateNewTeamMemberEventTypes(updatedMembership.userId, teamId);
|
||||
@@ -151,8 +146,6 @@ export class TeamsMembershipsController {
|
||||
): Promise<DeleteTeamMembershipOutput> {
|
||||
const membership = await this.teamsMembershipsService.deleteTeamMembership(teamId, membershipId);
|
||||
|
||||
await this.teamsEventTypesService.deleteUserTeamEventTypesAndHosts(membership.userId, teamId);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: plainToClass(TeamMembershipOutput, membership, { strategy: "excludeAll" }),
|
||||
|
||||
@@ -3,6 +3,8 @@ import { UpdateTeamMembershipInput } from "@/modules/teams/memberships/inputs/up
|
||||
import { TeamsMembershipsRepository } from "@/modules/teams/memberships/teams-memberships.repository";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
|
||||
import { TeamService } from "@calcom/platform-libraries";
|
||||
|
||||
@Injectable()
|
||||
export class TeamsMembershipsService {
|
||||
constructor(private readonly teamsMembershipsRepository: TeamsMembershipsRepository) {}
|
||||
@@ -41,10 +43,15 @@ export class TeamsMembershipsService {
|
||||
}
|
||||
|
||||
async deleteTeamMembership(teamId: number, membershipId: number) {
|
||||
const teamMembership = await this.teamsMembershipsRepository.deleteTeamMembershipById(
|
||||
teamId,
|
||||
membershipId
|
||||
);
|
||||
// First get the membership to get the userId
|
||||
const teamMembership = await this.teamsMembershipsRepository.findTeamMembership(teamId, membershipId);
|
||||
|
||||
if (!teamMembership) {
|
||||
throw new NotFoundException(`Membership with id ${membershipId} not found in team ${teamId}`);
|
||||
}
|
||||
|
||||
await TeamService.removeMembers({ teamIds: [teamId], userIds: [teamMembership.userId], isOrg: false });
|
||||
|
||||
return teamMembership;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user