From 39ae54d682993b65390bb350de59ea25d387e505 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Tue, 20 Jan 2026 18:40:44 +0530 Subject: [PATCH] feat: add auto-accept logic for team memberships based on org email domain (#26860) ## What does this PR do? Adds auto-accept logic to the `/v2/teams/{teamId}/memberships` endpoint, similar to what exists in the `/v2/organizations/{orgId}/teams/{teamId}/memberships` endpoint. When a user is added to a sub-team of an organization, the system now checks if the user's email domain matches the organization's `orgAutoAcceptEmail` setting. If it matches and the organization is verified, the membership is automatically accepted (overriding any `accepted: false` in the request). ### Changes: - Modified `TeamsMembershipsService.createTeamMembership()` to check if the team has a parent organization and apply auto-accept logic using the existing `OrganizationMembershipService.shouldAutoAccept()` method - Exported `OrganizationMembershipService` from `OrganizationsModule` for dependency injection - Added `TeamsModule` and `UsersModule` imports to `TeamsMembershipsModule` - Added required dependencies (`OrganizationMembershipService`, `OAuthClientRepository`, etc.) to `TeamsModule` and `TeamsSchedulesModule` since they provide `TeamsMembershipsService` directly - Added comprehensive E2E tests for auto-accept scenarios - Added `createOrgSettings` and `deleteOrgSettings` helper methods to test fixtures ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - no documentation changes needed. - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. ## How should this be tested? The E2E tests cover the following scenarios: 1. **Auto-accept when email matches** - User with `@acme.com` email is auto-accepted when org has `orgAutoAcceptEmail: "acme.com"` 2. **Case-insensitive matching** - User with `@ACME.COM` email matches `orgAutoAcceptEmail: "acme.com"` 3. **Override accepted:false** - Even if `accepted: false` is passed, it's overridden to `true` when email matches 4. **No auto-accept for non-matching emails** - User with `@external.com` email is NOT auto-accepted 5. **EventTypes assignment** - Verifies user is added to event types with `assignAllTeamMembers: true` To run the tests: ```bash TZ=UTC yarn test:e2e --testPathPattern="teams-memberships.controller.e2e-spec" ``` ## Human Review Checklist - [ ] Verify the auto-accept logic matches the existing implementation in `organizations-teams-memberships.controller.ts` - [ ] Confirm all modules that provide `TeamsMembershipsService` directly (`TeamsModule`, `TeamsSchedulesModule`, `OrganizationsModule`) have the required dependencies - [ ] Verify `updateNewTeamMemberEventTypes` is called when auto-accept triggers (controller checks `membership.accepted` after service returns) - [ ] Consider if organization membership creation is needed when a user is auto-accepted into a sub-team but doesn't have org membership yet (not implemented in this PR) ## Checklist - [x] I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md) - [x] My code follows the style guidelines of this project - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have checked if my changes generate no new warnings --- Link to Devin run: https://app.devin.ai/sessions/578b8904a5a94385b59031f9616379cc Requested by: @hariombalhara --- .../organizations/organizations.module.ts | 12 +- .../teams-memberships.controller.e2e-spec.ts | 220 ++++++++++++++++++ .../teams-memberships.controller.ts | 46 ++-- .../services/teams-memberships.service.ts | 44 +++- .../memberships/teams-memberships.module.ts | 16 +- .../teams/schedules/teams-schedules.module.ts | 2 - .../src/modules/teams/teams/teams.module.ts | 3 +- .../repository/team.repository.fixture.ts | 26 +++ 8 files changed, 326 insertions(+), 43 deletions(-) diff --git a/apps/api/v2/src/modules/organizations/organizations.module.ts b/apps/api/v2/src/modules/organizations/organizations.module.ts index c046434553..ca21829f7d 100644 --- a/apps/api/v2/src/modules/organizations/organizations.module.ts +++ b/apps/api/v2/src/modules/organizations/organizations.module.ts @@ -1,9 +1,11 @@ +import { Logger, Module } from "@nestjs/common"; +import { EventTypesModule_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.module"; import { OrganizationsEventTypesPrivateLinksController } from "@/ee/event-types-private-links/controllers/organizations-event-types-private-links.controller"; import { EventTypesPrivateLinksModule } from "@/ee/event-types-private-links/event-types-private-links.module"; -import { EventTypesModule_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.module"; import { SchedulesModule_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.module"; import { InputSchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/input-schedules.service"; import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service"; +import { OrganizationMembershipService } from "@/lib/services/organization-membership.service"; import { AppsRepository } from "@/modules/apps/apps.repository"; import { ConferencingRepository } from "@/modules/conferencing/repositories/conferencing.repository"; import { ConferencingService } from "@/modules/conferencing/services/conferencing.service"; @@ -13,7 +15,6 @@ import { ZoomVideoService } from "@/modules/conferencing/services/zoom-video.ser import { CredentialsRepository } from "@/modules/credentials/credentials.repository"; import { EmailModule } from "@/modules/email/email.module"; import { EmailService } from "@/modules/email/email.service"; -import { OrganizationMembershipService } from "@/lib/services/organization-membership.service"; import { MembershipsModule } from "@/modules/memberships/memberships.module"; import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository"; import { UserOOORepository } from "@/modules/ooo/repositories/ooo.repository"; @@ -37,8 +38,8 @@ import { OrganizationsRepository } from "@/modules/organizations/index/organizat import { OrganizationsService } from "@/modules/organizations/index/organizations.service"; import { OrganizationsMembershipsController } from "@/modules/organizations/memberships/organizations-membership.controller"; import { OrganizationsMembershipRepository } from "@/modules/organizations/memberships/organizations-membership.repository"; -import { OrganizationsMembershipOutputService } from "@/modules/organizations/memberships/services/organizations-membership-output.service"; import { OrganizationsMembershipService } from "@/modules/organizations/memberships/services/organizations-membership.service"; +import { OrganizationsMembershipOutputService } from "@/modules/organizations/memberships/services/organizations-membership-output.service"; import { OrganizationsOrganizationsModule } from "@/modules/organizations/organizations/organizations-organizations.module"; import { OrganizationsRolesModule } from "@/modules/organizations/roles/organizations-roles.module"; import { OrganizationsSchedulesController } from "@/modules/organizations/schedules/organizations-schedules.controller"; @@ -84,7 +85,6 @@ import { TeamRoutingFormWorkflowsService } from "@/modules/workflows/services/te import { WorkflowsInputService } from "@/modules/workflows/services/workflows.input.service"; import { WorkflowsOutputService } from "@/modules/workflows/services/workflows.output.service"; import { WorkflowsRepository } from "@/modules/workflows/workflows.repository"; -import { Module } from "@nestjs/common"; @Module({ imports: [ @@ -162,6 +162,7 @@ import { Module } from "@nestjs/common"; TeamsMembershipsService, TeamsMembershipsRepository, OAuthClientRepository, + Logger, ], exports: [ OrganizationsService, @@ -184,6 +185,7 @@ import { Module } from "@nestjs/common"; OrganizationsEventTypesService, OrganizationsConferencingService, OrganizationsStripeService, + OrganizationMembershipService, ], controllers: [ OrganizationsTeamsController, @@ -202,4 +204,4 @@ import { Module } from "@nestjs/common"; OrganizationsEventTypesPrivateLinksController, ], }) -export class OrganizationsModule { } +export class OrganizationsModule {} diff --git a/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.e2e-spec.ts b/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.e2e-spec.ts index 204819e7fa..2cebd8f883 100644 --- a/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.e2e-spec.ts +++ b/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.e2e-spec.ts @@ -505,6 +505,226 @@ describe("Teams Memberships Endpoints", () => { .expect(400); }); + // Auto-accept tests for sub-teams of organizations + describe("auto-accept based on email domain for org sub-teams", () => { + let orgWithAutoAccept: Team; + let subteamWithAutoAccept: Team; + let subteamEventType: EventType; + let userWithMatchingEmail: User; + let userWithUppercaseEmail: User; + let userWithMatchingEmailForOverride: User; + let userWithNonMatchingEmail: User; + + beforeAll(async () => { + // Create org with auto-accept settings + orgWithAutoAccept = await teamsRepositoryFixture.create({ + name: `auto-accept-org-${randomString()}`, + isOrganization: true, + }); + + // Create organization settings with orgAutoAcceptEmail + await teamsRepositoryFixture.createOrgSettings(orgWithAutoAccept.id, { + orgAutoAcceptEmail: "acme.com", + isOrganizationVerified: true, + isOrganizationConfigured: true, + isAdminAPIEnabled: true, + }); + + // Create subteam + subteamWithAutoAccept = await teamsRepositoryFixture.create({ + name: `auto-accept-subteam-${randomString()}`, + isOrganization: false, + parent: { connect: { id: orgWithAutoAccept.id } }, + }); + + // Create event type with assignAllTeamMembers + subteamEventType = await eventTypesRepositoryFixture.createTeamEventType({ + schedulingType: "COLLECTIVE", + team: { connect: { id: subteamWithAutoAccept.id } }, + title: "Auto Accept Event Type", + slug: "auto-accept-event-type", + length: 30, + assignAllTeamMembers: true, + bookingFields: [], + locations: [], + }); + + // Create users with different email domains + userWithMatchingEmail = await userRepositoryFixture.create({ + email: `alice-${randomString()}@acme.com`, + username: `alice-${randomString()}`, + }); + + userWithUppercaseEmail = await userRepositoryFixture.create({ + email: `bob-${randomString()}@ACME.COM`, + username: `bob-${randomString()}`, + }); + + userWithMatchingEmailForOverride = await userRepositoryFixture.create({ + email: `david-${randomString()}@acme.com`, + username: `david-${randomString()}`, + }); + + userWithNonMatchingEmail = await userRepositoryFixture.create({ + email: `charlie-${randomString()}@external.com`, + username: `charlie-${randomString()}`, + }); + + // Add users to org + await membershipsRepositoryFixture.create({ + role: "MEMBER", + accepted: true, + user: { connect: { id: userWithMatchingEmail.id } }, + team: { connect: { id: orgWithAutoAccept.id } }, + }); + + await membershipsRepositoryFixture.create({ + role: "MEMBER", + accepted: true, + user: { connect: { id: userWithUppercaseEmail.id } }, + team: { connect: { id: orgWithAutoAccept.id } }, + }); + + await membershipsRepositoryFixture.create({ + role: "MEMBER", + accepted: true, + user: { connect: { id: userWithMatchingEmailForOverride.id } }, + team: { connect: { id: orgWithAutoAccept.id } }, + }); + + await membershipsRepositoryFixture.create({ + role: "MEMBER", + accepted: true, + user: { connect: { id: userWithNonMatchingEmail.id } }, + team: { connect: { id: orgWithAutoAccept.id } }, + }); + + // Create profiles for users + await profileRepositoryFixture.create({ + uid: `usr-${userWithMatchingEmail.id}`, + username: userWithMatchingEmail.username || `user-${userWithMatchingEmail.id}`, + organization: { connect: { id: orgWithAutoAccept.id } }, + user: { connect: { id: userWithMatchingEmail.id } }, + }); + + await profileRepositoryFixture.create({ + uid: `usr-${userWithUppercaseEmail.id}`, + username: userWithUppercaseEmail.username || `user-${userWithUppercaseEmail.id}`, + organization: { connect: { id: orgWithAutoAccept.id } }, + user: { connect: { id: userWithUppercaseEmail.id } }, + }); + + await profileRepositoryFixture.create({ + uid: `usr-${userWithMatchingEmailForOverride.id}`, + username: + userWithMatchingEmailForOverride.username || `user-${userWithMatchingEmailForOverride.id}`, + organization: { connect: { id: orgWithAutoAccept.id } }, + user: { connect: { id: userWithMatchingEmailForOverride.id } }, + }); + + await profileRepositoryFixture.create({ + uid: `usr-${userWithNonMatchingEmail.id}`, + username: userWithNonMatchingEmail.username || `user-${userWithNonMatchingEmail.id}`, + organization: { connect: { id: orgWithAutoAccept.id } }, + user: { connect: { id: userWithNonMatchingEmail.id } }, + }); + + // Make teamAdmin an admin of the org and subteam for API access + await membershipsRepositoryFixture.create({ + role: "ADMIN", + accepted: true, + user: { connect: { id: teamAdmin.id } }, + team: { connect: { id: orgWithAutoAccept.id } }, + }); + + await membershipsRepositoryFixture.create({ + role: "ADMIN", + accepted: true, + user: { connect: { id: teamAdmin.id } }, + team: { connect: { id: subteamWithAutoAccept.id } }, + }); + + await profileRepositoryFixture.create({ + uid: `usr-org-${teamAdmin.id}`, + username: teamAdmin.username || `admin-${teamAdmin.id}`, + organization: { connect: { id: orgWithAutoAccept.id } }, + user: { connect: { id: teamAdmin.id } }, + }); + }); + + it("should auto-accept when email matches orgAutoAcceptEmail for sub-team", async () => { + const response = await request(app.getHttpServer()) + .post(`/v2/teams/${subteamWithAutoAccept.id}/memberships`) + .send({ + userId: userWithMatchingEmail.id, + role: "MEMBER", + } satisfies CreateTeamMembershipInput) + .expect(201); + + const responseBody: CreateTeamMembershipOutput = response.body; + expect(responseBody.data.accepted).toBe(true); + + // Verify EventTypes assignment + const eventTypes = await eventTypesRepositoryFixture.getAllTeamEventTypes(subteamWithAutoAccept.id); + const eventTypeWithAssignAll = eventTypes.find((et) => et.assignAllTeamMembers); + expect(eventTypeWithAssignAll).toBeTruthy(); + const userIsHost = eventTypeWithAssignAll?.hosts.some((h) => h.userId === userWithMatchingEmail.id); + expect(userIsHost).toBe(true); + }); + + it("should handle case-insensitive email domain matching for sub-team", async () => { + // User with email="bob@ACME.COM" should match orgAutoAcceptEmail="acme.com" + const response = await request(app.getHttpServer()) + .post(`/v2/teams/${subteamWithAutoAccept.id}/memberships`) + .send({ + userId: userWithUppercaseEmail.id, + role: "MEMBER", + } satisfies CreateTeamMembershipInput) + .expect(201); + + const responseBody: CreateTeamMembershipOutput = response.body; + expect(responseBody.data.accepted).toBe(true); + }); + + it("should ALWAYS auto-accept when email matches, even if accepted:false for sub-team", async () => { + const response = await request(app.getHttpServer()) + .post(`/v2/teams/${subteamWithAutoAccept.id}/memberships`) + .send({ + userId: userWithMatchingEmailForOverride.id, + role: "MEMBER", + accepted: false, + } satisfies CreateTeamMembershipInput) + .expect(201); + + const responseBody: CreateTeamMembershipOutput = response.body; + // Should override to true because email matches + expect(responseBody.data.accepted).toBe(true); + }); + + it("should NOT auto-accept when email does not match orgAutoAcceptEmail for sub-team", async () => { + const response = await request(app.getHttpServer()) + .post(`/v2/teams/${subteamWithAutoAccept.id}/memberships`) + .send({ + userId: userWithNonMatchingEmail.id, + role: "MEMBER", + } satisfies CreateTeamMembershipInput) + .expect(201); + + const responseBody: CreateTeamMembershipOutput = response.body; + expect(responseBody.data.accepted).toBe(false); + }); + + afterAll(async () => { + await userRepositoryFixture.deleteByEmail(userWithMatchingEmail.email); + await userRepositoryFixture.deleteByEmail(userWithUppercaseEmail.email); + await userRepositoryFixture.deleteByEmail(userWithMatchingEmailForOverride.email); + await userRepositoryFixture.deleteByEmail(userWithNonMatchingEmail.email); + await teamsRepositoryFixture.deleteOrgSettings(orgWithAutoAccept.id); + await teamsRepositoryFixture.delete(subteamWithAutoAccept.id); + await teamsRepositoryFixture.delete(orgWithAutoAccept.id); + }); + }); + afterAll(async () => { await userRepositoryFixture.deleteByEmail(teamAdmin.email); await userRepositoryFixture.deleteByEmail(teammateInvitedViaApi.email); diff --git a/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.ts b/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.ts index ff21ee24ee..ef635a69a9 100644 --- a/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.ts +++ b/apps/api/v2/src/modules/teams/memberships/controllers/teams-memberships.controller.ts @@ -1,3 +1,22 @@ +import { SUCCESS_STATUS } from "@calcom/platform-constants"; +import { updateNewTeamMemberEventTypes } from "@calcom/platform-libraries/event-types"; +import { + Body, + Controller, + Delete, + Get, + HttpCode, + HttpStatus, + Logger, + Param, + ParseIntPipe, + Patch, + Post, + Query, + UseGuards, +} from "@nestjs/common"; +import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger"; +import { plainToClass } from "class-transformer"; import { API_VERSIONS_VALUES } from "@/lib/api-versions"; import { API_KEY_HEADER } from "@/lib/docs/headers"; import { Roles } from "@/modules/auth/decorators/roles/roles.decorator"; @@ -13,26 +32,6 @@ import { GetTeamMembershipsOutput } from "@/modules/teams/memberships/outputs/ge import { TeamMembershipOutput } from "@/modules/teams/memberships/outputs/team-membership.output"; import { UpdateTeamMembershipOutput } from "@/modules/teams/memberships/outputs/update-team-membership.output"; import { TeamsMembershipsService } from "@/modules/teams/memberships/services/teams-memberships.service"; -import { - Controller, - UseGuards, - Get, - Param, - ParseIntPipe, - Query, - Delete, - Patch, - Post, - Body, - HttpCode, - HttpStatus, - Logger, -} from "@nestjs/common"; -import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger"; -import { plainToClass } from "class-transformer"; - -import { SUCCESS_STATUS } from "@calcom/platform-constants"; -import { updateNewTeamMemberEventTypes } from "@calcom/platform-libraries/event-types"; @Controller({ path: "/v2/teams/:teamId/memberships", @@ -55,13 +54,6 @@ export class TeamsMembershipsController { @Body() body: CreateTeamMembershipInput ): Promise { const membership = await this.teamsMembershipsService.createTeamMembership(teamId, body); - if (membership.accepted) { - try { - await updateNewTeamMemberEventTypes(body.userId, teamId); - } catch (err) { - this.logger.error("Could not update new team member eventTypes", err); - } - } return { status: SUCCESS_STATUS, data: plainToClass(TeamMembershipOutput, membership, { strategy: "excludeAll" }), diff --git a/apps/api/v2/src/modules/teams/memberships/services/teams-memberships.service.ts b/apps/api/v2/src/modules/teams/memberships/services/teams-memberships.service.ts index 7635773d58..db3e22b1e1 100644 --- a/apps/api/v2/src/modules/teams/memberships/services/teams-memberships.service.ts +++ b/apps/api/v2/src/modules/teams/memberships/services/teams-memberships.service.ts @@ -1,10 +1,13 @@ +import { TeamService } from "@calcom/platform-libraries"; +import { updateNewTeamMemberEventTypes } from "@calcom/platform-libraries/event-types"; +import { BadRequestException, Injectable, Logger, NotFoundException } from "@nestjs/common"; +import { OrganizationMembershipService } from "@/lib/services/organization-membership.service"; import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository"; import { CreateTeamMembershipInput } from "@/modules/teams/memberships/inputs/create-team-membership.input"; import { UpdateTeamMembershipInput } from "@/modules/teams/memberships/inputs/update-team-membership.input"; import { TeamsMembershipsRepository } from "@/modules/teams/memberships/teams-memberships.repository"; -import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common"; - -import { TeamService } from "@calcom/platform-libraries"; +import { TeamsRepository } from "@/modules/teams/teams/teams.repository"; +import { UsersRepository } from "@/modules/users/users.repository"; export const PLATFORM_USER_BEING_ADDED_TO_REGULAR_TEAM_ERROR = `Can't add user to team - the user is platform managed user but team is not because team probably was not created using OAuth credentials.`; export const REGULAR_USER_BEING_ADDED_TO_PLATFORM_TEAM_ERROR = `Can't add user to team - the user is not platform managed user but team is platform managed. Both have to be created using OAuth credentials.`; @@ -14,11 +17,44 @@ export const PLATFORM_USER_AND_PLATFORM_TEAM_CREATED_WITH_DIFFERENT_OAUTH_CLIENT export class TeamsMembershipsService { constructor( private readonly teamsMembershipsRepository: TeamsMembershipsRepository, - private readonly oAuthClientsRepository: OAuthClientRepository + private readonly oAuthClientsRepository: OAuthClientRepository, + private readonly teamsRepository: TeamsRepository, + private readonly usersRepository: UsersRepository, + private readonly orgMembershipService: OrganizationMembershipService, + private readonly logger: Logger ) {} + private async shouldAutoAccept({ teamId, userId }: { teamId: number; userId: number }): Promise { + const team = await this.teamsRepository.getById(teamId); + + if (team?.parentId) { + const user = await this.usersRepository.findById(userId); + if (user) { + const shouldAutoAccept = await this.orgMembershipService.shouldAutoAccept({ + organizationId: team.parentId, + userEmail: user.email, + }); + + return shouldAutoAccept; + } + } + + return false; + } async createTeamMembership(teamId: number, data: CreateTeamMembershipInput) { await this.canUserBeAddedToTeam(data.userId, teamId); + const shouldAutoAccept = await this.shouldAutoAccept({ teamId, userId: data.userId }); + if (shouldAutoAccept) { + data = { ...data, accepted: true }; + } + + if (data.accepted) { + try { + await updateNewTeamMemberEventTypes(data.userId, teamId); + } catch (err) { + this.logger.error("Could not update new team member eventTypes", err); + } + } const teamMembership = await this.teamsMembershipsRepository.createTeamMembership(teamId, data); return teamMembership; } diff --git a/apps/api/v2/src/modules/teams/memberships/teams-memberships.module.ts b/apps/api/v2/src/modules/teams/memberships/teams-memberships.module.ts index 0b3e729408..20c1cda63b 100644 --- a/apps/api/v2/src/modules/teams/memberships/teams-memberships.module.ts +++ b/apps/api/v2/src/modules/teams/memberships/teams-memberships.module.ts @@ -6,11 +6,21 @@ import { TeamsEventTypesModule } from "@/modules/teams/event-types/teams-event-t import { TeamsMembershipsController } from "@/modules/teams/memberships/controllers/teams-memberships.controller"; import { TeamsMembershipsService } from "@/modules/teams/memberships/services/teams-memberships.service"; import { TeamsMembershipsRepository } from "@/modules/teams/memberships/teams-memberships.repository"; -import { Module } from "@nestjs/common"; +import { TeamsModule } from "@/modules/teams/teams/teams.module"; +import { UsersModule } from "@/modules/users/users.module"; +import { Logger, Module } from "@nestjs/common"; @Module({ - imports: [PrismaModule, RedisModule, OrganizationsModule, MembershipsModule, TeamsEventTypesModule], - providers: [TeamsMembershipsRepository, TeamsMembershipsService], + imports: [ + PrismaModule, + RedisModule, + OrganizationsModule, + MembershipsModule, + TeamsEventTypesModule, + TeamsModule, + UsersModule, + ], + providers: [TeamsMembershipsRepository, TeamsMembershipsService, Logger], controllers: [TeamsMembershipsController], exports: [TeamsMembershipsService], }) diff --git a/apps/api/v2/src/modules/teams/schedules/teams-schedules.module.ts b/apps/api/v2/src/modules/teams/schedules/teams-schedules.module.ts index 9392ee5875..1a45d2fbd4 100644 --- a/apps/api/v2/src/modules/teams/schedules/teams-schedules.module.ts +++ b/apps/api/v2/src/modules/teams/schedules/teams-schedules.module.ts @@ -10,7 +10,6 @@ import { PrismaModule } from "@/modules/prisma/prisma.module"; import { RedisModule } from "@/modules/redis/redis.module"; import { TeamsEventTypesModule } from "@/modules/teams/event-types/teams-event-types.module"; import { StripeService } from "@/modules/stripe/stripe.service"; -import { TeamsMembershipsService } from "@/modules/teams/memberships/services/teams-memberships.service"; import { TeamsMembershipsRepository } from "@/modules/teams/memberships/teams-memberships.repository"; import { TeamsSchedulesController } from "@/modules/teams/schedules/controllers/teams-schedules.controller"; import { TeamsSchedulesService } from "@/modules/teams/schedules/services/teams-schedules.service"; @@ -26,7 +25,6 @@ import { Module } from "@nestjs/common"; TeamsRepository, TeamsService, TeamsMembershipsRepository, - TeamsMembershipsService, OutputSchedulesService_2024_06_11, OrganizationSchedulesRepository, StripeService, diff --git a/apps/api/v2/src/modules/teams/teams/teams.module.ts b/apps/api/v2/src/modules/teams/teams/teams.module.ts index 440229cc6a..db055ec827 100644 --- a/apps/api/v2/src/modules/teams/teams/teams.module.ts +++ b/apps/api/v2/src/modules/teams/teams/teams.module.ts @@ -2,7 +2,6 @@ import { MembershipsModule } from "@/modules/memberships/memberships.module"; import { PrismaModule } from "@/modules/prisma/prisma.module"; import { RedisModule } from "@/modules/redis/redis.module"; import { StripeModule } from "@/modules/stripe/stripe.module"; -import { TeamsMembershipsService } from "@/modules/teams/memberships/services/teams-memberships.service"; import { TeamsMembershipsRepository } from "@/modules/teams/memberships/teams-memberships.repository"; import { TeamsController } from "@/modules/teams/teams/controllers/teams.controller"; import { TeamsService } from "@/modules/teams/teams/services/teams.service"; @@ -11,7 +10,7 @@ import { Module } from "@nestjs/common"; @Module({ imports: [PrismaModule, MembershipsModule, RedisModule, StripeModule], - providers: [TeamsRepository, TeamsService, TeamsMembershipsRepository, TeamsMembershipsService], + providers: [TeamsRepository, TeamsService, TeamsMembershipsRepository], controllers: [TeamsController], exports: [TeamsRepository], }) diff --git a/apps/api/v2/test/fixtures/repository/team.repository.fixture.ts b/apps/api/v2/test/fixtures/repository/team.repository.fixture.ts index 0d2e3afb2d..3347663187 100644 --- a/apps/api/v2/test/fixtures/repository/team.repository.fixture.ts +++ b/apps/api/v2/test/fixtures/repository/team.repository.fixture.ts @@ -33,4 +33,30 @@ export class TeamRepositoryFixture { }, }); } + + async createOrgSettings( + organizationId: number, + settings: { + orgAutoAcceptEmail: string; + isOrganizationVerified?: boolean; + isOrganizationConfigured?: boolean; + isAdminAPIEnabled?: boolean; + } + ) { + return this.prismaWriteClient.organizationSettings.create({ + data: { + organizationId, + orgAutoAcceptEmail: settings.orgAutoAcceptEmail, + isOrganizationVerified: settings.isOrganizationVerified, + isOrganizationConfigured: settings.isOrganizationConfigured, + isAdminAPIEnabled: settings.isAdminAPIEnabled, + }, + }); + } + + async deleteOrgSettings(organizationId: number) { + return this.prismaWriteClient.organizationSettings.deleteMany({ + where: { organizationId }, + }); + } }