feat: Add booking and user creation source (#18768)
* migration and init to accept creationSource for new bookings * V1 create booking * V1 user creation * webapp booking + V1 user * user creation in V1, V2 and webapp * booking source V2 and fix for v1 user * fit type * --fix type * add test -- WIP * fix type * fix type * ^ * Need more sleep zzz * -_- * bump libraries platform * adds for v2 recurring booking * fix lint * instant meetings * fix: api v2 creation source * fixup! fix: api v2 creation source * bump libraries * add user * fix test * fixup! fix test * add more source * more source... * fix type & test --1 * fix type & test --2 * typefix * fixup test --------- Co-authored-by: Morgan Vernay <morgan@cal.com>
This commit is contained in:
1 parent
3f622fe277
commit
41f63582b2
46 files changed
+261
-18
No files matched your search
@@ -5,6 +5,7 @@ import handleNewBooking from "@calcom/features/bookings/lib/handleNewBooking";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import { defaultResponder } from "@calcom/lib/server";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
||||
|
||||
@@ -213,6 +214,10 @@ import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
||||
*/
|
||||
async function handler(req: NextApiRequest) {
|
||||
const { userId, isSystemWideAdmin, isOrganizationOwnerOrAdmin } = req;
|
||||
req.body = {
|
||||
...req.body,
|
||||
creationSource: CreationSource.API_V1,
|
||||
};
|
||||
if (isSystemWideAdmin) req.userId = req.body.userId || userId;
|
||||
|
||||
if (isOrganizationOwnerOrAdmin) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import { defaultResponder } from "@calcom/lib/server";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { createContext } from "@calcom/trpc/server/createContext";
|
||||
import { viewerTeamsRouter } from "@calcom/trpc/server/routers/viewer/teams/_router";
|
||||
import type { TInviteMemberInputSchema } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/inviteMember.schema";
|
||||
@@ -43,6 +44,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
||||
language: data.language,
|
||||
teamId: data.teamId,
|
||||
usernameOrEmail: data.usernameOrEmail,
|
||||
creationSource: CreationSource.API_V1,
|
||||
});
|
||||
|
||||
return { success: true, message: `${data.usernameOrEmail} has been invited.` };
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import { defaultResponder } from "@calcom/lib/server";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
import { schemaUserCreateBodyParams } from "~/lib/validations/user";
|
||||
|
||||
@@ -92,7 +93,7 @@ async function postHandler(req: NextApiRequest) {
|
||||
// If user is not ADMIN, return unauthorized.
|
||||
if (!isSystemWideAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" });
|
||||
const data = await schemaUserCreateBodyParams.parseAsync(req.body);
|
||||
const user = await prisma.user.create({ data });
|
||||
const user = await prisma.user.create({ data: { ...data, creationSource: CreationSource.API_V1 } });
|
||||
req.statusCode = 201;
|
||||
return { user };
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { buildBooking, buildEventType, buildWebhook } from "@calcom/lib/test/builder";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { Booking } from "@calcom/prisma/client";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
import handler from "../../../pages/api/bookings/_post";
|
||||
|
||||
@@ -220,6 +221,34 @@ describe.skipIf(true)("POST /api/bookings", () => {
|
||||
});
|
||||
expect(previousBooking?.status).toBe("cancelled");
|
||||
});
|
||||
|
||||
test("Creates source as api_v1", async () => {
|
||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||
method: "POST",
|
||||
body: {
|
||||
name: "test",
|
||||
start: dayjs().format(),
|
||||
end: dayjs().add(1, "day").format(),
|
||||
eventTypeId: 2,
|
||||
email: "test@example.com",
|
||||
location: "Cal.com Video",
|
||||
timeZone: "America/Montevideo",
|
||||
language: "en",
|
||||
customInputs: [],
|
||||
metadata: {},
|
||||
userId: 4,
|
||||
},
|
||||
prisma,
|
||||
});
|
||||
|
||||
prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType());
|
||||
prismaMock.booking.findMany.mockResolvedValue([]);
|
||||
|
||||
await handler(req, res);
|
||||
createdBooking = JSON.parse(res._getData());
|
||||
expect(createdBooking.creationSource).toEqual(CreationSource.API_V1);
|
||||
expect(prismaMock.booking.create).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Recurring event-type", () => {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"@axiomhq/winston": "^1.2.0",
|
||||
"@calcom/platform-constants": "*",
|
||||
"@calcom/platform-enums": "*",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.86",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.91",
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
|
||||
"@calcom/platform-types": "*",
|
||||
"@calcom/platform-utils": "*",
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { ApiQuery, ApiExcludeController as DocsExcludeController } from "@nestjs/swagger";
|
||||
import { User } from "@prisma/client";
|
||||
import { CreationSource } from "@prisma/client";
|
||||
import { Request } from "express";
|
||||
import { NextApiRequest } from "next/types";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
@@ -383,7 +384,11 @@ export class BookingsController_2024_04_15 {
|
||||
...oAuthParams,
|
||||
});
|
||||
Object.assign(clone, { userId, ...oAuthParams, platformBookingLocation });
|
||||
clone.body = { ...clone.body, noEmail: !oAuthParams.arePlatformEmailsEnabled };
|
||||
clone.body = {
|
||||
...clone.body,
|
||||
noEmail: !oAuthParams.arePlatformEmailsEnabled,
|
||||
creationSource: CreationSource.API_V2,
|
||||
};
|
||||
return clone as unknown as NextApiRequest & { userId?: number } & OAuthRequestParams;
|
||||
}
|
||||
|
||||
@@ -411,6 +416,7 @@ export class BookingsController_2024_04_15 {
|
||||
...oAuthParams,
|
||||
platformBookingLocation,
|
||||
noEmail: !oAuthParams.arePlatformEmailsEnabled,
|
||||
creationSource: CreationSource.API_V2,
|
||||
});
|
||||
return clone as unknown as NextApiRequest & { userId?: number } & OAuthRequestParams;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.se
|
||||
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Logger } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { CreationSource } from "@prisma/client";
|
||||
import { Request } from "express";
|
||||
import { DateTime } from "luxon";
|
||||
import { NextApiRequest } from "next/types";
|
||||
@@ -97,10 +98,14 @@ export class InputBookingsService_2024_08_13 {
|
||||
|
||||
if (oAuthClientParams) {
|
||||
Object.assign(newRequest, { userId, ...oAuthClientParams, platformBookingLocation: location });
|
||||
newRequest.body = { ...bodyTransformed, noEmail: !oAuthClientParams.arePlatformEmailsEnabled };
|
||||
newRequest.body = {
|
||||
...bodyTransformed,
|
||||
noEmail: !oAuthClientParams.arePlatformEmailsEnabled,
|
||||
creationSource: CreationSource.API_V2,
|
||||
};
|
||||
} else {
|
||||
Object.assign(newRequest, { userId, platformBookingLocation: location });
|
||||
newRequest.body = { ...bodyTransformed, noEmail: false };
|
||||
newRequest.body = { ...bodyTransformed, noEmail: false, creationSource: CreationSource.API_V2 };
|
||||
}
|
||||
|
||||
return newRequest as unknown as BookingRequest;
|
||||
@@ -220,6 +225,7 @@ export class InputBookingsService_2024_08_13 {
|
||||
|
||||
newRequest.body = bodyTransformed.map((event) => ({
|
||||
...event,
|
||||
creationSource: CreationSource.API_V2,
|
||||
}));
|
||||
|
||||
return newRequest as unknown as BookingRequest;
|
||||
@@ -317,10 +323,14 @@ export class InputBookingsService_2024_08_13 {
|
||||
const location = await this.getRescheduleBookingLocation(bookingUid);
|
||||
if (oAuthClientParams) {
|
||||
Object.assign(newRequest, { userId, ...oAuthClientParams, platformBookingLocation: location });
|
||||
newRequest.body = { ...bodyTransformed, noEmail: !oAuthClientParams.arePlatformEmailsEnabled };
|
||||
newRequest.body = {
|
||||
...bodyTransformed,
|
||||
noEmail: !oAuthClientParams.arePlatformEmailsEnabled,
|
||||
creationSource: CreationSource.API_V2,
|
||||
};
|
||||
} else {
|
||||
Object.assign(newRequest, { userId, platformBookingLocation: location });
|
||||
newRequest.body = { ...bodyTransformed, noEmail: false };
|
||||
newRequest.body = { ...bodyTransformed, noEmail: false, creationSource: CreationSource.API_V2 };
|
||||
}
|
||||
|
||||
return newRequest as unknown as BookingRequest;
|
||||
|
||||
@@ -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 } from "@prisma/client";
|
||||
import { User, CreationSource } from "@prisma/client";
|
||||
|
||||
import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries";
|
||||
|
||||
@@ -46,6 +46,7 @@ export class OAuthClientUsersService {
|
||||
role: "MEMBER",
|
||||
},
|
||||
],
|
||||
creationSource: CreationSource.API_V2,
|
||||
teamId: organizationId,
|
||||
isOrg: true,
|
||||
parentId: null,
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ import { UpdateOrganizationUserInput } from "@/modules/organizations/inputs/upda
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { CreationSource } from "@prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsUsersRepository {
|
||||
@@ -70,7 +71,7 @@ export class OrganizationsUsersRepository {
|
||||
|
||||
async createOrganizationUser(orgId: number, createUserBody: CreateOrganizationUserInput) {
|
||||
const createdUser = await this.dbWrite.prisma.user.create({
|
||||
data: createUserBody,
|
||||
data: { ...createUserBody, creationSource: CreationSource.API_V2 },
|
||||
});
|
||||
|
||||
return createdUser;
|
||||
|
||||
@@ -5,10 +5,10 @@ import { OrganizationsUsersRepository } from "@/modules/organizations/repositori
|
||||
import { OrganizationsTeamsService } from "@/modules/organizations/services/organizations-teams.service";
|
||||
import { CreateUserInput } from "@/modules/users/inputs/create-user.input";
|
||||
import { Injectable, ConflictException } from "@nestjs/common";
|
||||
import { Team, CreationSource } from "@prisma/client";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
|
||||
import { createNewUsersConnectToOrgIfExists } from "@calcom/platform-libraries";
|
||||
import { Team } from "@calcom/prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsUsersService {
|
||||
@@ -56,6 +56,7 @@ export class OrganizationsUsersService {
|
||||
},
|
||||
],
|
||||
teamId: org.id,
|
||||
creationSource: CreationSource.API_V2,
|
||||
isOrg: true,
|
||||
parentId: null,
|
||||
autoAcceptEmailDomain: "not-required-for-this-endpoint",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CreateManagedUserInput } from "@/modules/users/inputs/create-managed-us
|
||||
import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import type { Profile, User, Team, Prisma } from "@prisma/client";
|
||||
import { CreationSource } from "@prisma/client";
|
||||
|
||||
export type UserWithProfile = User & {
|
||||
movedToProfile?: (Profile & { organization: Pick<Team, "isPlatform" | "id" | "slug" | "name"> }) | null;
|
||||
@@ -30,6 +31,7 @@ export class UsersRepository {
|
||||
connect: { id: oAuthClientId },
|
||||
},
|
||||
isPlatformManaged,
|
||||
creationSource: CreationSource.API_V2,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { defaultHandler, defaultResponder } from "@calcom/lib/server";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { IdentityProvider } from "@calcom/prisma/enums";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
const querySchema = z.object({
|
||||
username: z
|
||||
@@ -48,6 +49,7 @@ async function handler(req: NextApiRequest) {
|
||||
emailVerified: new Date(),
|
||||
locale: "en", // TODO: We should revisit this
|
||||
identityProvider: IdentityProvider.CAL,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { organizationScenarios } from "@calcom/lib/server/repository/__mocks__/o
|
||||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
|
||||
import { MembershipRole } from "@calcom/prisma/client";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { inviteMembersWithNoInviterPermissionCheck } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler";
|
||||
|
||||
import { moveUserToMatchingOrg } from "./verify-email";
|
||||
@@ -29,6 +30,7 @@ describe("moveUserToMatchingOrg", () => {
|
||||
const argToInviteMembersWithNoInviterPermissionCheck = {
|
||||
inviterName: null,
|
||||
language: "en",
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
invitations: [
|
||||
{
|
||||
usernameOrEmail: email,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { IS_STRIPE_ENABLED } from "@calcom/lib/constants";
|
||||
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { MembershipRole } from "@calcom/prisma/client";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { userMetadata } from "@calcom/prisma/zod-utils";
|
||||
import { inviteMembersWithNoInviterPermissionCheck } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler";
|
||||
|
||||
@@ -29,6 +30,7 @@ export async function moveUserToMatchingOrg({ email }: { email: string }) {
|
||||
inviterName: null,
|
||||
teamId: org.id,
|
||||
language: "en",
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
invitations: [
|
||||
{
|
||||
usernameOrEmail: email,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowE
|
||||
import getIP from "@calcom/lib/getIP";
|
||||
import { defaultResponder } from "@calcom/lib/server";
|
||||
import { checkCfTurnstileToken } from "@calcom/lib/server/checkCfTurnstileToken";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
async function handler(req: NextApiRequest & { userId?: number }, res: NextApiResponse) {
|
||||
const userIp = getIP(req);
|
||||
@@ -25,6 +26,10 @@ async function handler(req: NextApiRequest & { userId?: number }, res: NextApiRe
|
||||
const session = await getServerSession({ req, res });
|
||||
/* To mimic API behavior and comply with types */
|
||||
req.userId = session?.user?.id || -1;
|
||||
req.body = {
|
||||
...req.body,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
};
|
||||
const booking = await handleNewBooking(req);
|
||||
return booking;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import handleInstantMeeting from "@calcom/features/instant-meeting/handleInstant
|
||||
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
||||
import getIP from "@calcom/lib/getIP";
|
||||
import { defaultResponder } from "@calcom/lib/server";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
async function handler(req: NextApiRequest & { userId?: number }, res: NextApiResponse) {
|
||||
const userIp = getIP(req);
|
||||
@@ -16,6 +17,7 @@ async function handler(req: NextApiRequest & { userId?: number }, res: NextApiRe
|
||||
|
||||
const session = await getServerSession({ req, res });
|
||||
req.userId = session?.user?.id || -1;
|
||||
req.body.creationSource = CreationSource.WEBAPP;
|
||||
const booking = await handleInstantMeeting(req);
|
||||
return booking;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { getDate } from "@calcom/web/test/utils/bookingScenario/bookingScenario";
|
||||
|
||||
import type { SchedulingType } from "@calcom/prisma/client";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
export const DEFAULT_TIMEZONE_BOOKER = "Asia/Kolkata";
|
||||
export function getBasicMockRequestDataForBooking() {
|
||||
@@ -40,6 +41,7 @@ export function getMockRequestDataForBooking({
|
||||
data: Partial<ReturnType<typeof getBasicMockRequestDataForBooking>> & {
|
||||
eventTypeId: number;
|
||||
user?: string;
|
||||
creationSource?: CreationSource;
|
||||
} & CommonPropsMockRequestData;
|
||||
}) {
|
||||
return {
|
||||
|
||||
@@ -36,6 +36,7 @@ import { ProfileRepository } from "@calcom/lib/server/repository/profile";
|
||||
import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { IdentityProvider, MembershipRole } from "@calcom/prisma/enums";
|
||||
import { teamMetadataSchema, userMetadata } from "@calcom/prisma/zod-utils";
|
||||
|
||||
@@ -979,6 +980,7 @@ export const getOptions = ({
|
||||
create: { role: MembershipRole.MEMBER, accepted: true, team: { connect: { id: orgId } } },
|
||||
},
|
||||
}),
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import logger from "@calcom/lib/logger";
|
||||
import { usernameHandler, type RequestWithUsernameStatus } from "@calcom/lib/server/username";
|
||||
import { validateAndGetCorrectedUsernameAndEmail } from "@calcom/lib/validateUsername";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { IdentityProvider } from "@calcom/prisma/enums";
|
||||
import { signupSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
@@ -199,6 +200,7 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
|
||||
stripeCustomerId: customer.id,
|
||||
checkoutSessionId,
|
||||
},
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
},
|
||||
});
|
||||
if (process.env.AVATARAPI_USERNAME && process.env.AVATARAPI_PASSWORD) {
|
||||
|
||||
@@ -68,6 +68,7 @@ import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { BookingStatus, SchedulingType, WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import {
|
||||
eventTypeAppMetadataOptionalSchema,
|
||||
eventTypeMetaDataSchemaWithTypedApps,
|
||||
@@ -277,6 +278,7 @@ const buildDryRunBooking = ({
|
||||
ratingFeedback: null,
|
||||
noShowHost: null,
|
||||
cancelledBy: null,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
} as CreatedBooking;
|
||||
|
||||
/**
|
||||
@@ -1195,6 +1197,7 @@ async function handler(
|
||||
},
|
||||
evt,
|
||||
originalRescheduledBooking,
|
||||
creationSource: req.body.creationSource,
|
||||
});
|
||||
|
||||
if (booking?.userId) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import dayjs from "@calcom/dayjs";
|
||||
import { isPrismaObjOrUndefined } from "@calcom/lib";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
import type { TgetBookingDataSchema } from "../getBookingDataSchema";
|
||||
@@ -51,6 +52,7 @@ type CreateBookingParams = {
|
||||
};
|
||||
evt: CalendarEvent;
|
||||
originalRescheduledBooking: OriginalRescheduledBooking;
|
||||
creationSource?: CreationSource;
|
||||
};
|
||||
|
||||
function updateEventDetails(
|
||||
@@ -85,6 +87,7 @@ export async function createBooking({
|
||||
routingFormResponseId,
|
||||
reroutingFormResponses,
|
||||
rescheduledBy,
|
||||
creationSource,
|
||||
}: CreateBookingParams & { rescheduledBy: string | undefined }) {
|
||||
updateEventDetails(evt, originalRescheduledBooking, input.changedOrganizer);
|
||||
const associatedBookingForFormResponse = routingFormResponseId
|
||||
@@ -101,6 +104,7 @@ export async function createBooking({
|
||||
input,
|
||||
evt,
|
||||
originalRescheduledBooking,
|
||||
creationSource,
|
||||
});
|
||||
|
||||
return await saveBooking(
|
||||
@@ -211,6 +215,7 @@ function buildNewBookingData(params: CreateBookingParams) {
|
||||
routingFormResponseId,
|
||||
reroutingFormResponses,
|
||||
rescheduledBy,
|
||||
creationSource,
|
||||
} = params;
|
||||
|
||||
const attendeesData = getAttendeesData(evt);
|
||||
@@ -258,6 +263,7 @@ function buildNewBookingData(params: CreateBookingParams) {
|
||||
routedFromRoutingFormReponse: routingFormResponseId
|
||||
? { connect: { id: routingFormResponseId } }
|
||||
: undefined,
|
||||
creationSource,
|
||||
};
|
||||
|
||||
if (reqBody.recurringEventId) {
|
||||
|
||||
@@ -56,6 +56,7 @@ import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
|
||||
import { WEBSITE_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { resetTestEmails } from "@calcom/lib/testEmails";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import { test } from "@calcom/web/test/fixtures/fixtures";
|
||||
|
||||
@@ -1549,6 +1550,86 @@ describe("handleNewBooking", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe("Creation source tests", () => {
|
||||
test(
|
||||
`should create a booking with creation source as WEBAPP`,
|
||||
async ({ emails }) => {
|
||||
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
||||
const booker = getBooker({
|
||||
email: "booker@example.com",
|
||||
name: "Booker",
|
||||
});
|
||||
|
||||
const organizer = getOrganizer({
|
||||
name: "Organizer",
|
||||
email: "organizer@example.com",
|
||||
id: 101,
|
||||
schedules: [TestData.schedules.IstWorkHours],
|
||||
credentials: [getZoomAppCredential()],
|
||||
selectedCalendars: [TestData.selectedCalendars.google],
|
||||
});
|
||||
|
||||
const { req } = createMockNextJsRequest({
|
||||
method: "POST",
|
||||
body: getMockRequestDataForBooking({
|
||||
data: {
|
||||
eventTypeId: 1,
|
||||
responses: {
|
||||
email: booker.email,
|
||||
name: booker.name,
|
||||
},
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const scenarioData = getScenarioData({
|
||||
webhooks: [
|
||||
{
|
||||
userId: organizer.id,
|
||||
eventTriggers: ["BOOKING_CREATED"],
|
||||
subscriberUrl: "http://my-webhook.example.com",
|
||||
active: true,
|
||||
eventTypeId: 1,
|
||||
appId: null,
|
||||
},
|
||||
],
|
||||
eventTypes: [
|
||||
{
|
||||
id: 1,
|
||||
slotInterval: 30,
|
||||
length: 30,
|
||||
users: [
|
||||
{
|
||||
id: 101,
|
||||
},
|
||||
],
|
||||
locations: [
|
||||
{
|
||||
type: BookingLocations.ZoomVideo,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
organizer,
|
||||
apps: [TestData.apps["zoomvideo"]],
|
||||
});
|
||||
|
||||
mockSuccessfulVideoMeetingCreation({
|
||||
metadataLookupKey: "zoomvideo",
|
||||
});
|
||||
await createBookingScenario(scenarioData);
|
||||
const createdBooking = await handleNewBooking(req);
|
||||
expect(createdBooking).toEqual(
|
||||
expect.objectContaining({
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
})
|
||||
);
|
||||
},
|
||||
timeout
|
||||
);
|
||||
});
|
||||
|
||||
describe(
|
||||
"Availability Check during booking",
|
||||
() => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { TFunction } from "next-i18next";
|
||||
import { ProfileRepository } from "@calcom/lib/server/repository/profile";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import type { getTeamOrThrow } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/utils";
|
||||
import { sendSignupToOrganizationEmail } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/utils";
|
||||
@@ -46,6 +47,7 @@ const createUserAndInviteToOrg = async ({
|
||||
],
|
||||
},
|
||||
},
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createOrUpdateMemberships } from "@calcom/features/auth/signup/utils/cr
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { IdentityProvider } from "@calcom/prisma/enums";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
import dSyncUserSelect from "./dSyncUserSelect";
|
||||
|
||||
@@ -37,6 +38,7 @@ const createUsersAndConnectToOrg = async (
|
||||
organizationId,
|
||||
identityProvider,
|
||||
identityProviderId,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import { classNames } from "@calcom/lib";
|
||||
import { IS_TEAM_BILLING_ENABLED_CLIENT } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { UserPermissionRole } from "@calcom/prisma/enums";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Button, CheckboxField, Form, Icon, showToast, TextField } from "@calcom/ui";
|
||||
@@ -151,7 +152,12 @@ const AddNewTeamsFormChild = ({
|
||||
const handleFormSubmit = () => {
|
||||
const fields = getValues("teams");
|
||||
const moveTeams = getValues("moveTeams");
|
||||
createTeamsMutation.mutate({ orgId: org.id, moveTeams, teamNames: fields.map((field) => field.name) });
|
||||
createTeamsMutation.mutate({
|
||||
orgId: org.id,
|
||||
moveTeams,
|
||||
teamNames: fields.map((field) => field.name),
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
});
|
||||
};
|
||||
|
||||
const moveTeams = watch("moveTeams");
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { UserPermissionRole } from "@calcom/prisma/enums";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import type { Ensure } from "@calcom/types/utils";
|
||||
import { Alert, Button, Form, Label, RadioGroup as RadioArea, TextField, ToggleGroup } from "@calcom/ui";
|
||||
@@ -107,7 +108,7 @@ const CreateANewOrganizationFormChild = ({
|
||||
handleSubmit={(v) => {
|
||||
if (!createOrganizationMutation.isPending) {
|
||||
setServerErrorMessage(null);
|
||||
createOrganizationMutation.mutate(v);
|
||||
createOrganizationMutation.mutate({ ...v, creationSource: CreationSource.WEBAPP });
|
||||
}
|
||||
}}>
|
||||
<div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useState, useEffect } from "react";
|
||||
import MemberInvitationModal from "@calcom/ee/teams/components/MemberInvitationModal";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
@@ -216,6 +217,7 @@ const MembersView = () => {
|
||||
language: i18n.language,
|
||||
role: values.role,
|
||||
usernameOrEmail: values.emailOrUsername,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
},
|
||||
{
|
||||
onSuccess: async (data) => {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { UserPermissionRole } from "@calcom/prisma/enums";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import type { Ensure } from "@calcom/types/utils";
|
||||
import { Alert, Form, TextField, Button } from "@calcom/ui";
|
||||
@@ -91,6 +92,7 @@ const CreateANewPlatformFormChild = ({ session }: { session: Ensure<SessionConte
|
||||
createOrganizationMutation.mutate({
|
||||
...v,
|
||||
slug: `${v.name.toLocaleLowerCase()}-platform-${uuid().substring(0, 20)}`,
|
||||
creationSource: CreationSource.API_V2,
|
||||
});
|
||||
}
|
||||
}}>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { IS_TEAM_BILLING_ENABLED_CLIENT, MAX_NB_INVITES } from "@calcom/lib/cons
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import type { RouterOutputs } from "@calcom/trpc";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { isEmail } from "@calcom/trpc/server/routers/viewer/teams/util";
|
||||
@@ -512,6 +513,7 @@ export const MemberInvitationModalWithoutMembers = ({
|
||||
language: i18n.language,
|
||||
role: values.role,
|
||||
usernameOrEmail: values.emailOrUsername,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
},
|
||||
{
|
||||
onSuccess: async (data) => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Alert, Button, ButtonGroup, EmptyScreen, Icon, Label, showToast } from "@calcom/ui";
|
||||
|
||||
@@ -95,7 +96,7 @@ export function TeamsListing() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!router) return;
|
||||
if (token) inviteMemberByToken({ token });
|
||||
if (token) inviteMemberByToken({ token, creationSource: CreationSource.WEBAPP });
|
||||
else setInviteTokenChecked(true);
|
||||
}, [router, inviteMemberByToken, setInviteTokenChecked, token]);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { RedirectType } from "@calcom/prisma/enums";
|
||||
import { _UserModel as User } from "@calcom/prisma/zod";
|
||||
import type { inferRouterOutputs } from "@calcom/trpc";
|
||||
@@ -63,7 +64,7 @@ export const userAdminRouter = router({
|
||||
}),
|
||||
add: authedAdminProcedure.input(userBodySchema).mutation(async ({ ctx, input }) => {
|
||||
const { prisma } = ctx;
|
||||
const user = await prisma.user.create({ data: input });
|
||||
const user = await prisma.user.create({ data: { ...input, creationSource: CreationSource.WEBAPP } });
|
||||
return { user, message: `User with id: ${user.id} added successfully` };
|
||||
}),
|
||||
update: authedAdminProcedureWithRequestedUser
|
||||
|
||||
@@ -261,6 +261,7 @@ async function handler(req: NextApiRequest) {
|
||||
data: attendeesList,
|
||||
},
|
||||
},
|
||||
creationSource: req.body.creationSource,
|
||||
};
|
||||
|
||||
const createBookingObj = {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Dispatch } from "react";
|
||||
|
||||
import MemberInvitationModal from "@calcom/features/ee/teams/components/MemberInvitationModal";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { showToast } from "@calcom/ui";
|
||||
import usePlatformMe from "@calcom/web/components/settings/platform/hooks/usePlatformMe";
|
||||
@@ -70,6 +71,7 @@ export function InviteMemberModal(props: Props) {
|
||||
role: values.role,
|
||||
usernameOrEmail: values.emailOrUsername,
|
||||
isPlatform: platformUser?.organization.isPlatform,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -4,6 +4,7 @@ import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { createAProfileForAnExistingUser } from "../../createAProfileForAnExistingUser";
|
||||
@@ -64,6 +65,7 @@ export class OrganizationRepository {
|
||||
static async createWithNonExistentOwner({
|
||||
orgData,
|
||||
owner,
|
||||
creationSource,
|
||||
}: {
|
||||
orgData: {
|
||||
name: string;
|
||||
@@ -79,6 +81,7 @@ export class OrganizationRepository {
|
||||
owner: {
|
||||
email: string;
|
||||
};
|
||||
creationSource: CreationSource;
|
||||
}) {
|
||||
logger.debug("createWithNonExistentOwner", safeStringify({ orgData, owner }));
|
||||
const organization = await this.create(orgData);
|
||||
@@ -87,6 +90,7 @@ export class OrganizationRepository {
|
||||
email: owner.email,
|
||||
username: ownerUsernameInOrg,
|
||||
organizationId: organization.id,
|
||||
creationSource,
|
||||
});
|
||||
|
||||
await prisma.membership.create({
|
||||
|
||||
@@ -9,6 +9,7 @@ import prisma from "@calcom/prisma";
|
||||
import { availabilityUserSelect } from "@calcom/prisma";
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
import type { User as UserType } from "@calcom/prisma/client";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
|
||||
import { userMetadata } from "@calcom/prisma/zod-utils";
|
||||
@@ -584,11 +585,14 @@ export class UserRepository {
|
||||
email,
|
||||
username,
|
||||
organizationId,
|
||||
creationSource,
|
||||
}: {
|
||||
email: string;
|
||||
username: string;
|
||||
organizationId: number | null;
|
||||
creationSource: CreationSource;
|
||||
}) {
|
||||
console.log("create user", { email, username, organizationId });
|
||||
const password = createHash("md5").update(`${email}${process.env.CALENDSO_ENCRYPTION_KEY}`).digest("hex");
|
||||
const hashedPassword = await hashPassword(password);
|
||||
const t = await getTranslation("en", "common");
|
||||
@@ -624,6 +628,7 @@ export class UserRepository {
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
creationSource,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Booking, EventType, Prisma, Webhook, BookingReference } from "@pri
|
||||
import type { TFunction } from "next-i18next";
|
||||
|
||||
import getICalUID from "@calcom/emails/lib/getICalUID";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import type { CalendarEvent, Person, VideoCallData } from "@calcom/types/Calendar";
|
||||
|
||||
@@ -76,6 +77,7 @@ export const buildBooking = (
|
||||
ratingFeedback: null,
|
||||
attendees: [],
|
||||
oneTimePassword: null,
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
...booking,
|
||||
};
|
||||
};
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CreationSource" AS ENUM ('api_v1', 'api_v2', 'webapp');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Booking" ADD COLUMN "creationSource" "CreationSource";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" ADD COLUMN "creationSource" "CreationSource";
|
||||
@@ -42,6 +42,12 @@ enum PeriodType {
|
||||
RANGE @map("range")
|
||||
}
|
||||
|
||||
enum CreationSource {
|
||||
API_V1 @map("api_v1")
|
||||
API_V2 @map("api_v2")
|
||||
WEBAPP @map("webapp")
|
||||
}
|
||||
|
||||
model Host {
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId Int
|
||||
@@ -367,6 +373,7 @@ model User {
|
||||
createdWatchlists Watchlist[] @relation("CreatedWatchlists")
|
||||
updatedWatchlists Watchlist[] @relation("UpdatedWatchlists")
|
||||
BookingInternalNote BookingInternalNote[]
|
||||
creationSource CreationSource?
|
||||
|
||||
@@unique([email])
|
||||
@@unique([email, username])
|
||||
@@ -671,6 +678,7 @@ model Booking {
|
||||
routedFromRoutingFormReponse App_RoutingForms_FormResponse?
|
||||
assignmentReason AssignmentReason[]
|
||||
internalNote BookingInternalNote[]
|
||||
creationSource CreationSource?
|
||||
|
||||
@@index([eventTypeId])
|
||||
@@index([userId])
|
||||
|
||||
@@ -89,6 +89,7 @@ export const createHandler = async ({ input, ctx }: CreateOptions) => {
|
||||
pricePerSeat,
|
||||
isPlatform,
|
||||
billingPeriod: billingPeriodRaw,
|
||||
creationSource,
|
||||
} = input;
|
||||
|
||||
const loggedInUser = await prisma.user.findUnique({
|
||||
@@ -229,6 +230,7 @@ export const createHandler = async ({ input, ctx }: CreateOptions) => {
|
||||
owner: {
|
||||
email: orgOwnerEmail,
|
||||
},
|
||||
creationSource,
|
||||
});
|
||||
|
||||
orgOwner = data.orgOwner;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { z } from "zod";
|
||||
|
||||
import { emailSchema } from "@calcom/lib/emailSchema";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
export enum BillingPeriod {
|
||||
MONTHLY = "MONTHLY",
|
||||
@@ -17,6 +18,7 @@ export const ZCreateInputSchema = z.object({
|
||||
pricePerSeat: z.number().optional(),
|
||||
isPlatform: z.boolean().default(false),
|
||||
billingPeriod: z.nativeEnum(BillingPeriod).default(BillingPeriod.MONTHLY).optional(),
|
||||
creationSource: z.nativeEnum(CreationSource),
|
||||
});
|
||||
|
||||
export type TCreateInputSchema = z.infer<typeof ZCreateInputSchema>;
|
||||
@@ -8,6 +8,7 @@ import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { MembershipRole, RedirectType } from "@calcom/prisma/enums";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
@@ -33,7 +34,7 @@ export const createTeamsHandler = async ({ ctx, input }: CreateTeamsOptions) =>
|
||||
throw new NoUserError();
|
||||
}
|
||||
|
||||
const { orgId, moveTeams } = input;
|
||||
const { orgId, moveTeams, creationSource } = input;
|
||||
|
||||
// Remove empty team names that could be there due to the default empty team name
|
||||
const teamNames = input.teamNames.filter((name) => name.trim().length > 0);
|
||||
@@ -106,6 +107,7 @@ export const createTeamsHandler = async ({ ctx, input }: CreateTeamsOptions) =>
|
||||
ownerId: organizationOwner.id,
|
||||
},
|
||||
ctx,
|
||||
creationSource,
|
||||
});
|
||||
})
|
||||
);
|
||||
@@ -173,6 +175,7 @@ async function moveTeam({
|
||||
newSlug,
|
||||
org,
|
||||
ctx,
|
||||
creationSource,
|
||||
}: {
|
||||
teamId: number;
|
||||
newSlug?: string | null;
|
||||
@@ -183,6 +186,7 @@ async function moveTeam({
|
||||
metadata: Prisma.JsonValue;
|
||||
};
|
||||
ctx: CreateTeamsOptions["ctx"];
|
||||
creationSource: CreationSource;
|
||||
}) {
|
||||
const team = await prisma.team.findUnique({
|
||||
where: {
|
||||
@@ -240,6 +244,7 @@ async function moveTeam({
|
||||
teamId: org.id,
|
||||
language: "en",
|
||||
usernameOrEmail: invitableMembers,
|
||||
creationSource,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
export const ZCreateTeamsSchema = z.object({
|
||||
teamNames: z.string().array(),
|
||||
orgId: z.number(),
|
||||
@@ -10,6 +12,7 @@ export const ZCreateTeamsSchema = z.object({
|
||||
shouldMove: z.boolean(),
|
||||
})
|
||||
),
|
||||
creationSource: z.nativeEnum(CreationSource),
|
||||
});
|
||||
|
||||
export type TCreateTeamsSchema = z.infer<typeof ZCreateTeamsSchema>;
|
||||
@@ -8,6 +8,7 @@ import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import { isOrganisationOwner } from "@calcom/lib/server/queries/organisations";
|
||||
import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
@@ -139,9 +140,10 @@ export const inviteMembersWithNoInviterPermissionCheck = async (
|
||||
usernameOrEmail: string;
|
||||
role: MembershipRole;
|
||||
}[];
|
||||
creationSource: CreationSource;
|
||||
} & TargetTeam
|
||||
) => {
|
||||
const { inviterName, orgSlug, invitations, language } = data;
|
||||
const { inviterName, orgSlug, invitations, language, creationSource } = data;
|
||||
const myLog = log.getSubLogger({ prefix: ["inviteMembers"] });
|
||||
const translation = await getTranslation(language ?? "en", "common");
|
||||
const team = "team" in data ? data.team : await getTeamOrThrow(data.teamId);
|
||||
@@ -188,6 +190,7 @@ export const inviteMembersWithNoInviterPermissionCheck = async (
|
||||
isOrg: isTeamAnOrg,
|
||||
inviter,
|
||||
autoAcceptEmailDomain: orgState.autoAcceptEmailDomain,
|
||||
creationSource,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -235,7 +238,7 @@ export const inviteMembersWithNoInviterPermissionCheck = async (
|
||||
|
||||
const inviteMembers = async ({ ctx, input }: InviteMemberOptions) => {
|
||||
const { user: inviter } = ctx;
|
||||
const { usernameOrEmail, role, isPlatform } = input;
|
||||
const { usernameOrEmail, role, isPlatform, creationSource } = input;
|
||||
|
||||
const team = await getTeamOrThrow(input.teamId);
|
||||
const requestedSlugForTeam = team?.metadata?.requestedSlug ?? null;
|
||||
@@ -267,11 +270,11 @@ const inviteMembers = async ({ ctx, input }: InviteMemberOptions) => {
|
||||
teamId: inviterOrgId && isInviterOrgAdmin ? inviterOrgId : input.teamId,
|
||||
isOrg: isTeamAnOrg,
|
||||
});
|
||||
|
||||
const result = await inviteMembersWithNoInviterPermissionCheck({
|
||||
inviterName: inviter.name,
|
||||
team,
|
||||
language: input.language,
|
||||
creationSource,
|
||||
orgSlug,
|
||||
invitations,
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import { z } from "zod";
|
||||
import { MAX_NB_INVITES } from "@calcom/lib/constants";
|
||||
import { emailSchema } from "@calcom/lib/emailSchema";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
export const ZInviteMemberInputSchema = z.object({
|
||||
teamId: z.number(),
|
||||
@@ -57,6 +58,7 @@ export const ZInviteMemberInputSchema = z.object({
|
||||
role: z.nativeEnum(MembershipRole).optional(),
|
||||
language: z.string(),
|
||||
isPlatform: z.boolean().optional(),
|
||||
creationSource: z.nativeEnum(CreationSource),
|
||||
});
|
||||
|
||||
export type TInviteMemberInputSchema = z.infer<typeof ZInviteMemberInputSchema>;
|
||||
@@ -20,6 +20,7 @@ import { prisma } from "@calcom/prisma";
|
||||
import type { Membership, OrganizationSettings, Team } from "@calcom/prisma/client";
|
||||
import { type User as UserType, type UserPassword, Prisma } from "@calcom/prisma/client";
|
||||
import type { Profile as ProfileType } from "@calcom/prisma/client";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
@@ -274,6 +275,7 @@ export async function createNewUsersConnectToOrgIfExists({
|
||||
weekStart,
|
||||
timeZone,
|
||||
language,
|
||||
creationSource,
|
||||
}: {
|
||||
invitations: Invitation[];
|
||||
isOrg: boolean;
|
||||
@@ -286,6 +288,7 @@ export async function createNewUsersConnectToOrgIfExists({
|
||||
weekStart?: string;
|
||||
timeZone?: string;
|
||||
language: string;
|
||||
creationSource: CreationSource;
|
||||
}) {
|
||||
// fail if we have invalid emails
|
||||
invitations.forEach((invitation) => checkInputEmailIsValid(invitation.usernameOrEmail));
|
||||
@@ -323,6 +326,7 @@ export async function createNewUsersConnectToOrgIfExists({
|
||||
timeFormat,
|
||||
weekStart,
|
||||
timeZone,
|
||||
creationSource,
|
||||
organizationId: orgId || null, // If the user is invited to a child team, they are automatically added to the parent org
|
||||
...(orgId
|
||||
? {
|
||||
@@ -911,6 +915,7 @@ export async function handleNewUsersInvites({
|
||||
isOrg,
|
||||
autoAcceptEmailDomain,
|
||||
inviter,
|
||||
creationSource,
|
||||
}: {
|
||||
invitationsForNewUsers: Invitation[];
|
||||
teamId: number;
|
||||
@@ -922,6 +927,7 @@ export async function handleNewUsersInvites({
|
||||
name: string | null;
|
||||
};
|
||||
isOrg: boolean;
|
||||
creationSource: CreationSource;
|
||||
}) {
|
||||
const translation = await getTranslation(language, "common");
|
||||
|
||||
@@ -933,6 +939,7 @@ export async function handleNewUsersInvites({
|
||||
autoAcceptEmailDomain: autoAcceptEmailDomain,
|
||||
parentId: team.parentId,
|
||||
language,
|
||||
creationSource,
|
||||
});
|
||||
|
||||
const sendVerifyEmailsPromises = invitationsForNewUsers.map((invitation) => {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
export const ZInviteMemberByTokenSchemaInputSchema = z.object({
|
||||
token: z.string(),
|
||||
creationSource: z.nativeEnum(CreationSource),
|
||||
});
|
||||
|
||||
export type TInviteMemberByTokenSchemaInputSchema = z.infer<typeof ZInviteMemberByTokenSchemaInputSchema>;
|
||||
Reference in new issue
Block a user