fix
This commit is contained in:
+39
-4
@@ -259,6 +259,7 @@ function ensureAnalyticsDb() {
|
||||
os text not null default 'Unknown',
|
||||
device text not null default 'Desktop',
|
||||
screen text not null default '',
|
||||
theme text not null default 'light',
|
||||
language text not null default '',
|
||||
timezone text not null default '',
|
||||
country text not null default '',
|
||||
@@ -284,6 +285,7 @@ function ensureAnalyticsDb() {
|
||||
os text not null default 'Unknown',
|
||||
device text not null default 'Desktop',
|
||||
screen text not null default '',
|
||||
theme text not null default 'light',
|
||||
language text not null default '',
|
||||
timezone text not null default '',
|
||||
country text not null default '',
|
||||
@@ -314,6 +316,8 @@ function ensureAnalyticsDb() {
|
||||
`alter table active_viewers add column latitude real`,
|
||||
`alter table viewer_events add column longitude real`,
|
||||
`alter table active_viewers add column longitude real`,
|
||||
`alter table viewer_events add column theme text not null default 'light'`,
|
||||
`alter table active_viewers add column theme text not null default 'light'`,
|
||||
]) {
|
||||
try {
|
||||
analyticsDb.exec(statement)
|
||||
@@ -578,6 +582,10 @@ function numberHeader(req, name, min, max) {
|
||||
return value
|
||||
}
|
||||
|
||||
function sanitizeTheme(value) {
|
||||
return value === 'dark' ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
const CITY_COORDINATE_OVERRIDES = new Map([
|
||||
['GB|ENGLAND|MILTON KEYNES', { latitude: 52.0406, longitude: -0.7594 }],
|
||||
])
|
||||
@@ -969,6 +977,7 @@ function recordViewerEvent(req, payload) {
|
||||
os: sanitizeText(payload.os || (shareUserAgent ? serverClient.os : 'Not shared'), 80),
|
||||
device: sanitizeText(payload.device || (shareUserAgent ? serverClient.device : 'Not shared'), 80),
|
||||
screen: sanitizeText(payload.screen, 40),
|
||||
theme: sanitizeTheme(payload.theme),
|
||||
language: sanitizeText(payload.language, 40),
|
||||
timezone: sanitizeText(payload.timezone, 80),
|
||||
country: location.country,
|
||||
@@ -989,22 +998,22 @@ function recordViewerEvent(req, payload) {
|
||||
db.prepare(`
|
||||
insert into viewer_events
|
||||
(occurred_at, visitor_id, session_id, ip_hash, event_type, page_path, page_title,
|
||||
referrer, user_agent, browser, os, device, screen, language, timezone,
|
||||
referrer, user_agent, browser, os, device, screen, theme, language, timezone,
|
||||
country, region, city, latitude, longitude, consent, metadata)
|
||||
values
|
||||
(@occurred_at, @visitor_id, @session_id, @ip_hash, @event_type, @page_path, @page_title,
|
||||
@referrer, @user_agent, @browser, @os, @device, @screen, @language, @timezone,
|
||||
@referrer, @user_agent, @browser, @os, @device, @screen, @theme, @language, @timezone,
|
||||
@country, @region, @city, @latitude, @longitude, @consent, @metadata)
|
||||
`).run({ ...event, occurred_at: now })
|
||||
|
||||
db.prepare(`
|
||||
insert into active_viewers
|
||||
(session_id, visitor_id, ip_hash, first_seen_at, last_seen_at, page_path, page_title,
|
||||
referrer, user_agent, browser, os, device, screen, language, timezone,
|
||||
referrer, user_agent, browser, os, device, screen, theme, language, timezone,
|
||||
country, region, city, latitude, longitude)
|
||||
values
|
||||
(@session_id, @visitor_id, @ip_hash, @now, @now, @page_path, @page_title,
|
||||
@referrer, @user_agent, @browser, @os, @device, @screen, @language, @timezone,
|
||||
@referrer, @user_agent, @browser, @os, @device, @screen, @theme, @language, @timezone,
|
||||
@country, @region, @city, @latitude, @longitude)
|
||||
on conflict(session_id) do update set
|
||||
last_seen_at = excluded.last_seen_at,
|
||||
@@ -1016,6 +1025,7 @@ function recordViewerEvent(req, payload) {
|
||||
os = excluded.os,
|
||||
device = excluded.device,
|
||||
screen = excluded.screen,
|
||||
theme = excluded.theme,
|
||||
language = excluded.language,
|
||||
timezone = excluded.timezone,
|
||||
country = excluded.country,
|
||||
@@ -1077,6 +1087,7 @@ function viewerDashboard() {
|
||||
max(os) as os,
|
||||
max(device) as device,
|
||||
max(screen) as screen,
|
||||
max(theme) as theme,
|
||||
max(language) as language,
|
||||
max(timezone) as timezone,
|
||||
max(country) as country,
|
||||
@@ -1102,6 +1113,7 @@ function viewerDashboard() {
|
||||
os: row.os,
|
||||
device: row.device,
|
||||
screen: row.screen,
|
||||
theme: sanitizeTheme(row.theme),
|
||||
language: row.language,
|
||||
timezone: row.timezone,
|
||||
country: row.country,
|
||||
@@ -1121,12 +1133,14 @@ function viewerDashboard() {
|
||||
visitors: new Set(),
|
||||
clients: new Map(),
|
||||
countries: new Set(),
|
||||
themes: new Map(),
|
||||
last_seen_at: viewer.last_seen_at,
|
||||
}
|
||||
|
||||
existing.viewers += viewer.sessions || 1
|
||||
existing.visitors.add(viewer.visitor)
|
||||
if (viewer.country) existing.countries.add(viewer.country)
|
||||
existing.themes.set(viewer.theme, (existing.themes.get(viewer.theme) || 0) + (viewer.sessions || 1))
|
||||
const clientKey = `${viewer.browser} on ${viewer.os}`
|
||||
existing.clients.set(clientKey, (existing.clients.get(clientKey) || 0) + 1)
|
||||
if (new Date(viewer.last_seen_at).getTime() > new Date(existing.last_seen_at).getTime()) {
|
||||
@@ -1142,6 +1156,9 @@ function viewerDashboard() {
|
||||
viewers: page.viewers,
|
||||
visitors: page.visitors.size,
|
||||
countries: Array.from(page.countries).sort(),
|
||||
themes: Array.from(page.themes.entries())
|
||||
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
||||
.map(([theme, count]) => ({ theme, count })),
|
||||
clients: Array.from(page.clients.entries())
|
||||
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
||||
.slice(0, 4)
|
||||
@@ -1188,6 +1205,22 @@ function viewerDashboard() {
|
||||
limit 12
|
||||
`).all(thirtyDaysSince)
|
||||
|
||||
const themes = db.prepare(`
|
||||
select theme, count(*) as events, count(distinct visitor_id) as visitors
|
||||
from viewer_events
|
||||
where occurred_at >= ?
|
||||
group by theme
|
||||
order by events desc
|
||||
`).all(daySince).map((row) => ({ ...row, theme: sanitizeTheme(row.theme) }))
|
||||
|
||||
const themes30d = db.prepare(`
|
||||
select theme, count(*) as events, count(distinct visitor_id) as visitors
|
||||
from viewer_events
|
||||
where occurred_at >= ?
|
||||
group by theme
|
||||
order by events desc
|
||||
`).all(thirtyDaysSince).map((row) => ({ ...row, theme: sanitizeTheme(row.theme) }))
|
||||
|
||||
const activity24h = db.prepare(`
|
||||
select
|
||||
substr(occurred_at, 1, 13) || ':00:00.000Z' as date,
|
||||
@@ -1447,6 +1480,8 @@ function viewerDashboard() {
|
||||
top_pages_30d: topPages30d,
|
||||
clients,
|
||||
clients_30d: clients30d,
|
||||
themes,
|
||||
themes_30d: themes30d,
|
||||
activity_24h: activity24hWithLabels,
|
||||
activity_30d: activityWithLocations,
|
||||
countries_24h: countries24h,
|
||||
|
||||
Reference in New Issue
Block a user