From d0fb1dd4ddb5e70b7525b7204e7de9f44000f14f Mon Sep 17 00:00:00 2001 From: Viet-Tien Ngoc Date: Sat, 20 Jul 2024 11:23:34 +0700 Subject: [PATCH] save ip, lat, lng of session --- db/clickhouse/migrations/04_ip_lat_lng.sql | 4 +++ db/clickhouse/schema.sql | 3 ++ .../migrations/07_ip_lat_lng/migration.sql | 9 ++++++ db/mysql/schema.prisma | 18 ++++++++---- .../migrations/07_ip_lat_lng/migration.sql | 9 ++++++ db/postgresql/schema.prisma | 12 ++++++-- src/lib/detect.ts | 28 ++++++++++++++++++- src/lib/session.ts | 21 ++++++++++++-- src/lib/types.ts | 3 ++ .../analytics/sessions/createSession.ts | 6 ++++ 10 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 db/clickhouse/migrations/04_ip_lat_lng.sql create mode 100644 db/mysql/migrations/07_ip_lat_lng/migration.sql create mode 100644 db/postgresql/migrations/07_ip_lat_lng/migration.sql diff --git a/db/clickhouse/migrations/04_ip_lat_lng.sql b/db/clickhouse/migrations/04_ip_lat_lng.sql new file mode 100644 index 000000000..02c6c5410 --- /dev/null +++ b/db/clickhouse/migrations/04_ip_lat_lng.sql @@ -0,0 +1,4 @@ +-- AlterTable +ALTER TABLE "session" ADD COLUMN "ip" VARCHAR(40), +ADD COLUMN "lat" FLOAT, +ADD COLUMN "lng" FLOAT; \ No newline at end of file diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index 53fba1fb7..c1e525c13 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -16,6 +16,9 @@ CREATE TABLE umami.website_event subdivision1 LowCardinality(String), subdivision2 LowCardinality(String), city String, + ip Nullable(String), + lat Nullable(Float32), + lng Nullable(Float32), --pageviews url_path String, url_query String, diff --git a/db/mysql/migrations/07_ip_lat_lng/migration.sql b/db/mysql/migrations/07_ip_lat_lng/migration.sql new file mode 100644 index 000000000..cda15a15e --- /dev/null +++ b/db/mysql/migrations/07_ip_lat_lng/migration.sql @@ -0,0 +1,9 @@ +-- AlterTable +ALTER TABLE "session" ADD COLUMN "ip" VARCHAR(255), +ADD COLUMN "lat" FLOAT, +ADD COLUMN "lng" FLOAT; + +-- CreateIndex +CREATE INDEX `session_website_id_created_at_ip_idx` ON `session`(`website_id`, `created_at`, `ip`); +CREATE INDEX `session_website_id_created_at_lat_idx` ON `session`(`website_id`, `created_at`, `lat`); +CREATE INDEX `session_website_id_created_at_lng_idx` ON `session`(`website_id`, `created_at`, `lng`); diff --git a/db/mysql/schema.prisma b/db/mysql/schema.prisma index a7722accd..c972be81b 100644 --- a/db/mysql/schema.prisma +++ b/db/mysql/schema.prisma @@ -19,10 +19,10 @@ model User { updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamp(0) deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) - websiteUser Website[] @relation("user") - websiteCreateUser Website[] @relation("createUser") - teamUser TeamUser[] - report Report[] + websiteUser Website[] @relation("user") + websiteCreateUser Website[] @relation("createUser") + teamUser TeamUser[] + report Report[] @@map("user") } @@ -40,6 +40,9 @@ model Session { subdivision1 String? @db.Char(20) subdivision2 String? @db.VarChar(50) city String? @db.VarChar(50) + ip String? @db.VarChar(40) + lat Float? + lng Float? createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) websiteEvent WebsiteEvent[] @@ -57,6 +60,9 @@ model Session { @@index([websiteId, createdAt, country]) @@index([websiteId, createdAt, subdivision1]) @@index([websiteId, createdAt, city]) + @@index([websiteId, createdAt, ip]) + @@index([websiteId, createdAt, lat]) + @@index([websiteId, createdAt, lng]) @@map("session") } @@ -174,8 +180,8 @@ model Team { updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamp(0) deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) - website Website[] - teamUser TeamUser[] + website Website[] + teamUser TeamUser[] @@index([accessCode]) @@map("team") diff --git a/db/postgresql/migrations/07_ip_lat_lng/migration.sql b/db/postgresql/migrations/07_ip_lat_lng/migration.sql new file mode 100644 index 000000000..914d86227 --- /dev/null +++ b/db/postgresql/migrations/07_ip_lat_lng/migration.sql @@ -0,0 +1,9 @@ +-- AlterTable +ALTER TABLE "session" ADD COLUMN "ip" VARCHAR(40), +ADD COLUMN "lat" FLOAT, +ADD COLUMN "lng" FLOAT; + +-- CreateIndex +CREATE INDEX "session_website_id_created_at_ip_idx" ON "session"("website_id", "created_at", "ip"); +CREATE INDEX "session_website_id_created_at_lat_idx" ON "session"("website_id", "created_at", "lat"); +CREATE INDEX "session_website_id_created_at_lng_idx" ON "session"("website_id", "created_at", "lng"); diff --git a/db/postgresql/schema.prisma b/db/postgresql/schema.prisma index b9009e0fb..6d52dfbc4 100644 --- a/db/postgresql/schema.prisma +++ b/db/postgresql/schema.prisma @@ -19,8 +19,8 @@ model User { updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) - websiteUser Website[] @relation("user") - websiteCreateUser Website[] @relation("createUser") + websiteUser Website[] @relation("user") + websiteCreateUser Website[] @relation("createUser") teamUser TeamUser[] report Report[] @@ -40,6 +40,9 @@ model Session { subdivision1 String? @db.VarChar(20) subdivision2 String? @db.VarChar(50) city String? @db.VarChar(50) + ip String? @db.VarChar(40) + lat Float? + lng Float? createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) websiteEvent WebsiteEvent[] @@ -57,6 +60,9 @@ model Session { @@index([websiteId, createdAt, country]) @@index([websiteId, createdAt, subdivision1]) @@index([websiteId, createdAt, city]) + @@index([websiteId, createdAt, ip]) + @@index([websiteId, createdAt, lat]) + @@index([websiteId, createdAt, lng]) @@map("session") } @@ -147,7 +153,7 @@ model SessionData { id String @id() @map("session_data_id") @db.Uuid websiteId String @map("website_id") @db.Uuid sessionId String @map("session_id") @db.Uuid - dataKey String @map("data_key") @db.VarChar(500) + dataKey String @map("data_key") @db.VarChar(500) stringValue String? @map("string_value") @db.VarChar(500) numberValue Decimal? @map("number_value") @db.Decimal(19, 4) dateValue DateTime? @map("date_value") @db.Timestamptz(6) diff --git a/src/lib/detect.ts b/src/lib/detect.ts index c3b3f3da3..4a00d086b 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -84,11 +84,15 @@ export async function getLocation(ip: string, req: NextApiRequestCollect) { const country = safeDecodeURIComponent(req.headers['cf-ipcountry']); const subdivision1 = safeDecodeURIComponent(req.headers['cf-region-code']); const city = safeDecodeURIComponent(req.headers['cf-ipcity']); + const lat = safeDecodeURIComponent(req.headers['cf-iplatitude']); + const lng = safeDecodeURIComponent(req.headers['cf-iplongitude']); return { country, subdivision1: getRegionCode(country, subdivision1), city, + lat: parseFloat(lat), + lng: parseFloat(lng), }; } @@ -99,11 +103,15 @@ export async function getLocation(ip: string, req: NextApiRequestCollect) { const country = safeDecodeURIComponent(req.headers['x-vercel-ip-country']); const subdivision1 = safeDecodeURIComponent(req.headers['x-vercel-ip-country-region']); const city = safeDecodeURIComponent(req.headers['x-vercel-ip-city']); + const lat = safeDecodeURIComponent(req.headers['x-vercel-ip-latitude']); + const lng = safeDecodeURIComponent(req.headers['x-vercel-ip-longitude']); return { country, subdivision1: getRegionCode(country, subdivision1), city, + lat: parseFloat(lat), + lng: parseFloat(lng), }; } @@ -121,12 +129,16 @@ export async function getLocation(ip: string, req: NextApiRequestCollect) { const subdivision1 = result.subdivisions?.[0]?.iso_code; const subdivision2 = result.subdivisions?.[1]?.names?.en; const city = result.city?.names?.en; + const lat = result.location?.latitude; + const lng = result.location?.longitude; return { country, subdivision1: getRegionCode(country, subdivision1), subdivision2, city, + lat, + lng, }; } @@ -141,9 +153,23 @@ export async function getClientInfo(req: NextApiRequestCollect) { const subdivision1 = location?.subdivision1; const subdivision2 = location?.subdivision2; const city = location?.city; + const lat = location?.lat; + const lng = location?.lng; const browser = browserName(userAgent); const os = detectOS(userAgent) as string; const device = getDevice(req.body?.payload?.screen, os); - return { userAgent, browser, os, ip, country, subdivision1, subdivision2, city, device }; + return { + userAgent, + browser, + os, + ip, + country, + subdivision1, + subdivision2, + city, + device, + lat, + lng, + }; } diff --git a/src/lib/session.ts b/src/lib/session.ts index cf30aa712..1dd5e65b8 100644 --- a/src/lib/session.ts +++ b/src/lib/session.ts @@ -36,8 +36,19 @@ export async function getSession(req: NextApiRequestCollect): Promise