import { MembershipRole, Prisma, PrismaClient, UserPlan } from "@prisma/client"; import dayjs from "dayjs"; import { uuid } from "short-uuid"; import { hashPassword } from "@calcom/lib/auth"; import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability"; require("dotenv").config({ path: "../../.env" }); const prisma = new PrismaClient(); async function createUserAndEventType(opts: { user: { email: string; password: string; username: string; plan: UserPlan; name: string; completedOnboarding?: boolean; timeZone?: string; }; eventTypes: Array< Prisma.EventTypeCreateInput & { _bookings?: Prisma.BookingCreateInput[]; } >; }) { const userData = { ...opts.user, password: await hashPassword(opts.user.password), emailVerified: new Date(), completedOnboarding: opts.user.completedOnboarding ?? true, locale: "en", schedules: opts.user.completedOnboarding ?? true ? { create: { name: "Working Hours", availability: { createMany: { data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE), }, }, }, } : undefined, }; const user = await prisma.user.upsert({ where: { email: opts.user.email }, update: userData, create: userData, }); console.log( `👤 Upserted '${opts.user.username}' with email "${opts.user.email}" & password "${opts.user.password}". Booking page 👉 ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${opts.user.username}` ); for (const eventTypeInput of opts.eventTypes) { const { _bookings: bookingInputs = [], ...eventTypeData } = eventTypeInput; eventTypeData.userId = user.id; eventTypeData.users = { connect: { id: user.id } }; const eventType = await prisma.eventType.findFirst({ where: { slug: eventTypeData.slug, users: { some: { id: eventTypeData.userId, }, }, }, select: { id: true, }, }); if (eventType) { console.log( `\t📆 Event type ${eventTypeData.slug} already seems seeded - ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}/${eventTypeData.slug}` ); continue; } const { id } = await prisma.eventType.create({ data: eventTypeData, }); console.log( `\t📆 Event type ${eventTypeData.slug}, length ${eventTypeData.length}min - ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}/${eventTypeData.slug}` ); for (const bookingInput of bookingInputs) { await prisma.booking.create({ data: { ...bookingInput, user: { connect: { email: opts.user.email, }, }, attendees: { create: { email: opts.user.email, name: opts.user.name, timeZone: "Europe/London", }, }, eventType: { connect: { id, }, }, confirmed: bookingInput.confirmed, }, }); console.log( `\t\t☎️ Created booking ${bookingInput.title} at ${new Date( bookingInput.startTime ).toLocaleDateString()}` ); } } return user; } async function createTeamAndAddUsers( teamInput: Prisma.TeamCreateInput, users: { id: number; username: string; role?: MembershipRole }[] ) { const createTeam = async (team: Prisma.TeamCreateInput) => { try { return await prisma.team.create({ data: { ...team, }, }); } catch (_err) { if (_err instanceof Error && _err.message.indexOf("Unique constraint failed on the fields") !== -1) { console.log(`Team '${team.name}' already exists, skipping.`); return; } throw _err; } }; const team = await createTeam(teamInput); if (!team) { return; } console.log( `🏢 Created team '${teamInput.name}' - ${process.env.NEXT_PUBLIC_WEBAPP_URL}/team/${team.slug}` ); for (const user of users) { const { role = MembershipRole.OWNER, id, username } = user; await prisma.membership.create({ data: { teamId: team.id, userId: id, role: role, accepted: true, }, }); console.log(`\t👤 Added '${teamInput.name}' membership for '${username}' with role '${role}'`); } } async function main() { await createUserAndEventType({ user: { email: "delete-me@example.com", password: "delete-me", username: "delete-me", name: "delete-me", plan: "FREE", }, eventTypes: [], }); await createUserAndEventType({ user: { email: "onboarding@example.com", password: "onboarding", username: "onboarding", name: "onboarding", plan: "TRIAL", completedOnboarding: false, }, eventTypes: [], }); await createUserAndEventType({ user: { email: "free-first-hidden@example.com", password: "free-first-hidden", username: "free-first-hidden", name: "Free First Hidden Example", plan: "FREE", }, eventTypes: [ { title: "30min", slug: "30min", length: 30, hidden: true, }, { title: "60min", slug: "60min", length: 30, }, ], }); await createUserAndEventType({ user: { email: "pro@example.com", name: "Pro Example", password: "pro", username: "pro", plan: "PRO", }, eventTypes: [ { title: "30min", slug: "30min", length: 30, _bookings: [ { uid: uuid(), title: "30min", startTime: dayjs().add(1, "day").toDate(), endTime: dayjs().add(1, "day").add(30, "minutes").toDate(), }, { uid: uuid(), title: "30min", startTime: dayjs().add(2, "day").toDate(), endTime: dayjs().add(2, "day").add(30, "minutes").toDate(), confirmed: false, }, ], }, { title: "60min", slug: "60min", length: 60, }, { title: "paid", slug: "paid", length: 60, price: 50, }, { title: "In person meeting", slug: "in-person", length: 60, locations: [{ type: "inPerson", address: "London" }], }, { title: "Zoom Event", slug: "zoom", length: 60, locations: [{ type: "integrations:zoom" }], }, { title: "Daily Event", slug: "daily", length: 60, locations: [{ type: "integrations:daily" }], }, { title: "Google Meet", slug: "google-meet", length: 60, locations: [{ type: "integrations:google:meet" }], }, ], }); await createUserAndEventType({ user: { email: "trial@example.com", password: "trial", username: "trial", name: "Trial Example", plan: "TRIAL", }, eventTypes: [ { title: "30min", slug: "30min", length: 30, }, { title: "60min", slug: "60min", length: 60, }, ], }); await createUserAndEventType({ user: { email: "free@example.com", password: "free", username: "free", name: "Free Example", plan: "FREE", }, eventTypes: [ { title: "30min", slug: "30min", length: 30, }, { title: "60min", slug: "60min", length: 30, }, ], }); await createUserAndEventType({ user: { email: "usa@example.com", password: "usa", username: "usa", name: "USA Timezone Example", plan: "FREE", timeZone: "America/Phoenix", }, eventTypes: [ { title: "30min", slug: "30min", length: 30, }, ], }); const freeUserTeam = await createUserAndEventType({ user: { email: "teamfree@example.com", password: "teamfree", username: "teamfree", name: "Team Free Example", plan: "FREE", }, eventTypes: [], }); const proUserTeam = await createUserAndEventType({ user: { email: "teampro@example.com", password: "teampro", username: "teampro", name: "Team Pro Example", plan: "PRO", }, eventTypes: [], }); const pro2UserTeam = await createUserAndEventType({ user: { email: "teampro2@example.com", password: "teampro2", username: "teampro2", name: "Team Pro Example 2", plan: "PRO", }, eventTypes: [], }); const pro3UserTeam = await createUserAndEventType({ user: { email: "teampro3@example.com", password: "teampro3", username: "teampro3", name: "Team Pro Example 3", plan: "PRO", }, eventTypes: [], }); const pro4UserTeam = await createUserAndEventType({ user: { email: "teampro4@example.com", password: "teampro4", username: "teampro4", name: "Team Pro Example 4", plan: "PRO", }, eventTypes: [], }); await createTeamAndAddUsers( { name: "Seeded Team", slug: "seeded-team", eventTypes: { createMany: { data: [ { title: "Collective Seeded Team Event", slug: "collective-seeded-team-event", length: 15, schedulingType: "COLLECTIVE", }, { title: "Round Robin Seeded Team Event", slug: "round-robin-seeded-team-event", length: 15, schedulingType: "ROUND_ROBIN", }, ], }, }, }, [ { id: proUserTeam.id, username: proUserTeam.name || "Unknown", }, { id: freeUserTeam.id, username: freeUserTeam.name || "Unknown", }, { id: pro2UserTeam.id, username: pro2UserTeam.name || "Unknown", }, { id: pro3UserTeam.id, username: pro3UserTeam.name || "Unknown", }, { id: pro4UserTeam.id, username: pro4UserTeam.name || "Unknown", }, ] ); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });