mirror of
https://github.com/umami-software/umami.git
synced 2026-02-05 13:17:19 +01:00
Merge dev.
This commit is contained in:
commit
be1b2fc272
88 changed files with 4120 additions and 21010 deletions
50
src/app/api/reports/attribution/route.ts
Normal file
50
src/app/api/reports/attribution/route.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { reportParms } from '@/lib/schema';
|
||||
import { getAttribution } from '@/queries/sql/reports/getAttribution';
|
||||
import { z } from 'zod';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const schema = z.object({
|
||||
...reportParms,
|
||||
model: z.string().regex(/firstClick|lastClick/i),
|
||||
steps: z
|
||||
.array(
|
||||
z.object({
|
||||
type: z.string(),
|
||||
value: z.string(),
|
||||
}),
|
||||
)
|
||||
.min(1),
|
||||
currency: z.string().optional(),
|
||||
});
|
||||
|
||||
const { auth, body, error } = await parseRequest(request, schema);
|
||||
|
||||
if (error) {
|
||||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
model,
|
||||
steps,
|
||||
currency,
|
||||
dateRange: { startDate, endDate },
|
||||
} = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getAttribution(websiteId, {
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
model: model,
|
||||
steps,
|
||||
currency,
|
||||
});
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ const schema = z.object({
|
|||
ip: z.string().ip().optional(),
|
||||
userAgent: z.string().optional(),
|
||||
timestamp: z.coerce.number().int().optional(),
|
||||
id: z.string().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ export async function POST(request: Request) {
|
|||
title,
|
||||
tag,
|
||||
timestamp,
|
||||
id,
|
||||
} = payload;
|
||||
|
||||
// Cache check
|
||||
|
|
@ -78,8 +80,10 @@ export async function POST(request: Request) {
|
|||
}
|
||||
|
||||
// Client info
|
||||
const { ip, userAgent, device, browser, os, country, subdivision1, subdivision2, city } =
|
||||
await getClientInfo(request, payload);
|
||||
const { ip, userAgent, device, browser, os, country, region, city } = await getClientInfo(
|
||||
request,
|
||||
payload,
|
||||
);
|
||||
|
||||
// Bot check
|
||||
if (!process.env.DISABLE_BOT_CHECK && isbot(userAgent)) {
|
||||
|
|
@ -97,7 +101,7 @@ export async function POST(request: Request) {
|
|||
const sessionSalt = hash(startOfMonth(createdAt).toUTCString());
|
||||
const visitSalt = hash(startOfHour(createdAt).toUTCString());
|
||||
|
||||
const sessionId = uuid(websiteId, ip, userAgent, sessionSalt);
|
||||
const sessionId = id ? uuid(websiteId, id) : uuid(websiteId, ip, userAgent, sessionSalt);
|
||||
|
||||
// Find session
|
||||
if (!clickhouse.enabled && !cache?.sessionId) {
|
||||
|
|
@ -109,15 +113,13 @@ export async function POST(request: Request) {
|
|||
await createSession({
|
||||
id: sessionId,
|
||||
websiteId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
region,
|
||||
city,
|
||||
});
|
||||
} catch (e: any) {
|
||||
|
|
@ -146,14 +148,29 @@ export async function POST(request: Request) {
|
|||
const urlQuery = currentUrl.search.substring(1);
|
||||
const urlDomain = currentUrl.hostname.replace(/^www./, '');
|
||||
|
||||
if (process.env.REMOVE_TRAILING_SLASH) {
|
||||
urlPath = urlPath.replace(/(.+)\/$/, '$1');
|
||||
}
|
||||
|
||||
let referrerPath: string;
|
||||
let referrerQuery: string;
|
||||
let referrerDomain: string;
|
||||
|
||||
// UTM Params
|
||||
const utmSource = currentUrl.searchParams.get('utm_source');
|
||||
const utmMedium = currentUrl.searchParams.get('utm_medium');
|
||||
const utmCampaign = currentUrl.searchParams.get('utm_campaign');
|
||||
const utmContent = currentUrl.searchParams.get('utm_content');
|
||||
const utmTerm = currentUrl.searchParams.get('utm_term');
|
||||
|
||||
// Click IDs
|
||||
const gclid = currentUrl.searchParams.get('gclid');
|
||||
const fbclid = currentUrl.searchParams.get('fbclid');
|
||||
const msclkid = currentUrl.searchParams.get('msclkid');
|
||||
const ttclid = currentUrl.searchParams.get('ttclid');
|
||||
const lifatid = currentUrl.searchParams.get('li_fat_id');
|
||||
const twclid = currentUrl.searchParams.get('twclid');
|
||||
|
||||
if (process.env.REMOVE_TRAILING_SLASH) {
|
||||
urlPath = urlPath.replace(/(.+)\/$/, '$1');
|
||||
}
|
||||
|
||||
if (referrer) {
|
||||
const referrerUrl = new URL(referrer, base);
|
||||
|
||||
|
|
@ -171,10 +188,21 @@ export async function POST(request: Request) {
|
|||
visitId,
|
||||
urlPath: safeDecodeURI(urlPath),
|
||||
urlQuery,
|
||||
utmSource,
|
||||
utmMedium,
|
||||
utmCampaign,
|
||||
utmContent,
|
||||
utmTerm,
|
||||
referrerPath: safeDecodeURI(referrerPath),
|
||||
referrerQuery,
|
||||
referrerDomain,
|
||||
pageTitle: safeDecodeURIComponent(title),
|
||||
gclid,
|
||||
fbclid,
|
||||
msclkid,
|
||||
ttclid,
|
||||
lifatid,
|
||||
twclid,
|
||||
eventName: name,
|
||||
eventData: data,
|
||||
hostname: hostname || urlDomain,
|
||||
|
|
@ -184,8 +212,7 @@ export async function POST(request: Request) {
|
|||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
region,
|
||||
city,
|
||||
tag,
|
||||
createdAt,
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
import { json } from '@/lib/response';
|
||||
import { CURRENT_VERSION } from '@/lib/constants';
|
||||
|
||||
export async function GET() {
|
||||
return json({ version: CURRENT_VERSION });
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue