mirror of
https://github.com/umami-software/umami.git
synced 2026-02-17 02:55:38 +01:00
Merge branch 'dev' of https://github.com/umami-software/umami into feat/add-segments
This commit is contained in:
commit
a753809a74
5 changed files with 56 additions and 60 deletions
|
|
@ -4,7 +4,7 @@ import { startOfHour, startOfMonth } from 'date-fns';
|
||||||
import clickhouse from '@/lib/clickhouse';
|
import clickhouse from '@/lib/clickhouse';
|
||||||
import { parseRequest } from '@/lib/request';
|
import { parseRequest } from '@/lib/request';
|
||||||
import { badRequest, json, forbidden, serverError } from '@/lib/response';
|
import { badRequest, json, forbidden, serverError } from '@/lib/response';
|
||||||
import { fetchSession, fetchWebsite } from '@/lib/load';
|
import { fetchWebsite } from '@/lib/load';
|
||||||
import { getClientInfo, hasBlockedIp } from '@/lib/detect';
|
import { getClientInfo, hasBlockedIp } from '@/lib/detect';
|
||||||
import { createToken, parseToken } from '@/lib/jwt';
|
import { createToken, parseToken } from '@/lib/jwt';
|
||||||
import { secret, uuid, hash } from '@/lib/crypto';
|
import { secret, uuid, hash } from '@/lib/crypto';
|
||||||
|
|
@ -103,32 +103,24 @@ export async function POST(request: Request) {
|
||||||
|
|
||||||
const sessionId = id ? uuid(websiteId, id) : uuid(websiteId, ip, userAgent, sessionSalt);
|
const sessionId = id ? uuid(websiteId, id) : uuid(websiteId, ip, userAgent, sessionSalt);
|
||||||
|
|
||||||
// Find session
|
// Create a session if not found
|
||||||
if (!clickhouse.enabled && !cache?.sessionId) {
|
if (!clickhouse.enabled && !cache?.sessionId) {
|
||||||
const session = await fetchSession(websiteId, sessionId);
|
await createSession(
|
||||||
|
{
|
||||||
// Create a session if not found
|
id: sessionId,
|
||||||
if (!session) {
|
websiteId,
|
||||||
try {
|
browser,
|
||||||
await createSession({
|
os,
|
||||||
id: sessionId,
|
device,
|
||||||
websiteId,
|
screen,
|
||||||
browser,
|
language,
|
||||||
os,
|
country,
|
||||||
device,
|
region,
|
||||||
screen,
|
city,
|
||||||
language,
|
distinctId: id,
|
||||||
country,
|
},
|
||||||
region,
|
{ skipDuplicates: true },
|
||||||
city,
|
);
|
||||||
distinctId: id,
|
|
||||||
});
|
|
||||||
} catch (e: any) {
|
|
||||||
if (!e.message.toLowerCase().includes('unique constraint')) {
|
|
||||||
return serverError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit info
|
// Visit info
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@ import ipaddr from 'ipaddr.js';
|
||||||
import maxmind from 'maxmind';
|
import maxmind from 'maxmind';
|
||||||
import {
|
import {
|
||||||
DESKTOP_OS,
|
DESKTOP_OS,
|
||||||
MOBILE_OS,
|
|
||||||
DESKTOP_SCREEN_WIDTH,
|
DESKTOP_SCREEN_WIDTH,
|
||||||
LAPTOP_SCREEN_WIDTH,
|
|
||||||
MOBILE_SCREEN_WIDTH,
|
|
||||||
IP_ADDRESS_HEADERS,
|
IP_ADDRESS_HEADERS,
|
||||||
|
LAPTOP_SCREEN_WIDTH,
|
||||||
|
MOBILE_OS,
|
||||||
|
MOBILE_SCREEN_WIDTH,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
import { safeDecodeURIComponent } from '@/lib/url';
|
||||||
|
|
||||||
const MAXMIND = 'maxmind';
|
const MAXMIND = 'maxmind';
|
||||||
|
|
||||||
|
|
@ -148,9 +149,9 @@ export async function getClientInfo(request: Request, payload: Record<string, an
|
||||||
const userAgent = payload?.userAgent || request.headers.get('user-agent');
|
const userAgent = payload?.userAgent || request.headers.get('user-agent');
|
||||||
const ip = payload?.ip || getIpAddress(request.headers);
|
const ip = payload?.ip || getIpAddress(request.headers);
|
||||||
const location = await getLocation(ip, request.headers, !!payload?.ip);
|
const location = await getLocation(ip, request.headers, !!payload?.ip);
|
||||||
const country = location?.country;
|
const country = safeDecodeURIComponent(location?.country);
|
||||||
const region = location?.region;
|
const region = safeDecodeURIComponent(location?.region);
|
||||||
const city = location?.city;
|
const city = safeDecodeURIComponent(location?.city);
|
||||||
const browser = browserName(userAgent);
|
const browser = browserName(userAgent);
|
||||||
const os = detectOS(userAgent) as string;
|
const os = detectOS(userAgent) as string;
|
||||||
const device = getDevice(payload?.screen, os);
|
const device = getDevice(payload?.screen, os);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
|
|
||||||
return pagedRawQuery(
|
return pagedRawQuery(
|
||||||
`
|
`
|
||||||
with events as (
|
|
||||||
select
|
select
|
||||||
event_id as "id",
|
event_id as "id",
|
||||||
website_id as "websiteId",
|
website_id as "websiteId",
|
||||||
|
|
@ -49,8 +48,6 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
order by created_at desc
|
order by created_at desc
|
||||||
limit 1000)
|
|
||||||
select * from events
|
|
||||||
`,
|
`,
|
||||||
{ ...params, search: `%${search}%` },
|
{ ...params, search: `%${search}%` },
|
||||||
pageParams,
|
pageParams,
|
||||||
|
|
@ -64,7 +61,6 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
|
|
||||||
return pagedQuery(
|
return pagedQuery(
|
||||||
`
|
`
|
||||||
with events as (
|
|
||||||
select
|
select
|
||||||
event_id as id,
|
event_id as id,
|
||||||
website_id as websiteId,
|
website_id as websiteId,
|
||||||
|
|
@ -89,8 +85,6 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
order by created_at desc
|
order by created_at desc
|
||||||
limit 1000)
|
|
||||||
select * from events
|
|
||||||
`,
|
`,
|
||||||
{ ...params, search },
|
{ ...params, search },
|
||||||
pageParams,
|
pageParams,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import { Prisma } from '@prisma/client';
|
import { Prisma } from '@prisma/client';
|
||||||
import prisma from '@/lib/prisma';
|
import prisma from '@/lib/prisma';
|
||||||
|
|
||||||
export async function createSession(data: Prisma.SessionCreateInput) {
|
export async function createSession(
|
||||||
|
data: Prisma.SessionCreateInput,
|
||||||
|
options = { skipDuplicates: false },
|
||||||
|
) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
websiteId,
|
websiteId,
|
||||||
|
|
@ -16,19 +19,31 @@ export async function createSession(data: Prisma.SessionCreateInput) {
|
||||||
distinctId,
|
distinctId,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
return prisma.client.session.create({
|
try {
|
||||||
data: {
|
return await prisma.client.session.create({
|
||||||
id,
|
data: {
|
||||||
websiteId,
|
id,
|
||||||
browser,
|
websiteId,
|
||||||
os,
|
browser,
|
||||||
device,
|
os,
|
||||||
screen,
|
device,
|
||||||
language,
|
screen,
|
||||||
country,
|
language,
|
||||||
region,
|
country,
|
||||||
city,
|
region,
|
||||||
distinctId,
|
city,
|
||||||
},
|
distinctId,
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
} catch (e: any) {
|
||||||
|
// With skipDuplicates flag: ignore unique constraint error and return null
|
||||||
|
if (
|
||||||
|
options.skipDuplicates &&
|
||||||
|
e instanceof Prisma.PrismaClientKnownRequestError &&
|
||||||
|
e.code === 'P2002'
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
|
|
||||||
return pagedRawQuery(
|
return pagedRawQuery(
|
||||||
`
|
`
|
||||||
with sessions as (
|
|
||||||
select
|
select
|
||||||
session.session_id as "id",
|
session.session_id as "id",
|
||||||
session.website_id as "websiteId",
|
session.website_id as "websiteId",
|
||||||
|
|
@ -68,8 +67,6 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
session.region,
|
session.region,
|
||||||
session.city
|
session.city
|
||||||
order by max(website_event.created_at) desc
|
order by max(website_event.created_at) desc
|
||||||
limit 1000)
|
|
||||||
select * from sessions
|
|
||||||
`,
|
`,
|
||||||
{ ...params, search: `%${search}%` },
|
{ ...params, search: `%${search}%` },
|
||||||
pageParams,
|
pageParams,
|
||||||
|
|
@ -83,7 +80,6 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
|
|
||||||
return pagedQuery(
|
return pagedQuery(
|
||||||
`
|
`
|
||||||
with sessions as (
|
|
||||||
select
|
select
|
||||||
session_id as id,
|
session_id as id,
|
||||||
website_id as websiteId,
|
website_id as websiteId,
|
||||||
|
|
@ -116,8 +112,6 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
||||||
}
|
}
|
||||||
group by session_id, website_id, hostname, browser, os, device, screen, language, country, region, city
|
group by session_id, website_id, hostname, browser, os, device, screen, language, country, region, city
|
||||||
order by lastAt desc
|
order by lastAt desc
|
||||||
limit 1000)
|
|
||||||
select * from sessions
|
|
||||||
`,
|
`,
|
||||||
{ ...params, search },
|
{ ...params, search },
|
||||||
pageParams,
|
pageParams,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue