chore: rename DWD to DelegationCredential (#19703)
* chore: rename DWD to DelegationCredential * fixup! chore: rename DWD to DelegationCredential * fixup! fixup! chore: rename DWD to DelegationCredential * fixup! Merge branch 'main' into rename-domain-wide-delegation * fixup! fixup! Merge branch 'main' into rename-domain-wide-delegation * fixup! fixup! fixup! Merge branch 'main' into rename-domain-wide-delegation
This commit is contained in:
@@ -210,7 +210,7 @@ export class EventTypesAtomService {
|
||||
credentials = credentials.concat(teamAppCredentials);
|
||||
}
|
||||
}
|
||||
//TODO: enrich credentials for DWD
|
||||
//TODO: enrich credentials for DelegationCredential
|
||||
const enabledApps = await getEnabledAppsFromCredentials(credentials, {
|
||||
where: { slug },
|
||||
});
|
||||
|
||||
+2
-2
@@ -29,12 +29,12 @@ export class DestinationCalendarsController {
|
||||
@Body() input: DestinationCalendarsInputBodyDto,
|
||||
@GetUser() user: UserWithProfile
|
||||
): Promise<DestinationCalendarsOutputResponseDto> {
|
||||
const { integration, externalId, domainWideDelegationCredentialId } = input;
|
||||
const { integration, externalId, delegationCredentialId } = input;
|
||||
const updatedDestinationCalendar = await this.destinationCalendarsService.updateDestinationCalendars(
|
||||
integration,
|
||||
externalId,
|
||||
user.id,
|
||||
domainWideDelegationCredentialId
|
||||
delegationCredentialId
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -12,21 +12,21 @@ export class DestinationCalendarsRepository {
|
||||
userId: number,
|
||||
primaryEmail: string | null,
|
||||
credentialId?: number,
|
||||
domainWideDelegationCredentialId?: string
|
||||
delegationCredentialId?: string
|
||||
) {
|
||||
return await this.dbWrite.prisma.destinationCalendar.upsert({
|
||||
update: {
|
||||
integration,
|
||||
externalId,
|
||||
...(credentialId ? { credentialId } : {}),
|
||||
...(domainWideDelegationCredentialId ? { domainWideDelegationCredentialId } : {}),
|
||||
...(delegationCredentialId ? { delegationCredentialId } : {}),
|
||||
primaryEmail,
|
||||
},
|
||||
create: {
|
||||
integration,
|
||||
externalId,
|
||||
...(credentialId ? { credentialId } : {}),
|
||||
...(domainWideDelegationCredentialId ? { domainWideDelegationCredentialId } : {}),
|
||||
...(delegationCredentialId ? { delegationCredentialId } : {}),
|
||||
primaryEmail,
|
||||
userId,
|
||||
},
|
||||
|
||||
@@ -37,5 +37,5 @@ export class DestinationCalendarsInputBodyDto {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@ApiPropertyOptional()
|
||||
readonly domainWideDelegationCredentialId?: string;
|
||||
readonly delegationCredentialId?: string;
|
||||
}
|
||||
|
||||
+11
-11
@@ -14,10 +14,10 @@ export class DestinationCalendarsService {
|
||||
integration: string,
|
||||
externalId: string,
|
||||
userId: number,
|
||||
domainWideDelegationCredentialId?: string
|
||||
delegationCredentialId?: string
|
||||
) {
|
||||
// note(Lauris): todo remove the log but leaving this now to confirm domainWideDelegationCredentialId is received
|
||||
console.log("debug: domainWideDelegationCredentialId", domainWideDelegationCredentialId);
|
||||
// note(Lauris): todo remove the log but leaving this now to confirm delegationCredentialId is received
|
||||
console.log("debug: delegationCredentialId", delegationCredentialId);
|
||||
const userCalendars = await this.calendarsService.getCalendars(userId);
|
||||
const allCalendars: Calendar[] = userCalendars.connectedCalendars
|
||||
.map((cal: ConnectedCalendar) => cal.calendars ?? [])
|
||||
@@ -27,25 +27,25 @@ export class DestinationCalendarsService {
|
||||
cal.externalId === externalId && cal.integration === integration && cal.readOnly === false
|
||||
)?.credentialId;
|
||||
|
||||
if (!domainWideDelegationCredentialId && !credentialId) {
|
||||
if (!delegationCredentialId && !credentialId) {
|
||||
throw new NotFoundException(`Could not find calendar ${externalId}`);
|
||||
}
|
||||
|
||||
const dwdCalendar = domainWideDelegationCredentialId
|
||||
const delegatedCalendar = delegationCredentialId
|
||||
? allCalendars.find(
|
||||
(cal: Calendar) =>
|
||||
cal.externalId === externalId &&
|
||||
cal.integration === integration &&
|
||||
cal.domainWideDelegationCredentialId === domainWideDelegationCredentialId
|
||||
cal.delegationCredentialId === delegationCredentialId
|
||||
)
|
||||
: undefined;
|
||||
|
||||
if (domainWideDelegationCredentialId && !dwdCalendar) {
|
||||
if (delegationCredentialId && !delegatedCalendar) {
|
||||
throw new NotFoundException(`Could not find calendar ${externalId}`);
|
||||
}
|
||||
|
||||
const primaryEmail = dwdCalendar
|
||||
? (dwdCalendar.primary && dwdCalendar?.email) || undefined
|
||||
const primaryEmail = delegatedCalendar
|
||||
? (delegatedCalendar.primary && delegatedCalendar?.email) || undefined
|
||||
: allCalendars.find((cal: Calendar) => cal.primary && cal.credentialId === credentialId)?.email;
|
||||
|
||||
const {
|
||||
@@ -58,8 +58,8 @@ export class DestinationCalendarsService {
|
||||
externalId,
|
||||
userId,
|
||||
primaryEmail ?? null,
|
||||
dwdCalendar ? undefined : credentialId,
|
||||
dwdCalendar ? domainWideDelegationCredentialId : undefined
|
||||
delegatedCalendar ? undefined : credentialId,
|
||||
delegatedCalendar ? delegationCredentialId : undefined
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+2
-2
@@ -2,12 +2,12 @@ import {
|
||||
GoogleServiceAccountKeyInput,
|
||||
ServiceAccountKeyValidator,
|
||||
MicrosoftServiceAccountKeyInput,
|
||||
} from "@/modules/organizations/dwd/inputs/service-account-key.input";
|
||||
} from "@/modules/organizations/delegation-credentials/inputs/service-account-key.input";
|
||||
import { ApiProperty, getSchemaPath } from "@nestjs/swagger";
|
||||
import { Expose, Type } from "class-transformer";
|
||||
import { IsString, IsNotEmpty, ValidateNested, Validate } from "class-validator";
|
||||
|
||||
export class CreateDwdInput {
|
||||
export class CreateDelegationCredentialInput {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty()
|
||||
+2
-2
@@ -2,12 +2,12 @@ import {
|
||||
GoogleServiceAccountKeyInput,
|
||||
MicrosoftServiceAccountKeyInput,
|
||||
ServiceAccountKeyValidator,
|
||||
} from "@/modules/organizations/dwd/inputs/service-account-key.input";
|
||||
} from "@/modules/organizations/delegation-credentials/inputs/service-account-key.input";
|
||||
import { ApiPropertyOptional, getSchemaPath } from "@nestjs/swagger";
|
||||
import { Expose, plainToClass, Transform, Type } from "class-transformer";
|
||||
import { IsBoolean, IsOptional, Validate, ValidateNested } from "class-validator";
|
||||
|
||||
export class UpdateDwdInput {
|
||||
export class UpdateDelegationCredentialInput {
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@ApiPropertyOptional()
|
||||
+29
-20
@@ -7,11 +7,11 @@ import { PlatformPlanGuard } from "@/modules/auth/guards/billing/platform-plan.g
|
||||
import { IsAdminAPIEnabledGuard } from "@/modules/auth/guards/organizations/is-admin-api-enabled.guard";
|
||||
import { IsOrgGuard } from "@/modules/auth/guards/organizations/is-org.guard";
|
||||
import { RolesGuard } from "@/modules/auth/guards/roles/roles.guard";
|
||||
import { UpdateDwdInput } from "@/modules/organizations/dwd/inputs/update-dwd.input";
|
||||
import { CreateDwdOutput } from "@/modules/organizations/dwd/outputs/create-dwd.output";
|
||||
import { DwdOutput } from "@/modules/organizations/dwd/outputs/dwd.output";
|
||||
import { UpdateDwdOutput } from "@/modules/organizations/dwd/outputs/update-dwd.output";
|
||||
import { OrganizationsDwdService } from "@/modules/organizations/dwd/services/organizations-dwd.service";
|
||||
import { UpdateDelegationCredentialInput } from "@/modules/organizations/delegation-credentials/inputs/update-delegation-credential.input";
|
||||
import { CreateDelegationCredentialOutput } from "@/modules/organizations/delegation-credentials/outputs/create-delegation-credential.output";
|
||||
import { DelegationCredentialOutput } from "@/modules/organizations/delegation-credentials/outputs/delegation-credential.output";
|
||||
import { UpdateDelegationCredentialOutput } from "@/modules/organizations/delegation-credentials/outputs/update-delegation-credential.output";
|
||||
import { OrganizationsDelegationCredentialService } from "@/modules/organizations/delegation-credentials/services/organizations-delegation-credential.service";
|
||||
import {
|
||||
Controller,
|
||||
UseGuards,
|
||||
@@ -29,7 +29,7 @@ import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
import { CreateDwdInput } from "./inputs/create-dwd.input";
|
||||
import { CreateDelegationCredentialInput } from "./inputs/create-delegation-credential.input";
|
||||
|
||||
@Controller({
|
||||
path: "/v2/organizations/:orgId/delegation-credentials",
|
||||
@@ -37,23 +37,27 @@ import { CreateDwdInput } from "./inputs/create-dwd.input";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Delegation Credentials")
|
||||
export class OrganizationsDwdController {
|
||||
constructor(private readonly dwdService: OrganizationsDwdService) {}
|
||||
export class OrganizationsDelegationCredentialController {
|
||||
constructor(private readonly delegationCredentialService: OrganizationsDelegationCredentialService) {}
|
||||
|
||||
@Post("/")
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
@Roles("ORG_ADMIN")
|
||||
@PlatformPlan("SCALE")
|
||||
@ApiOperation({ summary: "Save delegation credentials for your organization." })
|
||||
async createDwd(
|
||||
async createDelegationCredential(
|
||||
@Param("orgId", ParseIntPipe) orgId: number,
|
||||
@GetUser() dwdServiceAccountUser: User,
|
||||
@Body() body: CreateDwdInput
|
||||
): Promise<CreateDwdOutput> {
|
||||
const dwd = await this.dwdService.createDwd(orgId, dwdServiceAccountUser, body);
|
||||
@GetUser() delegatedServiceAccountUser: User,
|
||||
@Body() body: CreateDelegationCredentialInput
|
||||
): Promise<CreateDelegationCredentialOutput> {
|
||||
const delegationCredential = await this.delegationCredentialService.createDelegationCredential(
|
||||
orgId,
|
||||
delegatedServiceAccountUser,
|
||||
body
|
||||
);
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: plainToClass(DwdOutput, dwd, { strategy: "excludeAll" }),
|
||||
data: plainToClass(DelegationCredentialOutput, delegationCredential, { strategy: "excludeAll" }),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,16 +65,21 @@ export class OrganizationsDwdController {
|
||||
@Roles("ORG_ADMIN")
|
||||
@PlatformPlan("SCALE")
|
||||
@ApiOperation({ summary: "Update delegation credentials of your organization." })
|
||||
async updateDwd(
|
||||
async updateDelegationCredential(
|
||||
@Param("orgId", ParseIntPipe) orgId: number,
|
||||
@GetUser() dwdServiceAccountUser: User,
|
||||
@Body() body: UpdateDwdInput,
|
||||
@GetUser() delegatedServiceAccountUser: User,
|
||||
@Body() body: UpdateDelegationCredentialInput,
|
||||
@Param("credentialId") credentialId: string
|
||||
): Promise<UpdateDwdOutput> {
|
||||
const dwd = await this.dwdService.updateDwd(orgId, credentialId, dwdServiceAccountUser, body);
|
||||
): Promise<UpdateDelegationCredentialOutput> {
|
||||
const delegationCredential = await this.delegationCredentialService.updateDelegationCredential(
|
||||
orgId,
|
||||
credentialId,
|
||||
delegatedServiceAccountUser,
|
||||
body
|
||||
);
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: plainToClass(DwdOutput, dwd, { strategy: "excludeAll" }),
|
||||
data: plainToClass(DelegationCredentialOutput, delegationCredential, { strategy: "excludeAll" }),
|
||||
};
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { MembershipsModule } from "@/modules/memberships/memberships.module";
|
||||
import { OrganizationsDelegationCredentialController } from "@/modules/organizations/delegation-credentials/organizations-delegation-credential.controller";
|
||||
import { OrganizationsDelegationCredentialRepository } from "@/modules/organizations/delegation-credentials/organizations-delegation-credential.repository";
|
||||
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RedisModule } from "@/modules/redis/redis.module";
|
||||
import { StripeModule } from "@/modules/stripe/stripe.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
import { OrganizationsDelegationCredentialService } from "./services/organizations-delegation-credential.service";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, StripeModule, RedisModule, MembershipsModule],
|
||||
providers: [
|
||||
OrganizationsDelegationCredentialService,
|
||||
OrganizationsDelegationCredentialRepository,
|
||||
OrganizationsRepository,
|
||||
],
|
||||
controllers: [OrganizationsDelegationCredentialController],
|
||||
})
|
||||
export class OrganizationsDelegationCredentialModule {}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsDelegationCredentialRepository {
|
||||
constructor(private readonly dbRead: PrismaReadService) {}
|
||||
|
||||
async findById(delegationCredentialId: string) {
|
||||
return this.dbRead.prisma.delegationCredential.findUnique({ where: { id: delegationCredentialId } });
|
||||
}
|
||||
|
||||
async findByIdWithWorkspacePlatform(delegationCredentialId: string) {
|
||||
return this.dbRead.prisma.delegationCredential.findUnique({
|
||||
where: { id: delegationCredentialId },
|
||||
include: { workspacePlatform: true },
|
||||
});
|
||||
}
|
||||
|
||||
async updateIncludeWorkspacePlatform(
|
||||
delegationCredentialId: string,
|
||||
data: Prisma.DelegationCredentialUncheckedUpdateInput
|
||||
) {
|
||||
return this.dbRead.prisma.delegationCredential.update({
|
||||
where: { id: delegationCredentialId },
|
||||
data,
|
||||
include: { workspacePlatform: true },
|
||||
});
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,20 +1,20 @@
|
||||
import { DwdOutput } from "@/modules/organizations/dwd/outputs/dwd.output";
|
||||
import { DelegationCredentialOutput } from "@/modules/organizations/delegation-credentials/outputs/delegation-credential.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class UpdateDwdOutput {
|
||||
export class CreateDelegationCredentialOutput {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({
|
||||
type: DwdOutput,
|
||||
type: DelegationCredentialOutput,
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => DwdOutput)
|
||||
data!: DwdOutput;
|
||||
@Type(() => DelegationCredentialOutput)
|
||||
data!: DelegationCredentialOutput;
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ class WorkspacePlatformDto {
|
||||
slug!: string;
|
||||
}
|
||||
|
||||
export class DwdOutput {
|
||||
export class DelegationCredentialOutput {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@Expose()
|
||||
+5
-5
@@ -1,20 +1,20 @@
|
||||
import { DwdOutput } from "@/modules/organizations/dwd/outputs/dwd.output";
|
||||
import { DelegationCredentialOutput } from "@/modules/organizations/delegation-credentials/outputs/delegation-credential.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class CreateDwdOutput {
|
||||
export class UpdateDelegationCredentialOutput {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({
|
||||
type: DwdOutput,
|
||||
type: DelegationCredentialOutput,
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => DwdOutput)
|
||||
data!: DwdOutput;
|
||||
@Type(() => DelegationCredentialOutput)
|
||||
data!: DelegationCredentialOutput;
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
import { CreateDelegationCredentialInput } from "@/modules/organizations/delegation-credentials/inputs/create-delegation-credential.input";
|
||||
import {
|
||||
GoogleServiceAccountKeyInput,
|
||||
MicrosoftServiceAccountKeyInput,
|
||||
} from "@/modules/organizations/delegation-credentials/inputs/service-account-key.input";
|
||||
import { UpdateDelegationCredentialInput } from "@/modules/organizations/delegation-credentials/inputs/update-delegation-credential.input";
|
||||
import { OrganizationsDelegationCredentialRepository } from "@/modules/organizations/delegation-credentials/organizations-delegation-credential.repository";
|
||||
import { DelegationCredentialOutput } from "@/modules/organizations/delegation-credentials/outputs/delegation-credential.output";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { User } from "@prisma/client";
|
||||
|
||||
import {
|
||||
addDelegationCredential,
|
||||
toggleDelegationCredentialEnabled,
|
||||
encryptServiceAccountKey,
|
||||
} from "@calcom/platform-libraries";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsDelegationCredentialService {
|
||||
constructor(
|
||||
private readonly organizationsDelegationCredentialRepository: OrganizationsDelegationCredentialRepository
|
||||
) {}
|
||||
async createDelegationCredential(
|
||||
orgId: number,
|
||||
delegatedServiceAccountUser: User,
|
||||
body: CreateDelegationCredentialInput
|
||||
) {
|
||||
const delegationCredential = await addDelegationCredential({
|
||||
input: body,
|
||||
ctx: { user: { id: delegatedServiceAccountUser.id, organizationId: orgId } },
|
||||
});
|
||||
return delegationCredential;
|
||||
}
|
||||
|
||||
async updateDelegationCredential(
|
||||
orgId: number,
|
||||
delegationCredentialId: string,
|
||||
delegatedServiceAccountUser: User,
|
||||
body: UpdateDelegationCredentialInput
|
||||
) {
|
||||
if (body.enabled !== undefined) {
|
||||
await this.updateDelegationCredentialEnabled(
|
||||
orgId,
|
||||
delegationCredentialId,
|
||||
delegatedServiceAccountUser,
|
||||
body.enabled
|
||||
);
|
||||
}
|
||||
if (body.serviceAccountKey !== undefined) {
|
||||
await this.updateDelegationCredentialServiceAccountKey(delegationCredentialId, body.serviceAccountKey);
|
||||
}
|
||||
const delegationCredential =
|
||||
await this.organizationsDelegationCredentialRepository.findByIdWithWorkspacePlatform(
|
||||
delegationCredentialId
|
||||
);
|
||||
if (!delegationCredential) {
|
||||
throw new NotFoundException(`DelegationCredential with id ${delegationCredentialId} not found`);
|
||||
}
|
||||
|
||||
return delegationCredential;
|
||||
}
|
||||
|
||||
async updateDelegationCredentialEnabled(
|
||||
orgId: number,
|
||||
delegationCredentialId: string,
|
||||
delegatedServiceAccountUser: User,
|
||||
enabled: boolean
|
||||
) {
|
||||
const handlerUser = {
|
||||
id: delegatedServiceAccountUser.id,
|
||||
email: delegatedServiceAccountUser.email,
|
||||
organizationId: orgId,
|
||||
};
|
||||
const handlerBody = { id: delegationCredentialId, enabled };
|
||||
const delegationCredential = await toggleDelegationCredentialEnabled(handlerUser, handlerBody);
|
||||
return delegationCredential;
|
||||
}
|
||||
|
||||
async updateDelegationCredentialServiceAccountKey(
|
||||
delegationCredentialId: string,
|
||||
serviceAccountKey: GoogleServiceAccountKeyInput | MicrosoftServiceAccountKeyInput
|
||||
) {
|
||||
const encryptedServiceAccountKey = encryptServiceAccountKey(serviceAccountKey);
|
||||
const delegationCredential =
|
||||
await this.organizationsDelegationCredentialRepository.updateIncludeWorkspacePlatform(
|
||||
delegationCredentialId,
|
||||
{
|
||||
serviceAccountKey: encryptedServiceAccountKey,
|
||||
}
|
||||
);
|
||||
return delegationCredential;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { MembershipsModule } from "@/modules/memberships/memberships.module";
|
||||
import { OrganizationsDwdController } from "@/modules/organizations/dwd/organizations-dwd.controller";
|
||||
import { OrganizationsDwdRepository } from "@/modules/organizations/dwd/organizations-dwd.repository";
|
||||
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RedisModule } from "@/modules/redis/redis.module";
|
||||
import { StripeModule } from "@/modules/stripe/stripe.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
import { OrganizationsDwdService } from "./services/organizations-dwd.service";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, StripeModule, RedisModule, MembershipsModule],
|
||||
providers: [OrganizationsDwdService, OrganizationsDwdRepository, OrganizationsRepository],
|
||||
controllers: [OrganizationsDwdController],
|
||||
})
|
||||
export class OrganizationsDwdModule {}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsDwdRepository {
|
||||
constructor(private readonly dbRead: PrismaReadService) {}
|
||||
|
||||
async findById(dwdId: string) {
|
||||
return this.dbRead.prisma.domainWideDelegation.findUnique({ where: { id: dwdId } });
|
||||
}
|
||||
|
||||
async findByIdWithWorkspacePlatform(dwdId: string) {
|
||||
return this.dbRead.prisma.domainWideDelegation.findUnique({
|
||||
where: { id: dwdId },
|
||||
include: { workspacePlatform: true },
|
||||
});
|
||||
}
|
||||
|
||||
async updateIncludeWorkspacePlatform(dwdId: string, data: Prisma.DomainWideDelegationUncheckedUpdateInput) {
|
||||
return this.dbRead.prisma.domainWideDelegation.update({
|
||||
where: { id: dwdId },
|
||||
data,
|
||||
include: { workspacePlatform: true },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { CreateDwdInput } from "@/modules/organizations/dwd/inputs/create-dwd.input";
|
||||
import {
|
||||
GoogleServiceAccountKeyInput,
|
||||
MicrosoftServiceAccountKeyInput,
|
||||
} from "@/modules/organizations/dwd/inputs/service-account-key.input";
|
||||
import { UpdateDwdInput } from "@/modules/organizations/dwd/inputs/update-dwd.input";
|
||||
import { OrganizationsDwdRepository } from "@/modules/organizations/dwd/organizations-dwd.repository";
|
||||
import { DwdOutput } from "@/modules/organizations/dwd/outputs/dwd.output";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { User } from "@prisma/client";
|
||||
|
||||
import { addDwd, toggleDwdEnabled, encryptServiceAccountKey } from "@calcom/platform-libraries";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsDwdService {
|
||||
constructor(private readonly organizationsDwdRepository: OrganizationsDwdRepository) {}
|
||||
async createDwd(orgId: number, dwdServiceAccountUser: User, body: CreateDwdInput) {
|
||||
console.log("asap body", JSON.stringify(body, null, 2));
|
||||
const dwd = await addDwd({
|
||||
input: body,
|
||||
ctx: { user: { id: dwdServiceAccountUser.id, organizationId: orgId } },
|
||||
});
|
||||
return dwd;
|
||||
}
|
||||
|
||||
async updateDwd(orgId: number, dwdId: string, dwdServiceAccountUser: User, body: UpdateDwdInput) {
|
||||
if (body.enabled !== undefined) {
|
||||
await this.updateDwdEnabled(orgId, dwdId, dwdServiceAccountUser, body.enabled);
|
||||
}
|
||||
if (body.serviceAccountKey !== undefined) {
|
||||
await this.updateDwdServiceAccountKey(dwdId, body.serviceAccountKey);
|
||||
}
|
||||
const dwd = await this.organizationsDwdRepository.findByIdWithWorkspacePlatform(dwdId);
|
||||
if (!dwd) {
|
||||
throw new NotFoundException(`DWD with id ${dwdId} not found`);
|
||||
}
|
||||
|
||||
return dwd;
|
||||
}
|
||||
|
||||
async updateDwdEnabled(orgId: number, dwdId: string, dwdServiceAccountUser: User, enabled: boolean) {
|
||||
const handlerUser = {
|
||||
id: dwdServiceAccountUser.id,
|
||||
email: dwdServiceAccountUser.email,
|
||||
organizationId: orgId,
|
||||
};
|
||||
const handlerBody = { id: dwdId, enabled };
|
||||
const dwd = await toggleDwdEnabled(handlerUser, handlerBody);
|
||||
return dwd;
|
||||
}
|
||||
|
||||
async updateDwdServiceAccountKey(
|
||||
dwdId: string,
|
||||
serviceAccountKey: GoogleServiceAccountKeyInput | MicrosoftServiceAccountKeyInput
|
||||
) {
|
||||
const encryptedServiceAccountKey = encryptServiceAccountKey(serviceAccountKey);
|
||||
const dwd = await this.organizationsDwdRepository.updateIncludeWorkspacePlatform(dwdId, {
|
||||
serviceAccountKey: encryptedServiceAccountKey,
|
||||
});
|
||||
return dwd;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { OrganizationAttributesService } from "@/modules/organizations/attribute
|
||||
import { OrganizationAttributeOptionRepository } from "@/modules/organizations/attributes/options/organization-attribute-options.repository";
|
||||
import { OrganizationsAttributesOptionsController } from "@/modules/organizations/attributes/options/organizations-attributes-options.controller";
|
||||
import { OrganizationAttributeOptionService } from "@/modules/organizations/attributes/options/services/organization-attributes-option.service";
|
||||
import { OrganizationsDwdModule } from "@/modules/organizations/dwd/organizations-dwd.module";
|
||||
import { OrganizationsDelegationCredentialModule } from "@/modules/organizations/delegation-credentials/organizations-delegation-credential.module";
|
||||
import { OrganizationsEventTypesController } from "@/modules/organizations/event-types/organizations-event-types.controller";
|
||||
import { OrganizationsEventTypesRepository } from "@/modules/organizations/event-types/organizations-event-types.repository";
|
||||
import { OutputTeamEventTypesResponsePipe } from "@/modules/organizations/event-types/pipes/team-event-types-response.transformer";
|
||||
@@ -65,7 +65,7 @@ import { Module } from "@nestjs/common";
|
||||
EventTypesModule_2024_06_14,
|
||||
TeamsEventTypesModule,
|
||||
TeamsModule,
|
||||
OrganizationsDwdModule,
|
||||
OrganizationsDelegationCredentialModule,
|
||||
OrganizationsOrganizationsModule,
|
||||
OrganizationsTeamsRoutingFormsModule,
|
||||
],
|
||||
|
||||
@@ -12,7 +12,7 @@ export class SelectedCalendarsInputDto {
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
readonly domainWideDelegationCredentialId?: string;
|
||||
readonly delegationCredentialId?: string;
|
||||
}
|
||||
|
||||
export class SelectedCalendarsQueryParamsInputDto {
|
||||
@@ -27,5 +27,5 @@ export class SelectedCalendarsQueryParamsInputDto {
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
readonly domainWideDelegationCredentialId?: string;
|
||||
readonly delegationCredentialId?: string;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
|
||||
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
|
||||
import { AppsRepository } from "@/modules/apps/apps.repository";
|
||||
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
|
||||
import { OrganizationsDwdRepository } from "@/modules/organizations/dwd/organizations-dwd.repository";
|
||||
import { OrganizationsDelegationCredentialRepository } from "@/modules/organizations/delegation-credentials/organizations-delegation-credential.repository";
|
||||
import { OrganizationsMembershipRepository } from "@/modules/organizations/memberships/organizations-membership.repository";
|
||||
import { OrganizationsMembershipService } from "@/modules/organizations/memberships/services/organizations-membership.service";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
@@ -22,7 +22,7 @@ import { Module } from "@nestjs/common";
|
||||
CredentialsRepository,
|
||||
AppsRepository,
|
||||
OrganizationsMembershipService,
|
||||
OrganizationsDwdRepository,
|
||||
OrganizationsDelegationCredentialRepository,
|
||||
OrganizationsMembershipRepository,
|
||||
SelectedCalendarsService,
|
||||
],
|
||||
|
||||
@@ -89,7 +89,7 @@ export class SelectedCalendarsRepository {
|
||||
userId: number,
|
||||
integration: string,
|
||||
externalId: string,
|
||||
domainWideDelegationCredentialId?: string
|
||||
delegationCredentialId?: string
|
||||
) {
|
||||
// Using deleteMany because userId_externalId_integration_eventTypeId is a unique constraint but with eventTypeId being nullable, causing it to be not used as a unique constraint
|
||||
const records = await this.dbWrite.prisma.selectedCalendar.findMany({
|
||||
@@ -97,7 +97,7 @@ export class SelectedCalendarsRepository {
|
||||
userId,
|
||||
externalId,
|
||||
integration,
|
||||
domainWideDelegationCredentialId,
|
||||
delegationCredentialId,
|
||||
...ensureUserLevelWhere,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
|
||||
import { OrganizationsDwdRepository } from "@/modules/organizations/dwd/organizations-dwd.repository";
|
||||
import { OrganizationsDelegationCredentialRepository } from "@/modules/organizations/delegation-credentials/organizations-delegation-credential.repository";
|
||||
import { OrganizationsMembershipService } from "@/modules/organizations/memberships/services/organizations-membership.service";
|
||||
import {
|
||||
SelectedCalendarsInputDto,
|
||||
@@ -11,7 +11,9 @@ import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
|
||||
import { SelectedCalendarRepository } from "@calcom/platform-libraries";
|
||||
|
||||
type SelectedCalendarsInputDwd = SelectedCalendarsInputDto & { domainWideDelegationCredentialId: string };
|
||||
type SelectedCalendarsInputDelegationCredential = SelectedCalendarsInputDto & {
|
||||
delegationCredentialId: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class SelectedCalendarsService {
|
||||
@@ -19,16 +21,16 @@ export class SelectedCalendarsService {
|
||||
private readonly calendarsService: CalendarsService,
|
||||
private readonly selectedCalendarsRepository: SelectedCalendarsRepository,
|
||||
private readonly organizationsMembershipService: OrganizationsMembershipService,
|
||||
private readonly organizationsDwdRepository: OrganizationsDwdRepository
|
||||
private readonly organizationsDelegationCredentialRepository: OrganizationsDelegationCredentialRepository
|
||||
) {}
|
||||
|
||||
async addSelectedCalendar(user: UserWithProfile, input: SelectedCalendarsInputDto) {
|
||||
if (input.domainWideDelegationCredentialId) {
|
||||
const dwdInput = {
|
||||
if (input.delegationCredentialId) {
|
||||
const delegationCredentialInput = {
|
||||
...input,
|
||||
domainWideDelegationCredentialId: input.domainWideDelegationCredentialId,
|
||||
delegationCredentialId: input.delegationCredentialId,
|
||||
};
|
||||
return this.addSelectedCalendarDwd(user, dwdInput);
|
||||
return this.addSelectedCalendarDelegationCredential(user, delegationCredentialInput);
|
||||
}
|
||||
return this.addSelectedCalendarUser(user, input);
|
||||
}
|
||||
@@ -47,35 +49,42 @@ export class SelectedCalendarsService {
|
||||
return userSelectedCalendar;
|
||||
}
|
||||
|
||||
private async addSelectedCalendarDwd(user: UserWithProfile, selectedCalendar: SelectedCalendarsInputDwd) {
|
||||
const isMemberOfOrganization = await this.isMemberOfDwdOrganization(
|
||||
private async addSelectedCalendarDelegationCredential(
|
||||
user: UserWithProfile,
|
||||
selectedCalendar: SelectedCalendarsInputDelegationCredential
|
||||
) {
|
||||
const isMemberOfOrganization = await this.isMemberOfDelegationCredentialOrganization(
|
||||
user.id,
|
||||
selectedCalendar.domainWideDelegationCredentialId
|
||||
selectedCalendar.delegationCredentialId
|
||||
);
|
||||
if (!isMemberOfOrganization) {
|
||||
throw new NotFoundException("User is not a member of the organization that owns the DWD credential");
|
||||
throw new NotFoundException(
|
||||
"User is not a member of the organization that owns the Delegation credential"
|
||||
);
|
||||
}
|
||||
|
||||
const { integration, externalId, credentialId, domainWideDelegationCredentialId } = selectedCalendar;
|
||||
const dwdSelectedCalendar = await SelectedCalendarRepository.upsert({
|
||||
const { integration, externalId, credentialId, delegationCredentialId } = selectedCalendar;
|
||||
const delegationCredentialSelectedCalendar = await SelectedCalendarRepository.upsert({
|
||||
userId: user.id,
|
||||
integration,
|
||||
externalId,
|
||||
credentialId,
|
||||
domainWideDelegationCredentialId,
|
||||
delegationCredentialId,
|
||||
eventTypeId: null,
|
||||
});
|
||||
return dwdSelectedCalendar;
|
||||
return delegationCredentialSelectedCalendar;
|
||||
}
|
||||
|
||||
private async isMemberOfDwdOrganization(userId: number, domainWideDelegationCredentialId: string) {
|
||||
const dwd = await this.organizationsDwdRepository.findById(domainWideDelegationCredentialId);
|
||||
if (!dwd) {
|
||||
throw new NotFoundException("DWD with provided domainWideDelegationCredentialId not found");
|
||||
private async isMemberOfDelegationCredentialOrganization(userId: number, delegationCredentialId: string) {
|
||||
const delegationCredential = await this.organizationsDelegationCredentialRepository.findById(
|
||||
delegationCredentialId
|
||||
);
|
||||
if (!delegationCredential) {
|
||||
throw new NotFoundException("DelegationCredential with provided delegationCredentialId not found");
|
||||
}
|
||||
|
||||
const isMemberOfOrganization = await this.organizationsMembershipService.getOrgMembershipByUserId(
|
||||
dwd.organizationId,
|
||||
delegationCredential.organizationId,
|
||||
userId
|
||||
);
|
||||
|
||||
@@ -86,17 +95,19 @@ export class SelectedCalendarsService {
|
||||
selectedCalendar: SelectedCalendarsQueryParamsInputDto,
|
||||
user: UserWithProfile
|
||||
) {
|
||||
const { integration, externalId, credentialId, domainWideDelegationCredentialId } = selectedCalendar;
|
||||
const { integration, externalId, credentialId, delegationCredentialId } = selectedCalendar;
|
||||
|
||||
if (!domainWideDelegationCredentialId) {
|
||||
if (!delegationCredentialId) {
|
||||
await this.calendarsService.checkCalendarCredentials(Number(credentialId), user.id);
|
||||
} else {
|
||||
const isMemberOfOrganization = await this.isMemberOfDwdOrganization(
|
||||
const isMemberOfOrganization = await this.isMemberOfDelegationCredentialOrganization(
|
||||
user.id,
|
||||
domainWideDelegationCredentialId
|
||||
delegationCredentialId
|
||||
);
|
||||
if (!isMemberOfOrganization) {
|
||||
throw new NotFoundException("User is not a member of the organization that owns the DWD credential");
|
||||
throw new NotFoundException(
|
||||
"User is not a member of the organization that owns the Delegation credential"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +115,7 @@ export class SelectedCalendarsService {
|
||||
user.id,
|
||||
integration,
|
||||
externalId,
|
||||
domainWideDelegationCredentialId
|
||||
delegationCredentialId
|
||||
);
|
||||
|
||||
return removedCalendarEntry;
|
||||
|
||||
Reference in New Issue
Block a user