mirror of
https://github.com/umami-software/umami.git
synced 2026-02-12 00:27:11 +01:00
Added timestamp property to payload.
This commit is contained in:
parent
9a87442870
commit
65f18d12ab
6 changed files with 33 additions and 15 deletions
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
|
|
@ -2,4 +2,4 @@
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,16 @@ import { badRequest, json, forbidden, serverError } from '@/lib/response';
|
||||||
import { fetchSession, fetchWebsite } from '@/lib/load';
|
import { fetchSession, fetchWebsite } from '@/lib/load';
|
||||||
import { getClientInfo, hasBlockedIp } from '@/lib/detect';
|
import { getClientInfo, hasBlockedIp } from '@/lib/detect';
|
||||||
import { secret, uuid, visitSalt } from '@/lib/crypto';
|
import { secret, uuid, visitSalt } from '@/lib/crypto';
|
||||||
import { COLLECTION_TYPE, DOMAIN_REGEX } from '@/lib/constants';
|
import { COLLECTION_TYPE } from '@/lib/constants';
|
||||||
|
import { anyObjectParam, urlOrPathParam } from '@/lib/schema';
|
||||||
import { createSession, saveEvent, saveSessionData } from '@/queries';
|
import { createSession, saveEvent, saveSessionData } from '@/queries';
|
||||||
import { urlOrPathParam } from '@/lib/schema';
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
type: z.enum(['event', 'identify']),
|
type: z.enum(['event', 'identify']),
|
||||||
payload: z.object({
|
payload: z.object({
|
||||||
website: z.string().uuid(),
|
website: z.string().uuid(),
|
||||||
data: z.object({}).passthrough().optional(),
|
data: anyObjectParam.optional(),
|
||||||
hostname: z.string().regex(DOMAIN_REGEX).max(100).optional(),
|
hostname: z.string().max(100).optional(),
|
||||||
language: z.string().max(35).optional(),
|
language: z.string().max(35).optional(),
|
||||||
referrer: urlOrPathParam.optional(),
|
referrer: urlOrPathParam.optional(),
|
||||||
screen: z.string().max(11).optional(),
|
screen: z.string().max(11).optional(),
|
||||||
|
|
@ -26,6 +26,7 @@ const schema = z.object({
|
||||||
tag: z.string().max(50).optional(),
|
tag: z.string().max(50).optional(),
|
||||||
ip: z.string().ip().optional(),
|
ip: z.string().ip().optional(),
|
||||||
userAgent: z.string().optional(),
|
userAgent: z.string().optional(),
|
||||||
|
timestamp: z.coerce.number().int().optional(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -55,6 +56,7 @@ export async function POST(request: Request) {
|
||||||
data,
|
data,
|
||||||
title,
|
title,
|
||||||
tag,
|
tag,
|
||||||
|
timestamp,
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
// Cache check
|
// Cache check
|
||||||
|
|
@ -88,6 +90,7 @@ export async function POST(request: Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sessionId = uuid(websiteId, ip, userAgent);
|
const sessionId = uuid(websiteId, ip, userAgent);
|
||||||
|
const createdAt = timestamp ? new Date(timestamp * 1000) : new Date();
|
||||||
|
|
||||||
// Find session
|
// Find session
|
||||||
if (!clickhouse.enabled && !cache?.sessionId) {
|
if (!clickhouse.enabled && !cache?.sessionId) {
|
||||||
|
|
@ -179,6 +182,7 @@ export async function POST(request: Request) {
|
||||||
subdivision2,
|
subdivision2,
|
||||||
city,
|
city,
|
||||||
tag,
|
tag,
|
||||||
|
createdAt,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,6 +195,7 @@ export async function POST(request: Request) {
|
||||||
websiteId,
|
websiteId,
|
||||||
sessionId,
|
sessionId,
|
||||||
sessionData: data,
|
sessionData: data,
|
||||||
|
createdAt,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ export const unitParam = z.string().refine(value => UNIT_TYPES.includes(value),
|
||||||
|
|
||||||
export const roleParam = z.enum(['team-member', 'team-view-only', 'team-manager']);
|
export const roleParam = z.enum(['team-member', 'team-view-only', 'team-manager']);
|
||||||
|
|
||||||
|
export const anyObjectParam = z.object({}).passthrough();
|
||||||
|
|
||||||
export const urlOrPathParam = z.string().refine(
|
export const urlOrPathParam = z.string().refine(
|
||||||
value => {
|
value => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export async function saveEvent(args: {
|
||||||
subdivision2?: string;
|
subdivision2?: string;
|
||||||
city?: string;
|
city?: string;
|
||||||
tag?: string;
|
tag?: string;
|
||||||
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(args),
|
[PRISMA]: () => relationalQuery(args),
|
||||||
|
|
@ -49,6 +50,7 @@ async function relationalQuery(data: {
|
||||||
eventName?: string;
|
eventName?: string;
|
||||||
eventData?: any;
|
eventData?: any;
|
||||||
tag?: string;
|
tag?: string;
|
||||||
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
websiteId,
|
websiteId,
|
||||||
|
|
@ -63,6 +65,7 @@ async function relationalQuery(data: {
|
||||||
eventData,
|
eventData,
|
||||||
pageTitle,
|
pageTitle,
|
||||||
tag,
|
tag,
|
||||||
|
createdAt,
|
||||||
} = data;
|
} = data;
|
||||||
const websiteEventId = uuid();
|
const websiteEventId = uuid();
|
||||||
|
|
||||||
|
|
@ -81,6 +84,7 @@ async function relationalQuery(data: {
|
||||||
eventType: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
eventType: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
||||||
eventName: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
eventName: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
||||||
tag,
|
tag,
|
||||||
|
createdAt,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -92,6 +96,7 @@ async function relationalQuery(data: {
|
||||||
urlPath: urlPath?.substring(0, URL_LENGTH),
|
urlPath: urlPath?.substring(0, URL_LENGTH),
|
||||||
eventName: eventName?.substring(0, EVENT_NAME_LENGTH),
|
eventName: eventName?.substring(0, EVENT_NAME_LENGTH),
|
||||||
eventData,
|
eventData,
|
||||||
|
createdAt,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +126,7 @@ async function clickhouseQuery(data: {
|
||||||
subdivision2?: string;
|
subdivision2?: string;
|
||||||
city?: string;
|
city?: string;
|
||||||
tag?: string;
|
tag?: string;
|
||||||
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
websiteId,
|
websiteId,
|
||||||
|
|
@ -139,12 +145,12 @@ async function clickhouseQuery(data: {
|
||||||
subdivision2,
|
subdivision2,
|
||||||
city,
|
city,
|
||||||
tag,
|
tag,
|
||||||
|
createdAt,
|
||||||
...args
|
...args
|
||||||
} = data;
|
} = data;
|
||||||
const { insert, getUTCString } = clickhouse;
|
const { insert, getUTCString } = clickhouse;
|
||||||
const { sendMessage } = kafka;
|
const { sendMessage } = kafka;
|
||||||
const eventId = uuid();
|
const eventId = uuid();
|
||||||
const createdAt = getUTCString();
|
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
...args,
|
...args,
|
||||||
|
|
@ -170,7 +176,7 @@ async function clickhouseQuery(data: {
|
||||||
event_type: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
event_type: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
||||||
event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
created_at: createdAt,
|
created_at: getUTCString(createdAt),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (kafka.enabled) {
|
if (kafka.enabled) {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export async function saveEventData(data: {
|
||||||
urlPath?: string;
|
urlPath?: string;
|
||||||
eventName?: string;
|
eventName?: string;
|
||||||
eventData: DynamicData;
|
eventData: DynamicData;
|
||||||
createdAt?: string;
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(data),
|
[PRISMA]: () => relationalQuery(data),
|
||||||
|
|
@ -27,8 +27,9 @@ async function relationalQuery(data: {
|
||||||
websiteId: string;
|
websiteId: string;
|
||||||
eventId: string;
|
eventId: string;
|
||||||
eventData: DynamicData;
|
eventData: DynamicData;
|
||||||
|
createdAt?: Date;
|
||||||
}): Promise<Prisma.BatchPayload> {
|
}): Promise<Prisma.BatchPayload> {
|
||||||
const { websiteId, eventId, eventData } = data;
|
const { websiteId, eventId, eventData, createdAt } = data;
|
||||||
|
|
||||||
const jsonKeys = flattenJSON(eventData);
|
const jsonKeys = flattenJSON(eventData);
|
||||||
|
|
||||||
|
|
@ -42,6 +43,7 @@ async function relationalQuery(data: {
|
||||||
numberValue: a.dataType === DATA_TYPE.number ? a.value : null,
|
numberValue: a.dataType === DATA_TYPE.number ? a.value : null,
|
||||||
dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null,
|
dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null,
|
||||||
dataType: a.dataType,
|
dataType: a.dataType,
|
||||||
|
createdAt,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return prisma.client.eventData.createMany({
|
return prisma.client.eventData.createMany({
|
||||||
|
|
@ -56,7 +58,7 @@ async function clickhouseQuery(data: {
|
||||||
urlPath?: string;
|
urlPath?: string;
|
||||||
eventName?: string;
|
eventName?: string;
|
||||||
eventData: DynamicData;
|
eventData: DynamicData;
|
||||||
createdAt?: string;
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
const { websiteId, sessionId, eventId, urlPath, eventName, eventData, createdAt } = data;
|
const { websiteId, sessionId, eventId, urlPath, eventName, eventData, createdAt } = data;
|
||||||
|
|
||||||
|
|
@ -77,7 +79,7 @@ async function clickhouseQuery(data: {
|
||||||
string_value: getStringValue(value, dataType),
|
string_value: getStringValue(value, dataType),
|
||||||
number_value: dataType === DATA_TYPE.number ? value : null,
|
number_value: dataType === DATA_TYPE.number ? value : null,
|
||||||
date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null,
|
date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null,
|
||||||
created_at: createdAt,
|
created_at: getUTCString(createdAt),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export async function saveSessionData(data: {
|
||||||
websiteId: string;
|
websiteId: string;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
sessionData: DynamicData;
|
sessionData: DynamicData;
|
||||||
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(data),
|
[PRISMA]: () => relationalQuery(data),
|
||||||
|
|
@ -22,9 +23,10 @@ export async function relationalQuery(data: {
|
||||||
websiteId: string;
|
websiteId: string;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
sessionData: DynamicData;
|
sessionData: DynamicData;
|
||||||
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
const { client } = prisma;
|
const { client } = prisma;
|
||||||
const { websiteId, sessionId, sessionData } = data;
|
const { websiteId, sessionId, sessionData, createdAt } = data;
|
||||||
|
|
||||||
const jsonKeys = flattenJSON(sessionData);
|
const jsonKeys = flattenJSON(sessionData);
|
||||||
|
|
||||||
|
|
@ -37,6 +39,7 @@ export async function relationalQuery(data: {
|
||||||
numberValue: a.dataType === DATA_TYPE.number ? a.value : null,
|
numberValue: a.dataType === DATA_TYPE.number ? a.value : null,
|
||||||
dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null,
|
dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null,
|
||||||
dataType: a.dataType,
|
dataType: a.dataType,
|
||||||
|
createdAt,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const existing = await client.sessionData.findMany({
|
const existing = await client.sessionData.findMany({
|
||||||
|
|
@ -77,12 +80,12 @@ async function clickhouseQuery(data: {
|
||||||
websiteId: string;
|
websiteId: string;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
sessionData: DynamicData;
|
sessionData: DynamicData;
|
||||||
|
createdAt?: Date;
|
||||||
}) {
|
}) {
|
||||||
const { websiteId, sessionId, sessionData } = data;
|
const { websiteId, sessionId, sessionData, createdAt } = data;
|
||||||
|
|
||||||
const { insert, getUTCString } = clickhouse;
|
const { insert, getUTCString } = clickhouse;
|
||||||
const { sendMessage } = kafka;
|
const { sendMessage } = kafka;
|
||||||
const createdAt = getUTCString();
|
|
||||||
|
|
||||||
const jsonKeys = flattenJSON(sessionData);
|
const jsonKeys = flattenJSON(sessionData);
|
||||||
|
|
||||||
|
|
@ -95,7 +98,7 @@ async function clickhouseQuery(data: {
|
||||||
string_value: getStringValue(value, dataType),
|
string_value: getStringValue(value, dataType),
|
||||||
number_value: dataType === DATA_TYPE.number ? value : null,
|
number_value: dataType === DATA_TYPE.number ? value : null,
|
||||||
date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null,
|
date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null,
|
||||||
created_at: createdAt,
|
created_at: getUTCString(createdAt),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue