update getSessionActivity / getWebsiteSession

This commit is contained in:
Francis Cao 2024-08-09 15:49:30 -07:00
parent c7d39a3e94
commit a1c0ec9c81
7 changed files with 69 additions and 30 deletions

View File

@ -8,12 +8,16 @@ import styles from './SessionActivity.module.css';
export function SessionActivity({ export function SessionActivity({
websiteId, websiteId,
sessionId, sessionId,
startDate,
endDate,
}: { }: {
websiteId: string; websiteId: string;
sessionId: string; sessionId: string;
startDate: string;
endDate: string;
}) { }) {
const { locale } = useLocale(); const { locale } = useLocale();
const { data, isLoading } = useSessionActivity(websiteId, sessionId); const { data, isLoading } = useSessionActivity(websiteId, sessionId, startDate, endDate);
if (isLoading) { if (isLoading) {
return <Loading position="page" />; return <Loading position="page" />;

View File

@ -1,13 +1,13 @@
'use client'; 'use client';
import WebsiteHeader from '../../WebsiteHeader';
import SessionInfo from './SessionInfo';
import { useWebsiteSession } from 'components/hooks';
import Avatar from 'components/common/Avatar'; import Avatar from 'components/common/Avatar';
import { LoadingPanel } from 'components/common/LoadingPanel';
import { useWebsiteSession } from 'components/hooks';
import WebsiteHeader from '../../WebsiteHeader';
import { SessionActivity } from './SessionActivity'; import { SessionActivity } from './SessionActivity';
import { SessionStats } from './SessionStats';
import { SessionData } from './SessionData'; import { SessionData } from './SessionData';
import styles from './SessionDetailsPage.module.css'; import styles from './SessionDetailsPage.module.css';
import { LoadingPanel } from 'components/common/LoadingPanel'; import SessionInfo from './SessionInfo';
import { SessionStats } from './SessionStats';
export default function SessionDetailsPage({ export default function SessionDetailsPage({
websiteId, websiteId,
@ -28,7 +28,12 @@ export default function SessionDetailsPage({
</div> </div>
<div className={styles.content}> <div className={styles.content}>
<SessionStats data={data} /> <SessionStats data={data} />
<SessionActivity websiteId={websiteId} sessionId={sessionId} /> <SessionActivity
websiteId={websiteId}
sessionId={sessionId}
startDate={data?.firstAt}
endDate={data?.lastAt}
/>
</div> </div>
<div className={styles.data}> <div className={styles.data}>
<SessionData websiteId={websiteId} sessionId={sessionId} /> <SessionData websiteId={websiteId} sessionId={sessionId} />

View File

@ -1,12 +1,17 @@
import { useApi } from './useApi'; import { useApi } from './useApi';
export function useSessionActivity(websiteId: string, sessionId: string) { export function useSessionActivity(
websiteId: string,
sessionId: string,
startDate: string,
endDate: string,
) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
return useQuery({ return useQuery({
queryKey: ['session:activity', { websiteId, sessionId }], queryKey: ['session:activity', { websiteId, sessionId }],
queryFn: () => { queryFn: () => {
return get(`/websites/${websiteId}/sessions/${sessionId}/activity`); return get(`/websites/${websiteId}/sessions/${sessionId}/activity`, { startDate, endDate });
}, },
}); });
} }

View File

@ -9,12 +9,16 @@ import { getSessionActivity } from 'queries';
export interface SessionActivityRequestQuery extends PageParams { export interface SessionActivityRequestQuery extends PageParams {
websiteId: string; websiteId: string;
sessionId: string; sessionId: string;
startDate: string;
endDate: string;
} }
const schema = { const schema = {
GET: yup.object().shape({ GET: yup.object().shape({
websiteId: yup.string().uuid().required(), websiteId: yup.string().uuid().required(),
sessionId: yup.string().uuid().required(), sessionId: yup.string().uuid().required(),
startDate: yup.string().required(),
endDate: yup.string().required(),
}), }),
}; };
@ -26,14 +30,19 @@ export default async (
await useAuth(req, res); await useAuth(req, res);
await useValidate(schema, req, res); await useValidate(schema, req, res);
const { websiteId, sessionId } = req.query; const { websiteId, sessionId, startDate, endDate } = req.query;
if (req.method === 'GET') { if (req.method === 'GET') {
if (!(await canViewWebsite(req.auth, websiteId))) { if (!(await canViewWebsite(req.auth, websiteId))) {
return unauthorized(res); return unauthorized(res);
} }
const data = await getSessionActivity(websiteId, sessionId); const data = await getSessionActivity(
websiteId,
sessionId,
new Date(startDate),
new Date(endDate),
);
return ok(res, data); return ok(res, data);
} }

View File

@ -33,7 +33,7 @@ export default async (
return unauthorized(res); return unauthorized(res);
} }
const data = await getWebsiteSession(sessionId); const data = await getWebsiteSession(websiteId, sessionId);
return ok(res, data); return ok(res, data);
} }

View File

@ -1,24 +1,37 @@
import prisma from 'lib/prisma';
import clickhouse from 'lib/clickhouse'; import clickhouse from 'lib/clickhouse';
import { runQuery, PRISMA, CLICKHOUSE } from 'lib/db'; import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
import prisma from 'lib/prisma';
export async function getSessionActivity(...args: [websiteId: string, sessionId: string]) { export async function getSessionActivity(
...args: [websiteId: string, sessionId: string, startDate: Date, endDate: Date]
) {
return runQuery({ return runQuery({
[PRISMA]: () => relationalQuery(...args), [PRISMA]: () => relationalQuery(...args),
[CLICKHOUSE]: () => clickhouseQuery(...args), [CLICKHOUSE]: () => clickhouseQuery(...args),
}); });
} }
async function relationalQuery(websiteId: string, sessionId: string) { async function relationalQuery(
websiteId: string,
sessionId: string,
startDate: Date,
endDate: Date,
) {
return prisma.client.websiteEvent.findMany({ return prisma.client.websiteEvent.findMany({
where: { where: {
id: sessionId, id: sessionId,
websiteId, websiteId,
createdAt: { gte: startDate, lte: endDate },
}, },
}); });
} }
async function clickhouseQuery(websiteId: string, sessionId: string) { async function clickhouseQuery(
websiteId: string,
sessionId: string,
startDate: Date,
endDate: Date,
) {
const { rawQuery } = clickhouse; const { rawQuery } = clickhouse;
return rawQuery( return rawQuery(
@ -37,8 +50,9 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
from website_event from website_event
where website_id = {websiteId:UUID} where website_id = {websiteId:UUID}
and session_id = {sessionId:UUID} and session_id = {sessionId:UUID}
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
order by created_at desc order by created_at desc
`, `,
{ websiteId, sessionId }, { websiteId, sessionId, startDate, endDate },
); );
} }

View File

@ -2,22 +2,23 @@ import prisma from 'lib/prisma';
import clickhouse from 'lib/clickhouse'; import clickhouse from 'lib/clickhouse';
import { runQuery, PRISMA, CLICKHOUSE } from 'lib/db'; import { runQuery, PRISMA, CLICKHOUSE } from 'lib/db';
export async function getWebsiteSession(...args: [sessionId: string]) { export async function getWebsiteSession(...args: [websiteId: string, sessionId: string]) {
return runQuery({ return runQuery({
[PRISMA]: () => relationalQuery(...args), [PRISMA]: () => relationalQuery(...args),
[CLICKHOUSE]: () => clickhouseQuery(...args), [CLICKHOUSE]: () => clickhouseQuery(...args),
}); });
} }
async function relationalQuery(sessionId: string) { async function relationalQuery(websiteId: string, sessionId: string) {
return prisma.client.session.findUnique({ return prisma.client.session.findUnique({
where: { where: {
id: sessionId, id: sessionId,
websiteId,
}, },
}); });
} }
async function clickhouseQuery(sessionId: string) { async function clickhouseQuery(websiteId: string, sessionId: string) {
const { rawQuery } = clickhouse; const { rawQuery } = clickhouse;
return rawQuery( return rawQuery(
@ -34,15 +35,16 @@ async function clickhouseQuery(sessionId: string) {
country, country,
subdivision1, subdivision1,
city, city,
min(created_at) as firstAt, min(min_time) as firstAt,
max(created_at) as lastAt, max(max_time) as lastAt,
uniq(visit_id) as visits, uniq(visit_id) as visits,
sumIf(1, event_type = 1) as views, sumIf(views, event_type = 1) as views,
sumIf(1, event_type = 2) as events length(groupArrayArray(event_name)) as events
from website_event from website_event_stats_hourly
where session_id = {sessionId:UUID} where website_id = {websiteId:UUID}
group by session_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city and session_id = {sessionId:UUID}
group by session_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city;
`, `,
{ sessionId }, { websiteId, sessionId },
).then(result => result?.[0]); ).then(result => result?.[0]);
} }