refactor: platform default event types (#19225)
* feat: add areDefaultEventTypesEnabled to PlatformOAuthClient * feat: specify areDefaultEventTypesEnabled when creating OAuth client * feat: specify areDefaultEventTypesEnabled when updating OAuth client * feat: display areDefaultEventTypesEnabled in OAuth clients list * refactor: set areDefaultEventTypesEnabled by default to false on API level * feat: v2 API CREATE managed user toggle default event types * refactor: centralize OAuth inputs and outputs in platform/types * fix: correct response types for OAuth hooks * refactor: web/lib/hooks/settings/platform/oauth-clients/useOAuthClients.ts * refactor: web/lib/hooks/settings/platform/oauth-clients/useOAuthClients.ts * refactor: split web OAuth hooks into separate files * refactor: split web OAuth hooks into separate files * docs: v2 OAuth client inputs and outputs * refactor: update and create oauth client inputs
This commit is contained in:
+64
-5
@@ -74,6 +74,7 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let oAuthClient: PlatformOAuthClient;
|
||||
let oAuthClientEventTypesDisabled: PlatformOAuthClient;
|
||||
let organization: Team;
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
|
||||
@@ -84,6 +85,7 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
let membershipsRepositoryFixture: MembershipRepositoryFixture;
|
||||
|
||||
let postResponseData: CreateManagedUserOutput["data"];
|
||||
let postResponseData2: CreateManagedUserOutput["data"];
|
||||
|
||||
const platformAdminEmail = `oauth-client-users-admin-${randomString()}@api.com`;
|
||||
let platformAdmin: User;
|
||||
@@ -91,6 +93,9 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
const userEmail = `oauth-client-users-user-${randomString()}@api.com`;
|
||||
const userTimeZone = "Europe/Rome";
|
||||
|
||||
const userEmail2 = `oauth-client-users-user2-${randomString()}@api.com`;
|
||||
const userTimeZone2 = "America/New_York";
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
providers: [PrismaExceptionFilter, HttpExceptionFilter],
|
||||
@@ -116,6 +121,7 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
isOrganization: true,
|
||||
});
|
||||
oAuthClient = await createOAuthClient(organization.id);
|
||||
oAuthClientEventTypesDisabled = await createOAuthClient(organization.id, false);
|
||||
|
||||
await profilesRepositoryFixture.create({
|
||||
uid: "asd1qwwqeqw-asddsadasd",
|
||||
@@ -136,12 +142,13 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
await app.init();
|
||||
});
|
||||
|
||||
async function createOAuthClient(organizationId: number) {
|
||||
async function createOAuthClient(organizationId: number, areDefaultEventTypesEnabled?: boolean) {
|
||||
const data = {
|
||||
logo: "logo-url",
|
||||
name: "name",
|
||||
redirectUris: [CLIENT_REDIRECT_URI],
|
||||
permissions: 32,
|
||||
areDefaultEventTypesEnabled,
|
||||
};
|
||||
const secret = "secret";
|
||||
|
||||
@@ -185,7 +192,7 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
.expect(400);
|
||||
});
|
||||
|
||||
it(`/POST`, async () => {
|
||||
it(`/POST with default event types`, async () => {
|
||||
const requestBody: CreateManagedUserInput = {
|
||||
email: userEmail,
|
||||
timeZone: userTimeZone,
|
||||
@@ -218,14 +225,55 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
expect(responseBody.data.accessToken).toBeDefined();
|
||||
expect(responseBody.data.refreshToken).toBeDefined();
|
||||
|
||||
await userConnectedToOAuth(responseBody.data.user.email);
|
||||
await userConnectedToOAuth(oAuthClient.id, responseBody.data.user.email);
|
||||
await userHasDefaultEventTypes(responseBody.data.user.id);
|
||||
await userHasDefaultSchedule(responseBody.data.user.id, responseBody.data.user.defaultScheduleId);
|
||||
await userHasOnlyOneSchedule(responseBody.data.user.id);
|
||||
});
|
||||
|
||||
async function userConnectedToOAuth(userEmail: string) {
|
||||
const oAuthUsers = await oauthClientRepositoryFixture.getUsers(oAuthClient.id);
|
||||
it(`/POST without default event types`, async () => {
|
||||
const requestBody: CreateManagedUserInput = {
|
||||
email: userEmail2,
|
||||
timeZone: userTimeZone2,
|
||||
weekStart: "Monday",
|
||||
timeFormat: 24,
|
||||
locale: Locales.FR,
|
||||
name: "Alice Smith",
|
||||
avatarUrl: "https://cal.com/api/avatar/2b735186-b01b-46d3-87da-019b8f61776b.png",
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.post(`/api/v2/oauth-clients/${oAuthClientEventTypesDisabled.id}/users`)
|
||||
.set("x-cal-secret-key", oAuthClientEventTypesDisabled.secret)
|
||||
.send(requestBody)
|
||||
.expect(201);
|
||||
|
||||
const responseBody: CreateManagedUserOutput = response.body;
|
||||
|
||||
postResponseData2 = responseBody.data;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseBody.data.user.email).toEqual(
|
||||
getOAuthUserEmail(oAuthClientEventTypesDisabled.id, requestBody.email)
|
||||
);
|
||||
expect(responseBody.data.user.timeZone).toEqual(requestBody.timeZone);
|
||||
expect(responseBody.data.user.name).toEqual(requestBody.name);
|
||||
expect(responseBody.data.user.weekStart).toEqual(requestBody.weekStart);
|
||||
expect(responseBody.data.user.timeFormat).toEqual(requestBody.timeFormat);
|
||||
expect(responseBody.data.user.locale).toEqual(requestBody.locale);
|
||||
expect(responseBody.data.user.avatarUrl).toEqual(requestBody.avatarUrl);
|
||||
expect(responseBody.data.accessToken).toBeDefined();
|
||||
expect(responseBody.data.refreshToken).toBeDefined();
|
||||
|
||||
await userConnectedToOAuth(oAuthClientEventTypesDisabled.id, responseBody.data.user.email);
|
||||
await userDoesNotHaveDefaultEventTypes(responseBody.data.user.id);
|
||||
await userHasDefaultSchedule(responseBody.data.user.id, responseBody.data.user.defaultScheduleId);
|
||||
await userHasOnlyOneSchedule(responseBody.data.user.id);
|
||||
});
|
||||
|
||||
async function userConnectedToOAuth(oAuthClientId: string, userEmail: string) {
|
||||
const oAuthUsers = await oauthClientRepositoryFixture.getUsers(oAuthClientId);
|
||||
const newOAuthUser = oAuthUsers?.find((user) => user.email === userEmail);
|
||||
|
||||
expect(oAuthUsers?.length).toEqual(1);
|
||||
@@ -251,6 +299,11 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
).toBeTruthy();
|
||||
}
|
||||
|
||||
async function userDoesNotHaveDefaultEventTypes(userId: number) {
|
||||
const defaultEventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(userId);
|
||||
expect(defaultEventTypes?.length).toEqual(0);
|
||||
}
|
||||
|
||||
async function userHasDefaultSchedule(userId: number, scheduleId: number | null) {
|
||||
expect(scheduleId).toBeDefined();
|
||||
expect(scheduleId).not.toBeNull();
|
||||
@@ -358,12 +411,18 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await oauthClientRepositoryFixture.delete(oAuthClient.id);
|
||||
await oauthClientRepositoryFixture.delete(oAuthClientEventTypesDisabled.id);
|
||||
await teamRepositoryFixture.delete(organization.id);
|
||||
try {
|
||||
await userRepositoryFixture.delete(postResponseData.user.id);
|
||||
} catch (e) {
|
||||
// User might have been deleted by the test
|
||||
}
|
||||
try {
|
||||
await userRepositoryFixture.delete(postResponseData2.user.id);
|
||||
} catch (e) {
|
||||
// User might have been deleted by the test
|
||||
}
|
||||
try {
|
||||
await userRepositoryFixture.delete(platformAdmin.id);
|
||||
} catch (e) {
|
||||
|
||||
+4
-7
@@ -85,14 +85,11 @@ export class OAuthClientUsersController {
|
||||
`Creating user with data: ${JSON.stringify(body, null, 2)} for OAuth Client with ID ${oAuthClientId}`
|
||||
);
|
||||
const client = await this.oauthRepository.getOAuthClient(oAuthClientId);
|
||||
if (!client) {
|
||||
throw new NotFoundException(`OAuth Client with ID ${oAuthClientId} not found`);
|
||||
}
|
||||
|
||||
const isPlatformManaged = true;
|
||||
const { user, tokens } = await this.oAuthClientUsersService.createOauthClientUser(
|
||||
oAuthClientId,
|
||||
body,
|
||||
isPlatformManaged,
|
||||
client?.organizationId
|
||||
);
|
||||
const { user, tokens } = await this.oAuthClientUsersService.createOAuthClientUser(client, body);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
|
||||
+1
-2
@@ -37,8 +37,7 @@ import {
|
||||
import { User, MembershipRole } from "@prisma/client";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { CreateOAuthClientInput, UpdateOAuthClientInput } from "@calcom/platform-types";
|
||||
import { Pagination } from "@calcom/platform-types";
|
||||
import { CreateOAuthClientInput, UpdateOAuthClientInput, Pagination } from "@calcom/platform-types";
|
||||
|
||||
const AUTH_DOCUMENTATION = `⚠️ First, this endpoint requires \`Cookie: next-auth.session-token=eyJhbGciOiJ\` header. Log into Cal web app using owner of organization that was created after visiting \`/settings/organizations/new\`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.`;
|
||||
|
||||
+4
-17
@@ -1,22 +1,9 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsIn, ValidateNested, IsNotEmptyObject, IsString } from "class-validator";
|
||||
import { IsIn, ValidateNested, IsNotEmptyObject } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS, REDIRECT_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
class DataDto {
|
||||
@ApiProperty({
|
||||
example: "clsx38nbl0001vkhlwin9fmt0",
|
||||
})
|
||||
@IsString()
|
||||
clientId!: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoib2F1dGgtY2xpZW50Iiwi",
|
||||
})
|
||||
@IsString()
|
||||
clientSecret!: string;
|
||||
}
|
||||
import { CreateOAuthClientOutput } from "@calcom/platform-types";
|
||||
|
||||
export class CreateOAuthClientResponseDto {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@@ -31,8 +18,8 @@ export class CreateOAuthClientResponseDto {
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => DataDto)
|
||||
data!: DataDto;
|
||||
@Type(() => CreateOAuthClientOutput)
|
||||
data!: CreateOAuthClientOutput;
|
||||
}
|
||||
|
||||
export class CreateOauthClientRedirect {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { CreateManagedUserInput } from "@/modules/users/inputs/create-managed-us
|
||||
import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input";
|
||||
import { UsersRepository } from "@/modules/users/users.repository";
|
||||
import { BadRequestException, ConflictException, Injectable } from "@nestjs/common";
|
||||
import { User, CreationSource } from "@prisma/client";
|
||||
import { User, CreationSource, PlatformOAuthClient } from "@prisma/client";
|
||||
|
||||
import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries";
|
||||
|
||||
@@ -16,16 +16,13 @@ export class OAuthClientUsersService {
|
||||
private readonly userRepository: UsersRepository,
|
||||
private readonly tokensRepository: TokensRepository,
|
||||
private readonly eventTypesService: EventTypesService_2024_04_15,
|
||||
private readonly schedulesService: SchedulesService_2024_04_15,
|
||||
private readonly organizationsTeamsService: OrganizationsTeamsService
|
||||
private readonly schedulesService: SchedulesService_2024_04_15
|
||||
) {}
|
||||
|
||||
async createOauthClientUser(
|
||||
oAuthClientId: string,
|
||||
body: CreateManagedUserInput,
|
||||
isPlatformManaged: boolean,
|
||||
organizationId?: number
|
||||
) {
|
||||
async createOAuthClientUser(oAuthClient: PlatformOAuthClient, body: CreateManagedUserInput) {
|
||||
const oAuthClientId = oAuthClient.id;
|
||||
const organizationId = oAuthClient.organizationId;
|
||||
|
||||
const existingUser = await this.getExistingUserByEmail(oAuthClientId, body.email);
|
||||
if (existingUser) {
|
||||
throw new ConflictException(
|
||||
@@ -35,7 +32,9 @@ export class OAuthClientUsersService {
|
||||
|
||||
let user: User;
|
||||
if (!organizationId) {
|
||||
throw new BadRequestException("You cannot create a managed user outside of an organization");
|
||||
throw new BadRequestException(
|
||||
"You cannot create a managed user outside of an organization - the OAuth client does not belong to any organization."
|
||||
);
|
||||
} else {
|
||||
const email = this.getOAuthUserEmail(oAuthClientId, body.email);
|
||||
user = (
|
||||
@@ -57,7 +56,7 @@ export class OAuthClientUsersService {
|
||||
autoAccept: true,
|
||||
},
|
||||
},
|
||||
isPlatformManaged,
|
||||
isPlatformManaged: true,
|
||||
timeFormat: body.timeFormat,
|
||||
weekStart: body.weekStart,
|
||||
timeZone: body.timeZone,
|
||||
@@ -79,7 +78,9 @@ export class OAuthClientUsersService {
|
||||
user.id
|
||||
);
|
||||
|
||||
await this.eventTypesService.createUserDefaultEventTypes(user.id);
|
||||
if (oAuthClient.areDefaultEventTypesEnabled) {
|
||||
await this.eventTypesService.createUserDefaultEventTypes(user.id);
|
||||
}
|
||||
|
||||
if (body.timeZone) {
|
||||
const defaultSchedule = await this.schedulesService.createUserDefaultSchedule(user.id, body.timeZone);
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ export class OAuthClientsOutputService {
|
||||
bookingCancelRedirectUri: client.bookingCancelRedirectUri ?? undefined,
|
||||
bookingRescheduleRedirectUri: client.bookingRescheduleRedirectUri ?? undefined,
|
||||
areEmailsEnabled: client.areEmailsEnabled,
|
||||
areDefaultEventTypesEnabled: client.areDefaultEventTypesEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7635,6 +7635,11 @@
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"areDefaultEventTypesEnabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If true, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Set this as false if you want to create a managed user and then manually create event types for the user."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -7643,7 +7648,7 @@
|
||||
"permissions"
|
||||
]
|
||||
},
|
||||
"DataDto": {
|
||||
"CreateOAuthClientOutput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"clientId": {
|
||||
@@ -7678,7 +7683,7 @@
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DataDto"
|
||||
"$ref": "#/components/schemas/CreateOAuthClientOutput"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7748,6 +7753,15 @@
|
||||
"type": "string",
|
||||
"example": "2024-03-23T08:33:21.851Z"
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"areDefaultEventTypesEnabled": {
|
||||
"type": "boolean",
|
||||
"example": true,
|
||||
"description": "If enabled, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Leave this disabled if you want to create a managed user and then manually create event types for the user."
|
||||
},
|
||||
"bookingRedirectUri": {
|
||||
"type": "string",
|
||||
"example": "https://example.com/booking-redirect"
|
||||
@@ -7759,10 +7773,6 @@
|
||||
"bookingRescheduleRedirectUri": {
|
||||
"type": "string",
|
||||
"example": "https://example.com/booking-reschedule"
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -7772,7 +7782,9 @@
|
||||
"permissions",
|
||||
"redirectUris",
|
||||
"organizationId",
|
||||
"createdAt"
|
||||
"createdAt",
|
||||
"areEmailsEnabled",
|
||||
"areDefaultEventTypesEnabled"
|
||||
]
|
||||
},
|
||||
"GetOAuthClientsResponseDto": {
|
||||
@@ -7844,6 +7856,10 @@
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"areDefaultEventTypesEnabled": {
|
||||
"type": "boolean",
|
||||
"description": "If true, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Set this as false if you want to create a managed user and then manually create event types for the user."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -46,6 +46,7 @@ export const OAuthClientsList = ({ oauthClients, isDeleting, handleDelete }: OAu
|
||||
isLoading={isDeleting}
|
||||
onDelete={handleDelete}
|
||||
areEmailsEnabled={client.areEmailsEnabled}
|
||||
areDefaultEventTypesEnabled={client.areDefaultEventTypesEnabled}
|
||||
organizationId={client.organizationId}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCheckTeamBilling } from "@calcom/web/lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient";
|
||||
import { useCheckTeamBilling } from "@calcom/web/lib/hooks/settings/platform/billing/useCheckTeamBilling";
|
||||
|
||||
import { usePlatformMe } from "./usePlatformMe";
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ type OAuthClientCardProps = {
|
||||
bookingCancelRedirectUri: string | null | undefined;
|
||||
bookingRescheduleRedirectUri: string | null | undefined;
|
||||
areEmailsEnabled: boolean | undefined;
|
||||
areDefaultEventTypesEnabled: boolean;
|
||||
permissions: Array<keyof typeof PERMISSION_MAP>;
|
||||
lastItem: boolean;
|
||||
id: string;
|
||||
@@ -38,6 +39,7 @@ export const OAuthClientCard = ({
|
||||
onDelete,
|
||||
isLoading,
|
||||
areEmailsEnabled,
|
||||
areDefaultEventTypesEnabled,
|
||||
organizationId,
|
||||
}: OAuthClientCardProps) => {
|
||||
const router = useRouter();
|
||||
@@ -165,6 +167,10 @@ export const OAuthClientCard = ({
|
||||
<div className="flex gap-1 text-sm">
|
||||
<span className="text-sm font-semibold">Emails enabled:</span> {areEmailsEnabled ? "Yes" : "No"}
|
||||
</div>
|
||||
<div className="flex gap-1 text-sm">
|
||||
<span className="text-sm font-semibold">Default event types enabled:</span>{" "}
|
||||
{areDefaultEventTypesEnabled ? "Yes" : "No"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-4">
|
||||
<Button
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useForm, useFieldArray } from "react-hook-form";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants/permissions";
|
||||
import { TextField, Tooltip, Button, Label } from "@calcom/ui";
|
||||
import { TextField, Tooltip, Button, Label, Icon } from "@calcom/ui";
|
||||
|
||||
type OAuthClientFormProps = {
|
||||
defaultValues?: Partial<FormValues>;
|
||||
@@ -33,6 +33,7 @@ export type FormValues = {
|
||||
bookingCancelRedirectUri?: string;
|
||||
bookingRescheduleRedirectUri?: string;
|
||||
areEmailsEnabled?: boolean;
|
||||
areDefaultEventTypesEnabled?: boolean;
|
||||
};
|
||||
|
||||
export const OAuthClientForm = ({
|
||||
@@ -232,6 +233,29 @@ export const OAuthClientForm = ({
|
||||
Enable emails
|
||||
</label>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
{...register("areDefaultEventTypesEnabled")}
|
||||
id="areDefaultEventTypesEnabled"
|
||||
className="bg-default border-default h-4 w-4 shrink-0 cursor-pointer rounded-[4px] border ring-offset-2 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed"
|
||||
type="checkbox"
|
||||
disabled={isFormDisabled}
|
||||
/>
|
||||
<label
|
||||
htmlFor="areDefaultEventTypesEnabled"
|
||||
className="cursor-pointer px-2 text-base font-semibold">
|
||||
Enable managed user default event types
|
||||
</label>
|
||||
<Tooltip
|
||||
className="max-w-[400px] whitespace-normal"
|
||||
content="If enabled, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Leave this disabled if you want to create a managed user and then manually create event types for the user.">
|
||||
<div className="ml-1">
|
||||
<Icon name="info" className="h-4 w-4 text-gray-500" aria-hidden="true" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<div className="flex justify-between">
|
||||
<h1 className="text-base font-semibold underline">Permissions</h1>
|
||||
|
||||
@@ -5,10 +5,8 @@ import type { ReactNode } from "react";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { showToast } from "@calcom/ui";
|
||||
|
||||
import {
|
||||
useSubscribeTeamToStripe,
|
||||
useUpgradeTeamSubscriptionInStripe,
|
||||
} from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient";
|
||||
import { useSubscribeTeamToStripe } from "@lib/hooks/settings/platform/billing/useSubscribeTeamToStripe";
|
||||
import { useUpgradeTeamSubscriptionInStripe } from "@lib/hooks/settings/platform/billing/useUpgradeTeamSubscriptionInStripe";
|
||||
|
||||
import { platformPlans } from "@components/settings/platform/platformUtils";
|
||||
import { PlatformBillingCard } from "@components/settings/platform/pricing/billing-card";
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
export const useCheckTeamBilling = (teamId?: number | null, isPlatformTeam?: boolean | null) => {
|
||||
const QUERY_KEY = "check-team-billing";
|
||||
const isTeamBilledAlready = useQuery({
|
||||
queryKey: [QUERY_KEY, teamId],
|
||||
queryFn: async () => {
|
||||
const response = await fetch(`/api/v2/billing/${teamId}/check`, {
|
||||
method: "get",
|
||||
headers: { "Content-type": "application/json" },
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
return data.data;
|
||||
},
|
||||
enabled: !!teamId && !!isPlatformTeam,
|
||||
});
|
||||
|
||||
return isTeamBilledAlready;
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { ApiResponse, SubscribeTeamInput } from "@calcom/platform-types";
|
||||
|
||||
export const useSubscribeTeamToStripe = (
|
||||
{
|
||||
onSuccess,
|
||||
onError,
|
||||
teamId,
|
||||
}: { teamId?: number | null; onSuccess: (redirectUrl: string) => void; onError: () => void } = {
|
||||
onSuccess: () => {
|
||||
return;
|
||||
},
|
||||
onError: () => {
|
||||
return;
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const mutation = useMutation<ApiResponse<{ action: string; url: string }>, unknown, SubscribeTeamInput>({
|
||||
mutationFn: (data) => {
|
||||
return fetch(`/api/v2/billing/${teamId}/subscribe`, {
|
||||
method: "post",
|
||||
headers: { "Content-type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
}).then((res) => res?.json());
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data.status === SUCCESS_STATUS) {
|
||||
onSuccess?.(data.data?.url);
|
||||
} else {
|
||||
onError?.();
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
onError?.();
|
||||
},
|
||||
});
|
||||
|
||||
return mutation;
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { ApiResponse, SubscribeTeamInput } from "@calcom/platform-types";
|
||||
|
||||
export const useUpgradeTeamSubscriptionInStripe = (
|
||||
{
|
||||
onSuccess,
|
||||
onError,
|
||||
teamId,
|
||||
}: { teamId?: number | null; onSuccess: (redirectUrl: string) => void; onError: () => void } = {
|
||||
onSuccess: () => {
|
||||
return;
|
||||
},
|
||||
onError: () => {
|
||||
return;
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const mutation = useMutation<ApiResponse<{ action: string; url: string }>, unknown, SubscribeTeamInput>({
|
||||
mutationFn: (data) => {
|
||||
return fetch(`/api/v2/billing/${teamId}/upgrade`, {
|
||||
method: "post",
|
||||
headers: { "Content-type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
}).then((res) => res?.json());
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data.status === SUCCESS_STATUS) {
|
||||
onSuccess?.(data.data?.url);
|
||||
} else {
|
||||
onError?.();
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
onError?.();
|
||||
},
|
||||
});
|
||||
|
||||
return mutation;
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { ApiResponse, CreateOAuthClientInput, CreateOAuthClientOutput } from "@calcom/platform-types";
|
||||
|
||||
export interface IPersistOAuthClient {
|
||||
onSuccess?: () => void;
|
||||
onError?: () => void;
|
||||
}
|
||||
|
||||
export const useCreateOAuthClient = (
|
||||
{ onSuccess, onError }: IPersistOAuthClient = {
|
||||
onSuccess: () => {
|
||||
return;
|
||||
},
|
||||
onError: () => {
|
||||
return;
|
||||
},
|
||||
}
|
||||
) => {
|
||||
return useMutation<ApiResponse<CreateOAuthClientOutput>, unknown, CreateOAuthClientInput>({
|
||||
mutationFn: async (data) => {
|
||||
return fetch("/api/v2/oauth-clients", {
|
||||
method: "post",
|
||||
headers: { "Content-type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
}).then((res) => res.json());
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data.status === SUCCESS_STATUS) {
|
||||
onSuccess?.();
|
||||
} else {
|
||||
onError?.();
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
onError?.();
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { ApiResponse, DeleteOAuthClientInput, PlatformOAuthClientDto } from "@calcom/platform-types";
|
||||
|
||||
import type { IPersistOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useCreateOAuthClient";
|
||||
|
||||
export const useDeleteOAuthClient = (
|
||||
{ onSuccess, onError }: IPersistOAuthClient = {
|
||||
onSuccess: () => {
|
||||
return;
|
||||
},
|
||||
onError: () => {
|
||||
return;
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const mutation = useMutation<ApiResponse<PlatformOAuthClientDto>, unknown, DeleteOAuthClientInput>({
|
||||
mutationFn: async (data) => {
|
||||
const { id } = data;
|
||||
return fetch(`/api/v2/oauth-clients/${id}`, {
|
||||
method: "delete",
|
||||
headers: { "Content-type": "application/json" },
|
||||
}).then((res) => res?.json());
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data.status === SUCCESS_STATUS) {
|
||||
onSuccess?.();
|
||||
} else {
|
||||
onError?.();
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
onError?.();
|
||||
},
|
||||
});
|
||||
|
||||
return mutation;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import type { ApiSuccessResponse, PlatformOAuthClientDto } from "@calcom/platform-types";
|
||||
|
||||
export const useOAuthClient = (clientId?: string) => {
|
||||
const {
|
||||
isLoading,
|
||||
error,
|
||||
data: response,
|
||||
isFetched,
|
||||
isError,
|
||||
isFetching,
|
||||
isSuccess,
|
||||
isFetchedAfterMount,
|
||||
refetch,
|
||||
} = useQuery<ApiSuccessResponse<PlatformOAuthClientDto>>({
|
||||
queryKey: ["oauth-client", clientId],
|
||||
queryFn: () => {
|
||||
return fetch(`/api/v2/oauth-clients/${clientId}`, {
|
||||
method: "get",
|
||||
headers: { "Content-type": "application/json" },
|
||||
}).then((res) => res.json());
|
||||
},
|
||||
enabled: Boolean(clientId),
|
||||
staleTime: Infinity,
|
||||
});
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
data: response?.data,
|
||||
isFetched,
|
||||
isError,
|
||||
isFetching,
|
||||
isSuccess,
|
||||
isFetchedAfterMount,
|
||||
refetch,
|
||||
};
|
||||
};
|
||||
@@ -2,17 +2,6 @@ import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import type { ApiSuccessResponse, PlatformOAuthClientDto } from "@calcom/platform-types";
|
||||
|
||||
export type ManagedUser = {
|
||||
id: number;
|
||||
email: string;
|
||||
username: string | null;
|
||||
timeZone: string;
|
||||
weekStart: string;
|
||||
createdDate: Date;
|
||||
timeFormat: number | null;
|
||||
defaultScheduleId: number | null;
|
||||
};
|
||||
|
||||
export const useOAuthClients = () => {
|
||||
const query = useQuery<ApiSuccessResponse<PlatformOAuthClientDto[]>>({
|
||||
queryKey: ["oauth-clients"],
|
||||
@@ -26,58 +15,3 @@ export const useOAuthClients = () => {
|
||||
|
||||
return { ...query, data: query.data?.data ?? [] };
|
||||
};
|
||||
|
||||
export const useOAuthClient = (clientId?: string) => {
|
||||
const {
|
||||
isLoading,
|
||||
error,
|
||||
data: response,
|
||||
isFetched,
|
||||
isError,
|
||||
isFetching,
|
||||
isSuccess,
|
||||
isFetchedAfterMount,
|
||||
refetch,
|
||||
} = useQuery<ApiSuccessResponse<PlatformOAuthClientDto>>({
|
||||
queryKey: ["oauth-client", clientId],
|
||||
queryFn: () => {
|
||||
return fetch(`/api/v2/oauth-clients/${clientId}`, {
|
||||
method: "get",
|
||||
headers: { "Content-type": "application/json" },
|
||||
}).then((res) => res.json());
|
||||
},
|
||||
enabled: Boolean(clientId),
|
||||
staleTime: Infinity,
|
||||
});
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
data: response?.data,
|
||||
isFetched,
|
||||
isError,
|
||||
isFetching,
|
||||
isSuccess,
|
||||
isFetchedAfterMount,
|
||||
refetch,
|
||||
};
|
||||
};
|
||||
export const useGetOAuthClientManagedUsers = (clientId: string) => {
|
||||
const {
|
||||
isLoading,
|
||||
error,
|
||||
data: response,
|
||||
refetch,
|
||||
} = useQuery<ApiSuccessResponse<ManagedUser[]>>({
|
||||
queryKey: ["oauth-client-managed-users", clientId],
|
||||
queryFn: () => {
|
||||
return fetch(`/api/v2/oauth-clients/${clientId}/managed-users`, {
|
||||
method: "get",
|
||||
headers: { "Content-type": "application/json" },
|
||||
}).then((res) => res.json());
|
||||
},
|
||||
enabled: Boolean(clientId),
|
||||
});
|
||||
|
||||
return { isLoading, error, data: response?.data, refetch };
|
||||
};
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { ApiResponse, CreateOAuthClientInput, PlatformOAuthClientDto } from "@calcom/platform-types";
|
||||
|
||||
import type { IPersistOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useCreateOAuthClient";
|
||||
|
||||
export const useUpdateOAuthClient = (
|
||||
{ onSuccess, onError, clientId }: IPersistOAuthClient & { clientId?: string } = {
|
||||
onSuccess: () => {
|
||||
return;
|
||||
},
|
||||
onError: () => {
|
||||
return;
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const mutation = useMutation<
|
||||
ApiResponse<PlatformOAuthClientDto>,
|
||||
unknown,
|
||||
Omit<CreateOAuthClientInput, "permissions">
|
||||
>({
|
||||
mutationFn: async (data) => {
|
||||
return fetch(`/api/v2/oauth-clients/${clientId}`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
}).then((res) => res?.json());
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data.status === SUCCESS_STATUS) {
|
||||
onSuccess?.();
|
||||
} else {
|
||||
onError?.();
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
onError?.();
|
||||
},
|
||||
});
|
||||
|
||||
return mutation;
|
||||
};
|
||||
@@ -9,8 +9,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants";
|
||||
import { showToast } from "@calcom/ui";
|
||||
|
||||
import { useOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useOAuthClients";
|
||||
import { useUpdateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient";
|
||||
import { useOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useOAuthClient";
|
||||
import { useUpdateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useUpdateOAuthClient";
|
||||
|
||||
import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan";
|
||||
import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes";
|
||||
@@ -59,6 +59,7 @@ export default function EditOAuthClient() {
|
||||
bookingCancelRedirectUri: data.bookingCancelRedirectUri,
|
||||
bookingRescheduleRedirectUri: data.bookingRescheduleRedirectUri,
|
||||
areEmailsEnabled: data.areEmailsEnabled,
|
||||
areDefaultEventTypesEnabled: data.areDefaultEventTypesEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -85,6 +86,7 @@ export default function EditOAuthClient() {
|
||||
defaultValues={{
|
||||
name: data?.name ?? "",
|
||||
areEmailsEnabled: data.areEmailsEnabled ?? false,
|
||||
areDefaultEventTypesEnabled: data.areDefaultEventTypesEnabled ?? false,
|
||||
redirectUris: data?.redirectUris?.map((uri) => ({ uri })) ?? [{ uri: "" }],
|
||||
bookingRedirectUri: data?.bookingRedirectUri ?? "",
|
||||
bookingCancelRedirectUri: data?.bookingCancelRedirectUri ?? "",
|
||||
|
||||
@@ -10,7 +10,7 @@ import type { PERMISSION_MAP } from "@calcom/platform-constants";
|
||||
import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants/permissions";
|
||||
import { showToast } from "@calcom/ui";
|
||||
|
||||
import { useCreateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient";
|
||||
import { useCreateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useCreateOAuthClient";
|
||||
|
||||
import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan";
|
||||
import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes";
|
||||
@@ -55,6 +55,7 @@ export default function CreateOAuthClient() {
|
||||
bookingCancelRedirectUri: data.bookingCancelRedirectUri,
|
||||
bookingRescheduleRedirectUri: data.bookingRescheduleRedirectUri,
|
||||
areEmailsEnabled: data.areEmailsEnabled,
|
||||
areDefaultEventTypesEnabled: data.areDefaultEventTypesEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import Shell from "@calcom/features/shell/Shell";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { showToast } from "@calcom/ui";
|
||||
|
||||
import { useDeleteOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useDeleteOAuthClient";
|
||||
import { useOAuthClients } from "@lib/hooks/settings/platform/oauth-clients/useOAuthClients";
|
||||
import { useDeleteOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient";
|
||||
|
||||
import { HelpCards } from "@components/settings/platform/dashboard/HelpCards";
|
||||
import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan";
|
||||
|
||||
@@ -7181,11 +7181,16 @@
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"areDefaultEventTypesEnabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If true, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Set this as false if you want to create a managed user and then manually create event types for the user."
|
||||
}
|
||||
},
|
||||
"required": ["name", "redirectUris", "permissions"]
|
||||
},
|
||||
"DataDto": {
|
||||
"CreateOAuthClientOutput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"clientId": {
|
||||
@@ -7214,7 +7219,7 @@
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DataDto"
|
||||
"$ref": "#/components/schemas/CreateOAuthClientOutput"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7276,6 +7281,15 @@
|
||||
"type": "string",
|
||||
"example": "2024-03-23T08:33:21.851Z"
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"areDefaultEventTypesEnabled": {
|
||||
"type": "boolean",
|
||||
"example": true,
|
||||
"description": "If enabled, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Leave this disabled if you want to create a managed user and then manually create event types for the user."
|
||||
},
|
||||
"bookingRedirectUri": {
|
||||
"type": "string",
|
||||
"example": "https://example.com/booking-redirect"
|
||||
@@ -7287,13 +7301,19 @@
|
||||
"bookingRescheduleRedirectUri": {
|
||||
"type": "string",
|
||||
"example": "https://example.com/booking-reschedule"
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "name", "secret", "permissions", "redirectUris", "organizationId", "createdAt"]
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"secret",
|
||||
"permissions",
|
||||
"redirectUris",
|
||||
"organizationId",
|
||||
"createdAt",
|
||||
"areEmailsEnabled",
|
||||
"areDefaultEventTypesEnabled"
|
||||
]
|
||||
},
|
||||
"GetOAuthClientsResponseDto": {
|
||||
"type": "object",
|
||||
@@ -7352,6 +7372,10 @@
|
||||
},
|
||||
"areEmailsEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"areDefaultEventTypesEnabled": {
|
||||
"type": "boolean",
|
||||
"description": "If true, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Set this as false if you want to create a managed user and then manually create event types for the user."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,5 +10,6 @@ export * from "./event-types";
|
||||
export * from "./organizations";
|
||||
export * from "./teams";
|
||||
export * from "./embed";
|
||||
export * from "./oauth-clients";
|
||||
export * from "./routing-forms";
|
||||
export * from "./me";
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./outputs";
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./me";
|
||||
@@ -0,0 +1,15 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const userSchemaResponse = z.object({
|
||||
id: z.number().int(),
|
||||
email: z.string(),
|
||||
timeFormat: z.number().int().default(12),
|
||||
defaultScheduleId: z.number().int().nullable(),
|
||||
weekStart: z.string(),
|
||||
timeZone: z.string().default("Europe/London"),
|
||||
username: z.string(),
|
||||
organizationId: z.number().nullable(),
|
||||
organization: z.object({ isPlatform: z.boolean(), id: z.number() }).optional(),
|
||||
});
|
||||
|
||||
export type UserResponse = z.infer<typeof userSchemaResponse>;
|
||||
@@ -1,8 +1,11 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Transform } from "class-transformer";
|
||||
import { IsArray, IsEnum, IsOptional, IsBoolean, IsString } from "class-validator";
|
||||
|
||||
import { PERMISSION_MAP } from "@calcom/platform-constants";
|
||||
|
||||
export const ARE_DEFAULT_EVENT_TYPES_ENABLED_DOCS =
|
||||
"If true, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Set this as false if you want to create a managed user and then manually create event types for the user.";
|
||||
export class CreateOAuthClientInput {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -47,4 +50,14 @@ export class CreateOAuthClientInput {
|
||||
@IsBoolean()
|
||||
@ApiPropertyOptional()
|
||||
areEmailsEnabled?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => value ?? false)
|
||||
@ApiPropertyOptional({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: ARE_DEFAULT_EVENT_TYPES_ENABLED_DOCS,
|
||||
})
|
||||
areDefaultEventTypesEnabled? = false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { IsArray, IsBoolean, IsOptional, IsString } from "class-validator";
|
||||
|
||||
import { ARE_DEFAULT_EVENT_TYPES_ENABLED_DOCS } from "./create-oauth-client.input";
|
||||
|
||||
export class UpdateOAuthClientInput {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -37,4 +39,12 @@ export class UpdateOAuthClientInput {
|
||||
@IsBoolean()
|
||||
@ApiPropertyOptional()
|
||||
areEmailsEnabled?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@ApiPropertyOptional({
|
||||
type: Boolean,
|
||||
description: ARE_DEFAULT_EVENT_TYPES_ENABLED_DOCS,
|
||||
})
|
||||
areDefaultEventTypesEnabled?: boolean;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsString } from "class-validator";
|
||||
|
||||
export class CreateOAuthClientOutput {
|
||||
@ApiProperty({
|
||||
example: "clsx38nbl0001vkhlwin9fmt0",
|
||||
})
|
||||
@IsString()
|
||||
clientId!: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoib2F1dGgtY2xpZW50Iiwi",
|
||||
})
|
||||
@IsString()
|
||||
clientSecret!: string;
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./oauth-client.output";
|
||||
export * from "./create-oauth-client.output";
|
||||
|
||||
@@ -44,6 +44,18 @@ export class PlatformOAuthClientDto {
|
||||
@IsDate()
|
||||
createdAt!: Date;
|
||||
|
||||
@IsBoolean()
|
||||
@ApiProperty({ example: true })
|
||||
areEmailsEnabled!: boolean;
|
||||
|
||||
@IsBoolean()
|
||||
@ApiProperty({
|
||||
example: true,
|
||||
description:
|
||||
"If enabled, when creating a managed user the managed user will have 4 default event types: 30 and 60 minutes without Cal video, 30 and 60 minutes with Cal video. Leave this disabled if you want to create a managed user and then manually create event types for the user.",
|
||||
})
|
||||
areDefaultEventTypesEnabled!: boolean;
|
||||
|
||||
@ApiPropertyOptional({ example: "https://example.com/booking-redirect" })
|
||||
@IsOptional()
|
||||
@IsUrl()
|
||||
@@ -58,9 +70,4 @@ export class PlatformOAuthClientDto {
|
||||
@IsOptional()
|
||||
@IsUrl()
|
||||
bookingRescheduleRedirectUri?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: false })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
areEmailsEnabled?: boolean;
|
||||
}
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "PlatformOAuthClient" ADD COLUMN "areDefaultEventTypesEnabled" BOOLEAN NOT NULL DEFAULT true;
|
||||
@@ -1519,6 +1519,7 @@ model PlatformOAuthClient {
|
||||
bookingCancelRedirectUri String?
|
||||
bookingRescheduleRedirectUri String?
|
||||
areEmailsEnabled Boolean @default(false)
|
||||
areDefaultEventTypesEnabled Boolean @default(true)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user