import { z } from 'zod'; import { checkAuth } from '@/lib/auth'; import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS } from '@/lib/constants'; import { getAllowedUnits, getMinimumUnit, maxDate, parseDateRange } from '@/lib/date'; import { fetchWebsite } from '@/lib/load'; import { filtersArrayToObject } from '@/lib/params'; import { badRequest, unauthorized } from '@/lib/response'; import type { QueryFilters } from '@/lib/types'; import { getWebsiteSegment } from '@/queries/prisma'; export async function parseRequest( request: Request, schema?: any, options?: { skipAuth: boolean }, ): Promise { const url = new URL(request.url); let query = Object.fromEntries(url.searchParams); let body = await getJsonBody(request); let error: () => void | undefined; let auth = null; if (schema) { const isGet = request.method === 'GET'; const result = schema.safeParse(isGet ? query : body); if (!result.success) { error = () => badRequest(z.treeifyError(result.error)); } else if (isGet) { query = result.data; } else { body = result.data; } } if (!options?.skipAuth && !error) { auth = await checkAuth(request); if (!auth) { error = () => unauthorized(); } } return { url, query, body, auth, error }; } export async function getJsonBody(request: Request) { try { return await request.clone().json(); } catch { return undefined; } } export function getRequestDateRange(query: Record) { const { startAt, endAt, unit, timezone } = query; const startDate = new Date(+startAt); const endDate = new Date(+endAt); return { startDate, endDate, timezone, unit: getAllowedUnits(startDate, endDate).includes(unit) ? unit : getMinimumUnit(startDate, endDate), }; } export function getRequestFilters(query: Record) { const result: Record = {}; for (const key of Object.keys(FILTER_COLUMNS)) { const value = query[key]; if (value !== undefined) { result[key] = value; } } return result; } export async function setWebsiteDate(websiteId: string, data: Record) { const website = await fetchWebsite(websiteId); if (website?.resetAt) { data.startDate = maxDate(data.startDate, new Date(website?.resetAt)); } return data; } export async function getQueryFilters( params: Record, websiteId?: string, ): Promise { const dateRange = getRequestDateRange(params); const filters = getRequestFilters(params); if (websiteId) { await setWebsiteDate(websiteId, dateRange); if (params.segment) { const segmentParams = (await getWebsiteSegment(websiteId, params.segment)) ?.parameters as Record; Object.assign(filters, filtersArrayToObject(segmentParams.filters)); } if (params.cohort) { const cohortParams = (await getWebsiteSegment(websiteId, params.cohort)) ?.parameters as Record; const { startDate, endDate } = parseDateRange(cohortParams.dateRange); const cohortFilters = cohortParams.filters.map(({ name, ...props }) => ({ ...props, name: `cohort_${name}`, })); cohortFilters.push({ name: `cohort_${cohortParams.action.type}`, operator: 'eq', value: cohortParams.action.value, }); Object.assign(filters, { ...filtersArrayToObject(cohortFilters), cohort_startDate: startDate, cohort_endDate: endDate, }); } } return { ...dateRange, ...filters, page: params?.page, pageSize: params?.pageSize ? params?.pageSize || DEFAULT_PAGE_SIZE : undefined, orderBy: params?.orderBy, sortDescending: params?.sortDescending, search: params?.search, compare: params?.compare, }; }