2022-08-03 19:18:26 +00:00
|
|
|
import type { GetServerSidePropsContext } from "next";
|
|
|
|
import type { Session } from "next-auth";
|
2021-10-14 10:57:49 +00:00
|
|
|
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
2021-09-27 14:47:55 +00:00
|
|
|
|
2022-07-22 17:27:06 +00:00
|
|
|
import { getSession } from "@calcom/lib/auth";
|
2022-12-08 09:50:03 +00:00
|
|
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
2022-07-29 14:28:53 +00:00
|
|
|
import { getLocaleFromHeaders } from "@calcom/lib/i18n";
|
2022-07-22 17:27:06 +00:00
|
|
|
import { defaultAvatarSrc } from "@calcom/lib/profile";
|
|
|
|
import prisma from "@calcom/prisma";
|
|
|
|
|
2023-02-28 21:40:19 +00:00
|
|
|
import type { Maybe } from "@trpc/server";
|
|
|
|
import type { CreateNextContextOptions } from "@trpc/server/adapters/next";
|
2021-10-14 19:22:01 +00:00
|
|
|
|
2023-02-28 21:40:19 +00:00
|
|
|
type CreateContextOptions = CreateNextContextOptions | GetServerSidePropsContext;
|
2021-10-20 16:00:11 +00:00
|
|
|
|
|
|
|
async function getUserFromSession({
|
|
|
|
session,
|
|
|
|
req,
|
|
|
|
}: {
|
|
|
|
session: Maybe<Session>;
|
|
|
|
req: CreateContextOptions["req"];
|
|
|
|
}) {
|
2021-09-27 14:47:55 +00:00
|
|
|
if (!session?.user?.id) {
|
|
|
|
return null;
|
|
|
|
}
|
2023-02-28 21:40:19 +00:00
|
|
|
|
2021-09-27 14:47:55 +00:00
|
|
|
const user = await prisma.user.findUnique({
|
|
|
|
where: {
|
|
|
|
id: session.user.id,
|
|
|
|
},
|
|
|
|
select: {
|
|
|
|
id: true,
|
|
|
|
username: true,
|
|
|
|
name: true,
|
|
|
|
email: true,
|
|
|
|
bio: true,
|
|
|
|
timeZone: true,
|
|
|
|
weekStart: true,
|
|
|
|
startTime: true,
|
|
|
|
endTime: true,
|
2022-03-17 16:48:23 +00:00
|
|
|
defaultScheduleId: true,
|
2021-09-27 14:47:55 +00:00
|
|
|
bufferTime: true,
|
|
|
|
theme: true,
|
|
|
|
createdDate: true,
|
|
|
|
hideBranding: true,
|
|
|
|
avatar: true,
|
2021-10-18 07:02:25 +00:00
|
|
|
twoFactorEnabled: true,
|
2022-05-25 15:21:18 +00:00
|
|
|
disableImpersonation: true,
|
2022-01-13 20:05:23 +00:00
|
|
|
identityProvider: true,
|
2021-11-16 08:51:46 +00:00
|
|
|
brandColor: true,
|
2022-03-05 15:37:46 +00:00
|
|
|
darkBrandColor: true,
|
2022-01-11 10:32:40 +00:00
|
|
|
away: true,
|
2021-10-12 09:35:44 +00:00
|
|
|
credentials: {
|
|
|
|
select: {
|
|
|
|
id: true,
|
|
|
|
type: true,
|
|
|
|
key: true,
|
2022-03-23 22:00:30 +00:00
|
|
|
userId: true,
|
2022-05-02 20:39:35 +00:00
|
|
|
appId: true,
|
2022-10-31 22:06:03 +00:00
|
|
|
invalid: true,
|
2021-10-12 09:35:44 +00:00
|
|
|
},
|
2021-10-13 11:35:25 +00:00
|
|
|
orderBy: {
|
|
|
|
id: "asc",
|
|
|
|
},
|
2021-10-12 09:35:44 +00:00
|
|
|
},
|
|
|
|
selectedCalendars: {
|
|
|
|
select: {
|
|
|
|
externalId: true,
|
|
|
|
integration: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
completedOnboarding: true,
|
2021-12-09 15:51:37 +00:00
|
|
|
destinationCalendar: true,
|
2021-10-11 12:03:50 +00:00
|
|
|
locale: true,
|
2022-02-28 16:24:47 +00:00
|
|
|
timeFormat: true,
|
2022-03-03 19:29:19 +00:00
|
|
|
trialEndsAt: true,
|
2022-09-22 17:34:17 +00:00
|
|
|
metadata: true,
|
2022-12-07 21:47:02 +00:00
|
|
|
role: true,
|
2021-09-27 14:47:55 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
// some hacks to make sure `username` and `email` are never inferred as `null`
|
|
|
|
if (!user) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const { email, username } = user;
|
2021-11-16 01:08:04 +00:00
|
|
|
if (!email) {
|
2021-09-27 14:47:55 +00:00
|
|
|
return null;
|
|
|
|
}
|
2022-12-08 09:50:03 +00:00
|
|
|
const rawAvatar = user.avatar;
|
2022-10-17 19:49:09 +00:00
|
|
|
// This helps to prevent reaching the 4MB payload limit by avoiding base64 and instead passing the avatar url
|
2022-12-08 09:50:03 +00:00
|
|
|
user.avatar = rawAvatar ? `${WEBAPP_URL}/${user.username}/avatar.png` : defaultAvatarSrc({ email });
|
2021-10-11 12:03:50 +00:00
|
|
|
|
2021-11-02 17:09:22 +00:00
|
|
|
const locale = user.locale || getLocaleFromHeaders(req);
|
2021-09-27 14:47:55 +00:00
|
|
|
return {
|
|
|
|
...user,
|
2022-12-08 09:50:03 +00:00
|
|
|
rawAvatar,
|
2021-09-27 14:47:55 +00:00
|
|
|
email,
|
|
|
|
username,
|
2021-10-11 12:03:50 +00:00
|
|
|
locale,
|
2021-09-27 14:47:55 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-09 01:12:45 +00:00
|
|
|
type CreateInnerContextOptions = {
|
|
|
|
session: Session | null;
|
|
|
|
locale: string;
|
|
|
|
user: Awaited<ReturnType<typeof getUserFromSession>>;
|
|
|
|
i18n: Awaited<ReturnType<typeof serverSideTranslations>>;
|
|
|
|
} & Partial<CreateContextOptions>;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inner context. Will always be available in your procedures, in contrast to the outer context.
|
|
|
|
*
|
|
|
|
* Also useful for:
|
|
|
|
* - testing, so you don't have to mock Next.js' `req`/`res`
|
|
|
|
* - tRPC's `createSSGHelpers` where we don't have `req`/`res`
|
|
|
|
*
|
|
|
|
* @see https://trpc.io/docs/context#inner-and-outer-context
|
|
|
|
*/
|
|
|
|
export async function createContextInner(opts: CreateInnerContextOptions) {
|
|
|
|
return {
|
|
|
|
prisma,
|
|
|
|
...opts,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-09-27 14:47:55 +00:00
|
|
|
/**
|
|
|
|
* Creates context for an incoming request
|
|
|
|
* @link https://trpc.io/docs/context
|
|
|
|
*/
|
2023-02-09 01:12:45 +00:00
|
|
|
export const createContext = async ({ req, res }: CreateContextOptions, sessionGetter = getSession) => {
|
2021-09-27 14:47:55 +00:00
|
|
|
// for API-response caching see https://trpc.io/docs/caching
|
2022-11-18 23:36:32 +00:00
|
|
|
const session = await sessionGetter({ req });
|
2021-09-27 14:47:55 +00:00
|
|
|
|
2021-10-11 12:03:50 +00:00
|
|
|
const user = await getUserFromSession({ session, req });
|
|
|
|
const locale = user?.locale ?? getLocaleFromHeaders(req);
|
2022-05-06 17:21:30 +00:00
|
|
|
const i18n = await serverSideTranslations(locale, ["common", "vital"]);
|
2023-02-09 01:12:45 +00:00
|
|
|
|
|
|
|
const contextInner = await createContextInner({ session, i18n, locale, user });
|
2021-09-27 14:47:55 +00:00
|
|
|
return {
|
2023-02-09 01:12:45 +00:00
|
|
|
...contextInner,
|
|
|
|
req,
|
|
|
|
res,
|
2021-09-27 14:47:55 +00:00
|
|
|
};
|
|
|
|
};
|