mirror of
https://github.com/umami-software/umami.git
synced 2026-02-08 06:37:18 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
ffa8d8dd88
19 changed files with 11252 additions and 89 deletions
|
|
@ -36,7 +36,7 @@ export default function SessionInfo({ data }) {
|
|||
<Icon>
|
||||
<Icons.Location />
|
||||
</Icon>
|
||||
{getRegionName(data?.subdivision1)}
|
||||
{getRegionName(data?.region)}
|
||||
</dd>
|
||||
|
||||
<dt>{formatMessage(labels.city)}</dt>
|
||||
|
|
|
|||
|
|
@ -80,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)) {
|
||||
|
|
@ -111,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) {
|
||||
|
|
@ -212,8 +212,7 @@ export async function POST(request: Request) {
|
|||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
region,
|
||||
city,
|
||||
tag,
|
||||
createdAt,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,17 @@ export const FILTER_REFERRERS = 'filter-referrers';
|
|||
export const FILTER_PAGES = 'filter-pages';
|
||||
|
||||
export const UNIT_TYPES = ['year', 'month', 'hour', 'day', 'minute'];
|
||||
export const EVENT_COLUMNS = ['url', 'entry', 'exit', 'referrer', 'title', 'query', 'event', 'tag'];
|
||||
export const EVENT_COLUMNS = [
|
||||
'url',
|
||||
'entry',
|
||||
'exit',
|
||||
'referrer',
|
||||
'title',
|
||||
'query',
|
||||
'event',
|
||||
'tag',
|
||||
'region',
|
||||
];
|
||||
|
||||
export const SESSION_COLUMNS = [
|
||||
'browser',
|
||||
|
|
@ -42,7 +52,6 @@ export const SESSION_COLUMNS = [
|
|||
'screen',
|
||||
'language',
|
||||
'country',
|
||||
'region',
|
||||
'city',
|
||||
'host',
|
||||
];
|
||||
|
|
@ -59,7 +68,7 @@ export const FILTER_COLUMNS = {
|
|||
browser: 'browser',
|
||||
device: 'device',
|
||||
country: 'country',
|
||||
region: 'subdivision1',
|
||||
region: 'region',
|
||||
city: 'city',
|
||||
language: 'language',
|
||||
event: 'event_name',
|
||||
|
|
|
|||
|
|
@ -96,12 +96,12 @@ export async function getLocation(ip: string = '', headers: Headers, hasPayloadI
|
|||
// Cloudflare headers
|
||||
if (headers.get('cf-ipcountry')) {
|
||||
const country = decodeHeader(headers.get('cf-ipcountry'));
|
||||
const subdivision1 = decodeHeader(headers.get('cf-region-code'));
|
||||
const region = decodeHeader(headers.get('cf-region-code'));
|
||||
const city = decodeHeader(headers.get('cf-ipcity'));
|
||||
|
||||
return {
|
||||
country,
|
||||
subdivision1: getRegionCode(country, subdivision1),
|
||||
region: getRegionCode(country, region),
|
||||
city,
|
||||
};
|
||||
}
|
||||
|
|
@ -109,12 +109,12 @@ export async function getLocation(ip: string = '', headers: Headers, hasPayloadI
|
|||
// Vercel headers
|
||||
if (headers.get('x-vercel-ip-country')) {
|
||||
const country = decodeHeader(headers.get('x-vercel-ip-country'));
|
||||
const subdivision1 = decodeHeader(headers.get('x-vercel-ip-country-region'));
|
||||
const region = decodeHeader(headers.get('x-vercel-ip-country-region'));
|
||||
const city = decodeHeader(headers.get('x-vercel-ip-city'));
|
||||
|
||||
return {
|
||||
country,
|
||||
subdivision1: getRegionCode(country, subdivision1),
|
||||
region: getRegionCode(country, region),
|
||||
city,
|
||||
};
|
||||
}
|
||||
|
|
@ -131,14 +131,12 @@ export async function getLocation(ip: string = '', headers: Headers, hasPayloadI
|
|||
|
||||
if (result) {
|
||||
const country = result.country?.iso_code ?? result?.registered_country?.iso_code;
|
||||
const subdivision1 = result.subdivisions?.[0]?.iso_code;
|
||||
const subdivision2 = result.subdivisions?.[1]?.names?.en;
|
||||
const region = result.subdivisions?.[0]?.iso_code;
|
||||
const city = result.city?.names?.en;
|
||||
|
||||
return {
|
||||
country,
|
||||
subdivision1: getRegionCode(country, subdivision1),
|
||||
subdivision2,
|
||||
region: getRegionCode(country, region),
|
||||
city,
|
||||
};
|
||||
}
|
||||
|
|
@ -149,14 +147,13 @@ export async function getClientInfo(request: Request, payload: Record<string, an
|
|||
const ip = payload?.ip || getIpAddress(request.headers);
|
||||
const location = await getLocation(ip, request.headers, !!payload?.ip);
|
||||
const country = location?.country;
|
||||
const subdivision1 = location?.subdivision1;
|
||||
const subdivision2 = location?.subdivision2;
|
||||
const region = location?.region;
|
||||
const city = location?.city;
|
||||
const browser = browserName(userAgent);
|
||||
const os = detectOS(userAgent) as string;
|
||||
const device = getDevice(payload?.screen, os);
|
||||
|
||||
return { userAgent, browser, os, ip, country, subdivision1, subdivision2, city, device };
|
||||
return { userAgent, browser, os, ip, country, region, city, device };
|
||||
}
|
||||
|
||||
export function hasBlockedIp(clientIp: string) {
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ function getFilterQuery(filters: QueryFilters = {}, options: QueryOptions = {}):
|
|||
|
||||
if (name === 'referrer') {
|
||||
arr.push(
|
||||
`and (website_event.referrer_domain != session.hostname or website_event.referrer_domain is null)`,
|
||||
`and (website_event.referrer_domain != website_event.hostname or website_event.referrer_domain is null)`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,8 +197,7 @@ export interface SessionData {
|
|||
screen: string;
|
||||
language: string;
|
||||
country: string;
|
||||
subdivision1: string;
|
||||
subdivision2: string;
|
||||
region: string;
|
||||
city: string;
|
||||
ip?: string;
|
||||
userAgent?: string;
|
||||
|
|
|
|||
|
|
@ -36,8 +36,7 @@ export async function saveEvent(args: {
|
|||
screen?: string;
|
||||
language?: string;
|
||||
country?: string;
|
||||
subdivision1?: string;
|
||||
subdivision2?: string;
|
||||
region?: string;
|
||||
city?: string;
|
||||
tag?: string;
|
||||
createdAt?: Date;
|
||||
|
|
@ -72,6 +71,7 @@ async function relationalQuery(data: {
|
|||
eventName?: string;
|
||||
eventData?: any;
|
||||
tag?: string;
|
||||
hostname?: string;
|
||||
createdAt?: Date;
|
||||
}) {
|
||||
const {
|
||||
|
|
@ -98,6 +98,7 @@ async function relationalQuery(data: {
|
|||
lifatid,
|
||||
twclid,
|
||||
tag,
|
||||
hostname,
|
||||
createdAt,
|
||||
} = data;
|
||||
const websiteEventId = uuid();
|
||||
|
|
@ -128,6 +129,7 @@ async function relationalQuery(data: {
|
|||
eventType: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
||||
eventName: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
||||
tag,
|
||||
hostname,
|
||||
createdAt,
|
||||
},
|
||||
});
|
||||
|
|
@ -177,8 +179,7 @@ async function clickhouseQuery(data: {
|
|||
screen?: string;
|
||||
language?: string;
|
||||
country?: string;
|
||||
subdivision1?: string;
|
||||
subdivision2?: string;
|
||||
region?: string;
|
||||
city?: string;
|
||||
tag?: string;
|
||||
createdAt?: Date;
|
||||
|
|
@ -207,8 +208,7 @@ async function clickhouseQuery(data: {
|
|||
eventName,
|
||||
eventData,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
region,
|
||||
city,
|
||||
tag,
|
||||
createdAt,
|
||||
|
|
@ -225,13 +225,7 @@ async function clickhouseQuery(data: {
|
|||
visit_id: visitId,
|
||||
event_id: eventId,
|
||||
country: country,
|
||||
subdivision1:
|
||||
country && subdivision1
|
||||
? subdivision1.includes('-')
|
||||
? subdivision1
|
||||
: `${country}-${subdivision1}`
|
||||
: null,
|
||||
subdivision2: subdivision2,
|
||||
region: country && region ? (region.includes('-') ? region : `${country}-${region}`) : null,
|
||||
city: city,
|
||||
url_path: urlPath?.substring(0, URL_LENGTH),
|
||||
url_query: urlQuery?.substring(0, URL_LENGTH),
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ async function relationalQuery(
|
|||
let excludeDomain = '';
|
||||
|
||||
if (column === 'referrer_domain') {
|
||||
excludeDomain = `and website_event.referrer_domain != session.hostname
|
||||
excludeDomain = `and website_event.referrer_domain != website_event.hostname
|
||||
and website_event.referrer_domain != ''`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,34 +2,19 @@ import { Prisma } from '@prisma/client';
|
|||
import prisma from '@/lib/prisma';
|
||||
|
||||
export async function createSession(data: Prisma.SessionCreateInput) {
|
||||
const {
|
||||
id,
|
||||
websiteId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
city,
|
||||
} = data;
|
||||
const { id, websiteId, browser, os, device, screen, language, country, region, city } = data;
|
||||
|
||||
return prisma.client.session.create({
|
||||
data: {
|
||||
id,
|
||||
websiteId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
region,
|
||||
city,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ async function relationalQuery(
|
|||
joinSession: SESSION_COLUMNS.includes(type),
|
||||
},
|
||||
);
|
||||
const includeCountry = column === 'city' || column === 'subdivision1';
|
||||
const includeCountry = column === 'city' || column === 'region';
|
||||
|
||||
return rawQuery(
|
||||
`
|
||||
|
|
@ -75,7 +75,7 @@ async function clickhouseQuery(
|
|||
...filters,
|
||||
eventType: EVENT_TYPE.pageView,
|
||||
});
|
||||
const includeCountry = column === 'city' || column === 'subdivision1';
|
||||
const includeCountry = column === 'city' || column === 'region';
|
||||
|
||||
let sql = '';
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ async function relationalQuery(websiteId: string, sessionId: string) {
|
|||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
region,
|
||||
city,
|
||||
min(min_time) as "firstAt",
|
||||
max(max_time) as "lastAt",
|
||||
|
|
@ -35,14 +35,14 @@ async function relationalQuery(websiteId: string, sessionId: string) {
|
|||
session.session_id as id,
|
||||
website_event.visit_id,
|
||||
session.website_id,
|
||||
session.hostname,
|
||||
website_event.hostname,
|
||||
session.browser,
|
||||
session.os,
|
||||
session.device,
|
||||
session.screen,
|
||||
session.language,
|
||||
session.country,
|
||||
session.subdivision1,
|
||||
session.region,
|
||||
session.city,
|
||||
min(website_event.created_at) as min_time,
|
||||
max(website_event.created_at) as max_time,
|
||||
|
|
@ -52,8 +52,8 @@ async function relationalQuery(websiteId: string, sessionId: string) {
|
|||
join website_event on website_event.session_id = session.session_id
|
||||
where session.website_id = {{websiteId::uuid}}
|
||||
and session.session_id = {{sessionId::uuid}}
|
||||
group by session.session_id, visit_id, session.website_id, session.hostname, session.browser, session.os, session.device, session.screen, session.language, session.country, session.subdivision1, session.city) t
|
||||
group by id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city;
|
||||
group by session.session_id, visit_id, session.website_id, website_event.hostname, session.browser, session.os, session.device, session.screen, session.language, session.country, session.region, session.city) t
|
||||
group by id, website_id, hostname, browser, os, device, screen, language, country, region, city;
|
||||
`,
|
||||
{ websiteId, sessionId },
|
||||
).then(result => result?.[0]);
|
||||
|
|
@ -73,7 +73,7 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
|
|||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
region,
|
||||
city,
|
||||
${getDateStringSQL('min(min_time)')} as firstAt,
|
||||
${getDateStringSQL('max(max_time)')} as lastAt,
|
||||
|
|
@ -92,7 +92,7 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
|
|||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
region,
|
||||
city,
|
||||
min(min_time) as min_time,
|
||||
max(max_time) as max_time,
|
||||
|
|
@ -101,8 +101,8 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
|
|||
from website_event_stats_hourly
|
||||
where website_id = {websiteId:UUID}
|
||||
and session_id = {sessionId:UUID}
|
||||
group by session_id, visit_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city) t
|
||||
group by id, websiteId, hostname, browser, os, device, screen, language, country, subdivision1, city;
|
||||
group by session_id, visit_id, website_id, hostname, browser, os, device, screen, language, country, region, city) t
|
||||
group by id, websiteId, hostname, browser, os, device, screen, language, country, region, city;
|
||||
`,
|
||||
{ websiteId, sessionId },
|
||||
).then(result => result?.[0]);
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
select
|
||||
session.session_id as "id",
|
||||
session.website_id as "websiteId",
|
||||
session.hostname,
|
||||
website_event.hostname,
|
||||
session.browser,
|
||||
session.os,
|
||||
session.device,
|
||||
session.screen,
|
||||
session.language,
|
||||
session.country,
|
||||
session.subdivision1,
|
||||
session.region,
|
||||
session.city,
|
||||
min(website_event.created_at) as "firstAt",
|
||||
max(website_event.created_at) as "lastAt",
|
||||
|
|
@ -45,14 +45,14 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
${filterQuery}
|
||||
group by session.session_id,
|
||||
session.website_id,
|
||||
session.hostname,
|
||||
website_event.hostname,
|
||||
session.browser,
|
||||
session.os,
|
||||
session.device,
|
||||
session.screen,
|
||||
session.language,
|
||||
session.country,
|
||||
session.subdivision1,
|
||||
session.region,
|
||||
session.city
|
||||
order by max(website_event.created_at) desc
|
||||
limit 1000)
|
||||
|
|
@ -80,7 +80,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
region,
|
||||
city,
|
||||
${getDateStringSQL('min(min_time)')} as firstAt,
|
||||
${getDateStringSQL('max(max_time)')} as lastAt,
|
||||
|
|
@ -91,7 +91,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
where website_id = {websiteId:UUID}
|
||||
${dateQuery}
|
||||
${filterQuery}
|
||||
group by session_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city
|
||||
group by session_id, website_id, hostname, browser, os, device, screen, language, country, region, city
|
||||
order by lastAt desc
|
||||
limit 1000)
|
||||
select * from sessions
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue