From 68fab48ab729e7d6ac4d925ab8c35dbedd9885ab Mon Sep 17 00:00:00 2001 From: 360 Date: Thu, 15 May 2025 10:13:07 +0100 Subject: [PATCH 1/8] fix: correct example description for Umami version in bug report template --- .github/ISSUE_TEMPLATE/1.bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index 711468f2..2404918b 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -25,7 +25,7 @@ body: - type: input attributes: label: Which Umami version are you using? (if relevant) - description: 'For example: Chrome, Edge, Firefox, etc' + description: 'For example: 2.18.0, 2.15.1, 1.39.0, etc' - type: input attributes: label: Which browser are you using? (if relevant) From 8d483d92830cda0efa15d5c54d42a26168004077 Mon Sep 17 00:00:00 2001 From: Eritque arcus Date: Thu, 22 May 2025 00:19:50 -0500 Subject: [PATCH 2/8] fix: hash is not included in record --- src/app/api/send/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/send/route.ts b/src/app/api/send/route.ts index 60d6f7af..9d41a68f 100644 --- a/src/app/api/send/route.ts +++ b/src/app/api/send/route.ts @@ -145,7 +145,7 @@ export async function POST(request: Request) { const base = hostname ? `https://${hostname}` : 'https://localhost'; const currentUrl = new URL(url, base); - let urlPath = currentUrl.pathname === '/undefined' ? '' : currentUrl.pathname; + let urlPath = currentUrl.pathname === '/undefined' ? '' : currentUrl.pathname + currentUrl.hash; const urlQuery = currentUrl.search.substring(1); const urlDomain = currentUrl.hostname.replace(/^www./, ''); From 33110a44ec1c04896e4b6f06ba7773156901b6d6 Mon Sep 17 00:00:00 2001 From: Eritque arcus Date: Thu, 22 May 2025 00:24:48 -0500 Subject: [PATCH 3/8] fix: fix remove trailing slash regex --- src/app/api/send/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/send/route.ts b/src/app/api/send/route.ts index 9d41a68f..65c88a28 100644 --- a/src/app/api/send/route.ts +++ b/src/app/api/send/route.ts @@ -169,7 +169,7 @@ export async function POST(request: Request) { const twclid = currentUrl.searchParams.get('twclid'); if (process.env.REMOVE_TRAILING_SLASH) { - urlPath = urlPath.replace(/(.+)\/$/, '$1'); + urlPath = urlPath.replace(/\/(?=(#.*)?$)/, ''); } if (referrer) { From e8f166cc690c595f21a1ebf6143bbaf61b343848 Mon Sep 17 00:00:00 2001 From: Ru Chern Chong <10343662+ruchernchong@users.noreply.github.com> Date: Thu, 22 May 2025 15:19:34 +0800 Subject: [PATCH 4/8] Update ci.yml Only run the CI if it belongs to the original repository --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 314c6944..835407b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,8 @@ env: jobs: build: + # Only run the CI if it belongs to the original repository + if: github.repository == 'umami-software/umami' runs-on: ubuntu-latest strategy: From 57acaf9855063f6143d79543fa96acd43231f366 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 4 Jun 2025 16:06:11 -0700 Subject: [PATCH 5/8] remove data conversion --- .../migrations/12_update_report_parameter/migration.sql | 4 ---- 1 file changed, 4 deletions(-) diff --git a/db/postgresql/migrations/12_update_report_parameter/migration.sql b/db/postgresql/migrations/12_update_report_parameter/migration.sql index aca2f39d..19b663f4 100644 --- a/db/postgresql/migrations/12_update_report_parameter/migration.sql +++ b/db/postgresql/migrations/12_update_report_parameter/migration.sql @@ -1,7 +1,3 @@ --- ConvertData -UPDATE "report" -SET "parameters" = CONCAT('"', REPLACE(parameters, '"', '\"'), '"'); - -- AlterTable ALTER TABLE "report" ALTER COLUMN "parameters" SET DATA TYPE JSONB USING parameters::JSONB; From 826f29bbc07438597999160cac26e30fbe3e1e4d Mon Sep 17 00:00:00 2001 From: undefined Date: Thu, 5 Jun 2025 17:34:09 +0100 Subject: [PATCH 6/8] chore: allow custom geolite database path --- src/lib/detect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/detect.ts b/src/lib/detect.ts index a023d27d..99c101ab 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -124,7 +124,7 @@ export async function getLocation(ip: string = '', headers: Headers, hasPayloadI if (!global[MAXMIND]) { const dir = path.join(process.cwd(), 'geo'); - global[MAXMIND] = await maxmind.open(path.resolve(dir, 'GeoLite2-City.mmdb')); + global[MAXMIND] = await maxmind.open(process.env.GEOLITE_DB_PATH || path.resolve(dir, 'GeoLite2-City.mmdb')); } const result = global[MAXMIND].get(ip); From a16846f4ce2cbed81eeb3be7a1c02222fddc90be Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 6 Jun 2025 08:47:52 -0700 Subject: [PATCH 7/8] add website_revenue table and view. update revenue report to use view --- db/clickhouse/schema.sql | 35 ++++++++++++++ src/queries/sql/reports/getRevenue.ts | 68 ++++++++------------------- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index fef600e0..ff85112b 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -246,3 +246,38 @@ SELECT * ORDER BY toStartOfDay(created_at), website_id, referrer_domain, created ); ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_referrer_domain_projection; + +-- revenue +CREATE TABLE umami.website_revenue +( + website_id UUID, + session_id UUID, + event_id UUID, + event_name String, + currency String, + revenue DECIMAL(18,4), + created_at DateTime('UTC') +) +ENGINE = MergeTree + PARTITION BY toYYYYMM(created_at) + ORDER BY (website_id, session_id, created_at) + SETTINGS index_granularity = 8192; + + +CREATE MATERIALIZED VIEW umami.website_revenue_mv +TO umami.website_revenue +AS +SELECT DISTINCT + ed.website_id, + ed.session_id, + ed.event_id, + ed.event_name, + c.currency, + coalesce(toDecimal64(ed.number_value, 2), toDecimal64(ed.string_value, 2)) revenue, + ed.created_at +FROM umami.event_data ed +JOIN (SELECT event_id, string_value as currency + FROM event_data + WHERE positionCaseInsensitive(data_key, 'currency') > 0) c + ON c.event_id = ed.event_id +WHERE positionCaseInsensitive(data_key, 'revenue') > 0; diff --git a/src/queries/sql/reports/getRevenue.ts b/src/queries/sql/reports/getRevenue.ts index f1fb1d73..f7996fcc 100644 --- a/src/queries/sql/reports/getRevenue.ts +++ b/src/queries/sql/reports/getRevenue.ts @@ -180,18 +180,11 @@ async function clickhouseQuery( select event_name x, ${getDateSQL('created_at', unit, timezone)} t, - sum(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) y - from event_data - join (select event_id - from event_data - where website_id = {websiteId:UUID} - and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'currency') > 0 - and string_value = {currency:String}) currency - on currency.event_id = event_data.event_id + sum(revenue) y + from website_revenue where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'revenue') > 0 + and currency = {currency:String} group by x, t order by t `, @@ -207,23 +200,16 @@ async function clickhouseQuery( ` select s.country as name, - sum(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) as value - from event_data ed - join (select event_id - from event_data - where website_id = {websiteId:UUID} - and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'currency') > 0 - and string_value = {currency:String}) c - on c.event_id = ed.event_id + sum(w.revenue) as value + from website_revenue w join (select distinct website_id, session_id, country from website_event_stats_hourly where website_id = {websiteId:UUID}) s - on ed.website_id = s.website_id - and ed.session_id = s.session_id - where ed.website_id = {websiteId:UUID} - and ed.created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(ed.data_key, 'revenue') > 0 + on w.website_id = s.website_id + and w.session_id = s.session_id + where w.website_id = {websiteId:UUID} + and w.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and w.currency = {currency:String} group by s.country `, { websiteId, startDate, endDate, currency }, @@ -237,20 +223,13 @@ async function clickhouseQuery( }>( ` select - sum(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) as sum, + sum(revenue) as sum, uniqExact(event_id) as count, uniqExact(session_id) as unique_count - from event_data - join (select event_id - from event_data - where website_id = {websiteId:UUID} - and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'currency') > 0 - and string_value = {currency:String}) currency - on currency.event_id = event_data.event_id + from website_revenue where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'revenue') > 0 + and currency = {currency:String} `, { websiteId, startDate, endDate, currency }, ).then(result => result?.[0]); @@ -266,22 +245,15 @@ async function clickhouseQuery( >( ` select - c.currency, - sum(coalesce(toDecimal64(ed.number_value, 2), toDecimal64(ed.string_value, 2))) as sum, - uniqExact(ed.event_id) as count, - uniqExact(ed.session_id) as unique_count - from event_data ed - join (select event_id, string_value as currency - from event_data - where website_id = {websiteId:UUID} - and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'currency') > 0) c - on c.event_id = ed.event_id + currency, + sum(revenue) as sum, + uniqExact(event_id) as count, + uniqExact(session_id) as unique_count + from website_revenue where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'revenue') > 0 - group by c.currency - order by sum desc; + group by currency + order by sum desc `, { websiteId, startDate, endDate, unit, timezone, currency }, ); From 9a437dcfa2110ca150c598b1b2042d8444fbdea2 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Sat, 7 Jun 2025 07:43:36 -0700 Subject: [PATCH 8/8] convert attribution report --- db/clickhouse/schema.sql | 2 +- src/queries/sql/reports/getAttribution.ts | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index ff85112b..396d300a 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -277,7 +277,7 @@ SELECT DISTINCT ed.created_at FROM umami.event_data ed JOIN (SELECT event_id, string_value as currency - FROM event_data + FROM umami.event_data WHERE positionCaseInsensitive(data_key, 'currency') > 0) c ON c.event_id = ed.event_id WHERE positionCaseInsensitive(data_key, 'revenue') > 0; diff --git a/src/queries/sql/reports/getAttribution.ts b/src/queries/sql/reports/getAttribution.ts index 0c3d447a..f224eb5c 100644 --- a/src/queries/sql/reports/getAttribution.ts +++ b/src/queries/sql/reports/getAttribution.ts @@ -311,21 +311,14 @@ async function clickhouseQuery( const revenueEventQuery = `WITH events AS ( select - ed.session_id, - max(ed.created_at) max_dt, - sum(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) as value - from event_data ed - join (select event_id - from event_data - where website_id = {websiteId:UUID} - and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and positionCaseInsensitive(data_key, 'currency') > 0 - and string_value = {currency:String}) c - on c.event_id = ed.event_id + session_id, + max(created_at) max_dt, + sum(revenue) as value + from website_revenue where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and ${column} = {conversionStep:String} - and positionCaseInsensitive(ed.data_key, 'revenue') > 0 + and ${column} = {conversionStep:String} + and currency = {currency:String} group by 1),`; function getModelQuery(model: string) {