diff --git a/apps/partner-sas/lib/trpc/index.ts b/apps/partner-sas/lib/trpc/index.ts index 7b3e01b42..6c38d6a3c 100644 --- a/apps/partner-sas/lib/trpc/index.ts +++ b/apps/partner-sas/lib/trpc/index.ts @@ -3,6 +3,7 @@ import { headers } from "next/headers" import { dt } from "@scandic-hotels/common/dt" import { createContext } from "@scandic-hotels/trpc/context" import { getEuroBonusProfileData } from "@scandic-hotels/trpc/routers/partners/sas/getEuroBonusProfile" +import { getBasicUser } from "@scandic-hotels/trpc/routers/user/utils/getBasicUser" import { getVerifiedUser } from "@scandic-hotels/trpc/routers/user/utils/getVerifiedUser" import { appServerClient, @@ -57,6 +58,19 @@ export async function createAppContext() { includeExtendedPartnerData: input?.withExtendedPartnerData, }) + return user ?? null + }, + getScandicBasicUser: async () => { + const session = await getSocialSession() + if (!session) return null + + const user = await getBasicUser({ + token: { + expires_at: dt(session.expires_at).unix() * 1000, + access_token: session.access_token, + }, + }) + return user ?? null }, }) diff --git a/apps/scandic-web/lib/trpc/server.ts b/apps/scandic-web/lib/trpc/server.ts index 576bcdbfc..bd649217e 100644 --- a/apps/scandic-web/lib/trpc/server.ts +++ b/apps/scandic-web/lib/trpc/server.ts @@ -6,6 +6,7 @@ import { Lang } from "@scandic-hotels/common/constants/language" import { login } from "@scandic-hotels/common/constants/routes/handleAuth" import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createContext } from "@scandic-hotels/trpc/context" +import { getBasicUser } from "@scandic-hotels/trpc/routers/user/utils/getBasicUser" import { getVerifiedUser } from "@scandic-hotels/trpc/routers/user/utils/getVerifiedUser" import { appServerClient, @@ -85,6 +86,19 @@ export async function createAppContext() { includeExtendedPartnerData: input?.withExtendedPartnerData, }) + return user ?? null + }, + getScandicBasicUser: async () => { + const session = await getUserSession() + if (!session) return null + + const user = await getBasicUser({ + token: { + expires_at: session.token.expires_at ?? 0, + access_token: session.token.access_token, + }, + }) + return user ?? null }, }) diff --git a/packages/trpc/lib/api/endpoints.ts b/packages/trpc/lib/api/endpoints.ts index b8a9e680e..b7eb198ec 100644 --- a/packages/trpc/lib/api/endpoints.ts +++ b/packages/trpc/lib/api/endpoints.ts @@ -224,6 +224,7 @@ export namespace endpoints { */ export namespace Profile { export const profile = `${base.path.profile}/${version}/${base.enitity.Profile}` + export const basicProfile = `${profile}/BasicInfo` export const promoCampaign = `${profile}/Promotion` export function teamMemberCard(employeeId: string) { diff --git a/packages/trpc/lib/context.ts b/packages/trpc/lib/context.ts index 9d9f50944..d407cc15e 100644 --- a/packages/trpc/lib/context.ts +++ b/packages/trpc/lib/context.ts @@ -2,6 +2,7 @@ import type { Lang } from "@scandic-hotels/common/constants/language" import type { User } from "next-auth" import type { JWT } from "next-auth/jwt" +import type { getBasicUser } from "./routers/user/utils/getBasicUser" import type { getVerifiedUser } from "./routers/user/utils/getVerifiedUser" type Session = { @@ -12,6 +13,7 @@ type Session = { } type ScandicUser = Awaited> +type ScandicBasicUser = Awaited> type CreateContextOptions = { auth: () => Promise lang: Lang @@ -26,6 +28,7 @@ type CreateContextOptions = { getScandicUser: (input?: { withExtendedPartnerData: boolean }) => Promise + getScandicBasicUser: () => Promise } export function createContext(opts: CreateContextOptions) { @@ -41,6 +44,7 @@ export function createContext(opts: CreateContextOptions) { getScandicUserToken: opts.getScandicUserToken, getUserPointsBalance: opts.getUserPointsBalance, getScandicUser: opts.getScandicUser, + getScandicBasicUser: opts.getScandicBasicUser, } } diff --git a/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts b/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts index cc24ca170..ca52f6ade 100644 --- a/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts +++ b/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts @@ -9,7 +9,7 @@ import { safeTry } from "@scandic-hotels/common/utils/safeTry" import * as api from "../../../api" import { protectedProcedure } from "../../../procedures" import { getUserSchema } from "../../user/output" -import { getVerifiedUser } from "../../user/utils/getVerifiedUser" +import { getBasicUser } from "../../user/utils/getBasicUser" import type { FriendsTier } from "../../../types/user" @@ -33,12 +33,12 @@ export const performLevelUpgrade = protectedProcedure } const [profile, error] = await safeTry( - getVerifiedUser({ token: ctx.session.token }) + getBasicUser({ token: ctx.session.token }) ) - if (!profile?.membership || error) { + if (!profile || error) { return { tierMatchState: "error" } } - const currentLevel = profile.membership.membershipLevel + const currentLevel = profile.tier sasLogger.debug("tier match started") diff --git a/packages/trpc/lib/routers/user/output.ts b/packages/trpc/lib/routers/user/output.ts index a4db4021d..f1b805598 100644 --- a/packages/trpc/lib/routers/user/output.ts +++ b/packages/trpc/lib/routers/user/output.ts @@ -128,6 +128,30 @@ export const getUserSchema = z } }) +export const getBasicUserSchema = z.object({ + dateOfBirth: z.string().optional().default("1900-01-01"), + firstName: z.string(), + language: z + .string() + .transform((s) => s.charAt(0).toUpperCase() + s.slice(1)) + .optional(), + lastName: z.string(), + phoneNumber: z.string().optional(), + profileId: z.string().optional(), + membershipNumber: z.string(), + tier: scandicFriendsTier, + address: z + .object({ + city: z.string().optional(), + country: z.string().optional(), + countryCode: z.nativeEnum(countriesMap).optional(), + streetAddress: z.string().optional(), + zipCode: z.string().optional(), + }) + .optional() + .nullable(), +}) + export const creditCardSchema = z .object({ attribute: z.object({ diff --git a/packages/trpc/lib/routers/user/query/index.ts b/packages/trpc/lib/routers/user/query/index.ts index eefba1fe0..c50878d6e 100644 --- a/packages/trpc/lib/routers/user/query/index.ts +++ b/packages/trpc/lib/routers/user/query/index.ts @@ -83,7 +83,7 @@ export const userQueryRouter = router({ if (!isValidSession(ctx.session)) { return null } - const user = await ctx.getScandicUser() + const user = await ctx.getScandicBasicUser() if (!user) { return null diff --git a/packages/trpc/lib/routers/user/query/userTrackingInfo.ts b/packages/trpc/lib/routers/user/query/userTrackingInfo.ts index add01ea40..4123a94a5 100644 --- a/packages/trpc/lib/routers/user/query/userTrackingInfo.ts +++ b/packages/trpc/lib/routers/user/query/userTrackingInfo.ts @@ -3,8 +3,7 @@ import { createCounter } from "@scandic-hotels/common/telemetry" import { safeProtectedProcedure } from "../../../procedures" import { isValidSession } from "../../../utils/session" import { getEuroBonusProfileData } from "../../partners/sas/getEuroBonusProfile" -import { getFriendsMembership } from "../helpers" -import { getVerifiedUser } from "../utils/getVerifiedUser" +import { getBasicUser } from "../utils/getBasicUser" import type { LoginType } from "@scandic-hotels/common/constants/loginType" import type { Session } from "next-auth" @@ -48,9 +47,9 @@ async function getScandicFriendsUserTrackingData(session: Session | null) { } try { - const verifiedUserData = await getVerifiedUser({ token: session.token }) + const verifiedUserData = await getBasicUser({ token: session.token }) - if (!verifiedUserData || !verifiedUserData.loyalty) { + if (!verifiedUserData) { metricsUserTrackingInfo.success({ reason: "invalid user data", data: notLoggedInUserTrackingData, @@ -58,14 +57,12 @@ async function getScandicFriendsUserTrackingData(session: Session | null) { return notLoggedInUserTrackingData } - const membership = getFriendsMembership(verifiedUserData.loyalty) - const loggedInUserTrackingData: TrackingUserData = { loginStatus: "logged in", loginType: session.token.loginType as LoginType, memberId: verifiedUserData.profileId, - membershipNumber: membership?.membershipNumber, - memberLevel: membership?.membershipLevel, + membershipNumber: verifiedUserData.membershipNumber, + memberLevel: verifiedUserData?.tier, loginAction: "login success", memberType, } @@ -126,19 +123,17 @@ async function getSasEurobonusUserTrackingData( async function getScandicFriendsDataHelper(scandicUserToken: string | null) { if (!scandicUserToken) return null - const verifiedUserData = await getVerifiedUser({ + const verifiedUserData = await getBasicUser({ token: { access_token: scandicUserToken }, }) - if (!verifiedUserData || !verifiedUserData.loyalty) { + if (!verifiedUserData) { return null } - const membership = getFriendsMembership(verifiedUserData.loyalty) - return { memberId: verifiedUserData.profileId, - membershipNumber: membership?.membershipNumber, - memberLevel: membership?.membershipLevel, + membershipNumber: verifiedUserData.membershipNumber, + memberLevel: verifiedUserData.tier, } } diff --git a/packages/trpc/lib/routers/user/utils.ts b/packages/trpc/lib/routers/user/utils.ts index bfbbbf028..32e7a311c 100644 --- a/packages/trpc/lib/routers/user/utils.ts +++ b/packages/trpc/lib/routers/user/utils.ts @@ -9,7 +9,7 @@ import { cache } from "../../DUPLICATED/cache" import { creditCardsSchema } from "../../routers/user/output" import { toApiLang } from "../../utils" import { encrypt } from "../../utils/encryption" -import { getVerifiedUser } from "./utils/getVerifiedUser" +import { getBasicUser } from "./utils/getBasicUser" import { type FriendTransaction, getStaysSchema, type Stay } from "./output" import type { Lang } from "@scandic-hotels/common/constants/language" @@ -190,7 +190,7 @@ export async function updateStaysBookingUrl( lang: Lang ) { const [user, error] = await safeTry( - getVerifiedUser({ + getBasicUser({ token: session.token, }) ) diff --git a/packages/trpc/lib/routers/user/utils/getBasicUser.ts b/packages/trpc/lib/routers/user/utils/getBasicUser.ts new file mode 100644 index 000000000..2a80aed71 --- /dev/null +++ b/packages/trpc/lib/routers/user/utils/getBasicUser.ts @@ -0,0 +1,48 @@ +import { createCounter } from "@scandic-hotels/common/telemetry" + +import * as api from "../../../api" +import { cache } from "../../../DUPLICATED/cache" +import { serverErrorByStatus, sessionExpiredError } from "../../../errors" +import { getBasicUserSchema } from "../output" + +export const getBasicUser = cache( + async ({ + token, + }: { + token: { expires_at?: number; access_token: string } + }) => { + const getBasicUserCounter = createCounter("user", "getBasicUser") + const metricsGetBasicUser = getBasicUserCounter.init() + + metricsGetBasicUser.start() + + const now = Date.now() + if (token.expires_at && token.expires_at < now) { + metricsGetBasicUser.dataError(`Token expired`) + throw sessionExpiredError() + } + + const apiResponse = await api.get(api.endpoints.v2.Profile.basicProfile, { + headers: { + Authorization: `Bearer ${token.access_token}`, + }, + }) + + if (!apiResponse.ok) { + await metricsGetBasicUser.httpError(apiResponse) + + throw serverErrorByStatus(apiResponse.status, apiResponse) + } + const apiJson = await apiResponse.json() + + const verifiedData = getBasicUserSchema.safeParse(apiJson) + if (!verifiedData.success) { + metricsGetBasicUser.validationError(verifiedData.error) + throw verifiedData.error + } + + metricsGetBasicUser.success() + + return verifiedData.data + } +) diff --git a/packages/trpc/lib/routers/user/utils/updateStaysBookingUrl.ts b/packages/trpc/lib/routers/user/utils/updateStaysBookingUrl.ts index 7566539b4..b155688cb 100644 --- a/packages/trpc/lib/routers/user/utils/updateStaysBookingUrl.ts +++ b/packages/trpc/lib/routers/user/utils/updateStaysBookingUrl.ts @@ -5,7 +5,7 @@ import { safeTry } from "@scandic-hotels/common/utils/safeTry" import { env } from "../../../../env/server" import { encrypt } from "../../../utils/encryption" -import { getVerifiedUser } from "./getVerifiedUser" +import { getBasicUser } from "./getBasicUser" import type { Lang } from "@scandic-hotels/common/constants/language" import type { Session } from "next-auth" @@ -30,7 +30,7 @@ export async function updateStaysBookingUrl( lang: Lang ) { const [user, error] = await safeTry( - getVerifiedUser({ + getBasicUser({ token: { access_token: session.token.access_token, expires_at: session.token.expires_at ?? 0,