diff --git a/cmd/goatcounter/dashboard.go b/cmd/goatcounter/dashboard.go index a3165e7a7..00c85183b 100644 --- a/cmd/goatcounter/dashboard.go +++ b/cmd/goatcounter/dashboard.go @@ -236,7 +236,7 @@ func dash(url, key string, rng ztime.Range) error { }) for _, path := range data.hits.Hits { left = append(left, - nr(fmt.Sprintf("%-6d %-38s", path.CountUnique, zli.Colorize(zstring.ElideCenter(path.Path, 37), zli.Bold))), + nr(fmt.Sprintf("%-6d %-38s", path.Count, zli.Colorize(zstring.ElideCenter(path.Path, 37), zli.Bold))), nr(fmt.Sprintf(" %-38s", zstring.ElideLeft(path.Title, 37))), nr(""), ) @@ -259,7 +259,7 @@ func dash(url, key string, rng ztime.Range) error { stat.Name = "(unknown)" } var ( - p = float64(stat.CountUnique) / float64(data.total.TotalUniqueUTC) * 100 + p = float64(stat.Count) / float64(data.total.TotalUTC) * 100 perc string ) switch { @@ -289,7 +289,7 @@ func dash(url, key string, rng ztime.Range) error { // Combine the two columns fmt.Printf("%s\n", zli.Colorize(zstring.AlignCenter(fmt.Sprintf( - "%s – %d of %d visits shown", rng.String(), data.hits.TotalUnique, data.total.TotalUnique), + "%s – %d of %d visits shown", rng.String(), data.hits.Total, data.total.Total), 78), zli.Bold)) fmt.Printf("┌%s┬%s┐\n", strings.Repeat("─", 48), strings.Repeat("─", 30)) m := zint.Max(len(left), len(right)) @@ -322,10 +322,9 @@ type ( dashboardData struct { total goatcounter.TotalCount hits struct { - Hits goatcounter.HitLists `json:"hits"` - Total int `json:"total"` - TotalUnique int `json:"total_unique"` - More bool `json:"more"` + Hits goatcounter.HitLists `json:"hits"` + Total int `json:"total"` + More bool `json:"more"` } stats map[string]stats } diff --git a/cron/browser_stat.go b/cron/browser_stat.go index 43a15f080..97ccf8090 100644 --- a/cron/browser_stat.go +++ b/cron/browser_stat.go @@ -18,10 +18,10 @@ import ( func updateBrowserStats(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { type gt struct { - countUnique int - day string - browserID int64 - pathID int64 + count int + day string + browserID int64 + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -39,31 +39,31 @@ func updateBrowserStats(ctx context.Context, hits []goatcounter.Hit) error { day := h.CreatedAt.Format("2006-01-02") k := day + strconv.FormatInt(h.BrowserID, 10) + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if v.countUnique == 0 { + if v.count == 0 { v.day = day v.browserID = h.BrowserID v.pathID = h.PathID } if h.FirstVisit { - v.countUnique += 1 + v.count += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID ins := zdb.NewBulkInsert(ctx, "browser_stats", []string{"site_id", "day", - "path_id", "browser_id", "count_unique"}) + "path_id", "browser_id", "count"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "browser_stats#site_id#path_id#day#browser_id" do update set - count_unique = browser_stats.count_unique + excluded.count_unique`) + count = browser_stats.count + excluded.count`) } else { ins.OnConflict(`on conflict(site_id, path_id, day, browser_id) do update set - count_unique = browser_stats.count_unique + excluded.count_unique`) + count = browser_stats.count + excluded.count`) } for _, v := range grouped { - ins.Values(siteID, v.day, v.pathID, v.browserID, v.countUnique) + ins.Values(siteID, v.day, v.pathID, v.browserID, v.count) } return ins.Finish() }), "cron.updateBrowserStats") diff --git a/cron/campaign_stat.go b/cron/campaign_stat.go index c5b0e9e59..ea5d11491 100644 --- a/cron/campaign_stat.go +++ b/cron/campaign_stat.go @@ -16,11 +16,11 @@ import ( func updateCampaignStats(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { type gt struct { - countUnique int - day string - campaignID int64 - ref string - pathID int64 + count int + day string + campaignID int64 + ref string + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -31,7 +31,7 @@ func updateCampaignStats(ctx context.Context, hits []goatcounter.Hit) error { day := h.CreatedAt.Format("2006-01-02") k := day + strconv.FormatInt(*h.CampaignID, 10) + h.Ref + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if v.countUnique == 0 { + if v.count == 0 { v.day = day v.campaignID = *h.CampaignID v.ref = h.Ref @@ -39,24 +39,24 @@ func updateCampaignStats(ctx context.Context, hits []goatcounter.Hit) error { } if h.FirstVisit { - v.countUnique += 1 + v.count += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID ins := zdb.NewBulkInsert(ctx, "campaign_stats", []string{"site_id", "day", - "path_id", "campaign_id", "ref", "count_unique"}) + "path_id", "campaign_id", "ref", "count"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "campaign_stats#site_id#path_id#campaign_id#ref#day" do update set - count_unique = campaign_stats.count_unique + excluded.count_unique`) + count = campaign_stats.count + excluded.count`) } else { ins.OnConflict(`on conflict(site_id, path_id, campaign_id, ref, day) do update set - count_unique = campaign_stats.count_unique + excluded.count_unique`) + count = campaign_stats.count + excluded.count`) } for _, v := range grouped { - ins.Values(siteID, v.day, v.pathID, v.campaignID, v.ref, v.countUnique) + ins.Values(siteID, v.day, v.pathID, v.campaignID, v.ref, v.count) } return ins.Finish() }), "cron.updateCampaignStats") diff --git a/cron/email_reports.go b/cron/email_reports.go index cdd40d30b..ae15e2820 100644 --- a/cron/email_reports.go +++ b/cron/email_reports.go @@ -177,7 +177,7 @@ func reportText(ctx context.Context, site goatcounter.Site, user goatcounter.Use fmt.Fprintf(b, " %-36s %9s %7s\n", template.HTMLEscapeString(zstring.ElideLeft(path, 35)), - tplfunc.Number(p.CountUnique, user.Settings.NumberFormat), + tplfunc.Number(p.Count, user.Settings.NumberFormat), diffStr[i]) } args.TextPagesTable = template.HTML(b.String()) @@ -199,7 +199,7 @@ func reportText(ctx context.Context, site goatcounter.Site, user goatcounter.Use } fmt.Fprintf(b, " %-45s %9s\n", template.HTMLEscapeString(zstring.ElideLeft(path, 44)), - tplfunc.Number(r.CountUnique, user.Settings.NumberFormat)) + tplfunc.Number(r.Count, user.Settings.NumberFormat)) //refs[i].Path = zstring.ElideLeft(refs[i].Path, 44) } args.TextRefTable = template.HTML(b.String()) diff --git a/cron/hit_count.go b/cron/hit_count.go index 74e61c344..2c32326d4 100644 --- a/cron/hit_count.go +++ b/cron/hit_count.go @@ -17,9 +17,9 @@ func updateHitCounts(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { // Group by day + pathID type gt struct { - totalUnique int - hour string - pathID int64 + total int + hour string + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -30,30 +30,30 @@ func updateHitCounts(ctx context.Context, hits []goatcounter.Hit) error { hour := h.CreatedAt.Format("2006-01-02 15:00:00") k := hour + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if v.totalUnique == 0 { + if v.total == 0 { v.hour = hour v.pathID = h.PathID } if h.FirstVisit { - v.totalUnique += 1 + v.total += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID ins := zdb.NewBulkInsert(ctx, "hit_counts", []string{"site_id", "path_id", - "hour", "total_unique"}) + "hour", "total"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "hit_counts#site_id#path_id#hour" do update set - total_unique = hit_counts.total_unique + excluded.total_unique`) + total = hit_counts.total + excluded.total`) } else { ins.OnConflict(`on conflict(site_id, path_id, hour) do update set - total_unique = hit_counts.total_unique + excluded.total_unique`) + total = hit_counts.total + excluded.total`) } for _, v := range grouped { - ins.Values(siteID, v.pathID, v.hour, v.totalUnique) + ins.Values(siteID, v.pathID, v.hour, v.total) } return ins.Finish() }), "cron.updateHitCounts") diff --git a/cron/hit_stat.go b/cron/hit_stat.go index 01506eddf..254e704a9 100644 --- a/cron/hit_stat.go +++ b/cron/hit_stat.go @@ -17,10 +17,10 @@ import ( func updateHitStats(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { type gt struct { - countUnique []int - day string - hour string - pathID int64 + count []int + day string + hour string + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -32,15 +32,15 @@ func updateHitStats(ctx context.Context, hits []goatcounter.Hit) error { dayHour := h.CreatedAt.Format("2006-01-02 15:00:00") k := day + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if len(v.countUnique) == 0 { + if len(v.count) == 0 { v.day = day v.hour = dayHour v.pathID = h.PathID - v.countUnique = make([]int, 24) + v.count = make([]int, 24) if zdb.SQLDialect(ctx) == zdb.DialectSQLite { var err error - v.countUnique, err = existingHitStats(ctx, h.Site, day, v.pathID) + v.count, err = existingHitStats(ctx, h.Site, day, v.pathID) if err != nil { return err } @@ -49,20 +49,20 @@ func updateHitStats(ctx context.Context, hits []goatcounter.Hit) error { hour, _ := strconv.ParseInt(h.CreatedAt.Format("15"), 10, 8) if h.FirstVisit { - v.countUnique[hour] += 1 + v.count[hour] += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID - ins := zdb.NewBulkInsert(ctx, "hit_stats", []string{"site_id", "day", "path_id", "stats_unique"}) + ins := zdb.NewBulkInsert(ctx, "hit_stats", []string{"site_id", "day", "path_id", "stats"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "hit_stats#site_id#path_id#day" do update set - stats_unique = ( + stats = ( with x as ( select - unnest(string_to_array(trim(hit_stats.stats_unique, '[]'), ',')::int[]) as orig, - unnest(string_to_array(trim(excluded.stats_unique, '[]'), ',')::int[]) as new + unnest(string_to_array(trim(hit_stats.stats, '[]'), ',')::int[]) as orig, + unnest(string_to_array(trim(excluded.stats, '[]'), ',')::int[]) as new ) select '[' || array_to_string(array_agg(orig + new), ',') || ']' from x ) `) @@ -72,24 +72,23 @@ func updateHitStats(ctx context.Context, hits []goatcounter.Hit) error { // it's kinda tricky with SQLite :-/ // // ins.OnConflict(`on conflict(site_id, path_id, day) do update set - // stats_unique = excluded.stats_unique + // stats = excluded.stats // `) // } for _, v := range grouped { - ins.Values(siteID, v.day, v.pathID, zjson.MustMarshal(v.countUnique)) + ins.Values(siteID, v.day, v.pathID, zjson.MustMarshal(v.count)) } return errors.Wrap(ins.Finish(), "updateHitStats hit_stats") }), "cron.updateHitStats") } func existingHitStats(ctx context.Context, siteID int64, day string, pathID int64) ([]int, error) { - var ex []struct { - StatsUnique []byte `db:"stats_unique"` + Stats []byte `db:"stats"` } err := zdb.Select(ctx, &ex, `/* existingHitStats */ - select stats_unique from hit_stats + select stats from hit_stats where site_id=$1 and day=$2 and path_id=$3 limit 1`, siteID, day, pathID) if err != nil { @@ -107,8 +106,8 @@ func existingHitStats(ctx context.Context, siteID int64, day string, pathID int6 } var ru []int - if ex[0].StatsUnique != nil { - zjson.MustUnmarshal(ex[0].StatsUnique, &ru) + if ex[0].Stats != nil { + zjson.MustUnmarshal(ex[0].Stats, &ru) } return ru, nil diff --git a/cron/hit_stat_test.go b/cron/hit_stat_test.go index decb438a6..5b23e80f3 100644 --- a/cron/hit_stat_test.go +++ b/cron/hit_stat_test.go @@ -34,14 +34,14 @@ func TestHitStats(t *testing.T) { t.Helper() var stats goatcounter.HitLists - displayUnique, more, err := stats.List(ctx, + display, more, err := stats.List(ctx, ztime.NewRange(now.Add(-1*time.Hour)).To(now.Add(1*time.Hour)), nil, nil, 10, false) if err != nil { t.Fatal(err) } - gotT := fmt.Sprintf("%d %t", displayUnique, more) + gotT := fmt.Sprintf("%d %t", display, more) if wantT != gotT { t.Fatalf("wrong totals\nhave: %s\nwant: %s", gotT, wantT) } @@ -59,7 +59,7 @@ func TestHitStats(t *testing.T) { } check("1 false", `{ - "count_unique": 1, + "count": 1, "path_id": 1, "path": "/asd", "event": false, @@ -67,12 +67,12 @@ func TestHitStats(t *testing.T) { "max": 1, "stats": [{ "day": "2019-08-31", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0], - "daily_unique": 1 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0], + "daily": 1 }]} `, `{ - "count_unique": 0, + "count": 0, "path_id": 2, "path": "/zxc", "event": false, @@ -80,8 +80,8 @@ func TestHitStats(t *testing.T) { "max": 0, "stats": [{ "day": "2019-08-31", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 0 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "daily": 0 }]}`, ) @@ -91,7 +91,7 @@ func TestHitStats(t *testing.T) { }...) check("2 false", `{ - "count_unique": 2, + "count": 2, "path_id": 1, "path": "/asd", "event": false, @@ -99,11 +99,11 @@ func TestHitStats(t *testing.T) { "max": 1, "stats":[{ "day": "2019-08-31", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0], - "daily_unique": 2 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0], + "daily": 2 }]}`, `{ - "count_unique": 0, + "count": 0, "path_id": 2, "path": "/zxc", "event": false, @@ -111,8 +111,8 @@ func TestHitStats(t *testing.T) { "max": 0, "stats":[{ "day": "2019-08-31", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 0 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "daily": 0 }]}`, ) } diff --git a/cron/language_stat.go b/cron/language_stat.go index 27e20e182..6f675ee0c 100644 --- a/cron/language_stat.go +++ b/cron/language_stat.go @@ -17,10 +17,10 @@ import ( func updateLanguageStats(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { type gt struct { - countUnique int - day string - language string - pathID int64 + count int + day string + language string + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -31,30 +31,30 @@ func updateLanguageStats(ctx context.Context, hits []goatcounter.Hit) error { day := h.CreatedAt.Format("2006-01-02") k := day + ztype.Deref(h.Language, "") + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if v.countUnique == 0 { + if v.count == 0 { v.day = day v.language = ztype.Deref(h.Language, "") v.pathID = h.PathID } if h.FirstVisit { - v.countUnique += 1 + v.count += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID - ins := zdb.NewBulkInsert(ctx, "language_stats", []string{"site_id", "day", "path_id", "language", "count_unique"}) + ins := zdb.NewBulkInsert(ctx, "language_stats", []string{"site_id", "day", "path_id", "language", "count"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "language_stats#site_id#path_id#day#language" do update set - count_unique = language_stats.count_unique + excluded.count_unique`) + count = language_stats.count + excluded.count`) } else { ins.OnConflict(`on conflict(site_id, path_id, day, language) do update set - count_unique = language_stats.count_unique + excluded.count_unique`) + count = language_stats.count + excluded.count`) } for _, v := range grouped { - ins.Values(siteID, v.day, v.pathID, v.language, v.countUnique) + ins.Values(siteID, v.day, v.pathID, v.language, v.count) } return ins.Finish() }), "cron.updateLanguageStats") diff --git a/cron/location_stat.go b/cron/location_stat.go index 834d8f6b6..8f751bff0 100644 --- a/cron/location_stat.go +++ b/cron/location_stat.go @@ -16,10 +16,10 @@ import ( func updateLocationStats(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { type gt struct { - countUnique int - day string - location string - pathID int64 + count int + day string + location string + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -30,7 +30,7 @@ func updateLocationStats(ctx context.Context, hits []goatcounter.Hit) error { day := h.CreatedAt.Format("2006-01-02") k := day + h.Location + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if v.countUnique == 0 { + if v.count == 0 { v.day = day v.location = h.Location v.pathID = h.PathID @@ -43,24 +43,24 @@ func updateLocationStats(ctx context.Context, hits []goatcounter.Hit) error { (&goatcounter.Location{}).ByCode(ctx, h.Location) if h.FirstVisit { - v.countUnique += 1 + v.count += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID ins := zdb.NewBulkInsert(ctx, "location_stats", []string{"site_id", "day", - "path_id", "location", "count_unique"}) + "path_id", "location", "count"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "location_stats#site_id#path_id#day#location" do update set - count_unique = location_stats.count_unique + excluded.count_unique`) + count = location_stats.count + excluded.count`) } else { ins.OnConflict(`on conflict(site_id, path_id, day, location) do update set - count_unique = location_stats.count_unique + excluded.count_unique`) + count = location_stats.count + excluded.count`) } for _, v := range grouped { - ins.Values(siteID, v.day, v.pathID, v.location, v.countUnique) + ins.Values(siteID, v.day, v.pathID, v.location, v.count) } return ins.Finish() }), "cron.updateLocationStats") diff --git a/cron/ref_count.go b/cron/ref_count.go index 5ddf8f186..c9b42f896 100644 --- a/cron/ref_count.go +++ b/cron/ref_count.go @@ -17,11 +17,11 @@ func updateRefCounts(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { // Group by day + pathID + ref. type gt struct { - totalUnique int - hour string - pathID int64 - ref string - refScheme *string + total int + hour string + pathID int64 + ref string + refScheme *string } grouped := map[string]gt{} for _, h := range hits { @@ -32,7 +32,7 @@ func updateRefCounts(ctx context.Context, hits []goatcounter.Hit) error { hour := h.CreatedAt.Format("2006-01-02 15:00:00") k := hour + strconv.FormatInt(h.PathID, 10) + h.Ref v := grouped[k] - if v.totalUnique == 0 { + if v.total == 0 { v.hour = hour v.pathID = h.PathID v.ref = h.Ref @@ -40,24 +40,24 @@ func updateRefCounts(ctx context.Context, hits []goatcounter.Hit) error { } if h.FirstVisit { - v.totalUnique += 1 + v.total += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID ins := zdb.NewBulkInsert(ctx, "ref_counts", []string{"site_id", "path_id", - "ref", "hour", "total_unique", "ref_scheme"}) + "ref", "hour", "total", "ref_scheme"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "ref_counts#site_id#path_id#ref#hour" do update set - total_unique = ref_counts.total_unique + excluded.total_unique`) + total = ref_counts.total + excluded.total`) } else { ins.OnConflict(`on conflict(site_id, path_id, ref, hour) do update set - total_unique = ref_counts.total_unique + excluded.total_unique`) + total = ref_counts.total + excluded.total`) } for _, v := range grouped { - ins.Values(siteID, v.pathID, v.ref, v.hour, v.totalUnique, v.refScheme) + ins.Values(siteID, v.pathID, v.ref, v.hour, v.total, v.refScheme) } return ins.Finish() }), "cron.updateRefCounts") diff --git a/cron/size_stat.go b/cron/size_stat.go index 8811a3ffd..6f6ada7e4 100644 --- a/cron/size_stat.go +++ b/cron/size_stat.go @@ -16,10 +16,10 @@ import ( func updateSizeStats(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { type gt struct { - countUnique int - day string - width int - pathID int64 + count int + day string + width int + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -35,31 +35,31 @@ func updateSizeStats(ctx context.Context, hits []goatcounter.Hit) error { day := h.CreatedAt.Format("2006-01-02") k := day + strconv.Itoa(width) + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if v.countUnique == 0 { + if v.count == 0 { v.day = day v.width = width v.pathID = h.PathID } if h.FirstVisit { - v.countUnique += 1 + v.count += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID ins := zdb.NewBulkInsert(ctx, "size_stats", []string{"site_id", "day", - "path_id", "width", "count_unique"}) + "path_id", "width", "count"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "size_stats#site_id#path_id#day#width" do update set - count_unique = size_stats.count_unique + excluded.count_unique`) + count = size_stats.count + excluded.count`) } else { ins.OnConflict(`on conflict(site_id, path_id, day, width) do update set - count_unique = size_stats.count_unique + excluded.count_unique`) + count = size_stats.count + excluded.count`) } for _, v := range grouped { - ins.Values(siteID, v.day, v.pathID, v.width, v.countUnique) + ins.Values(siteID, v.day, v.pathID, v.width, v.count) } return ins.Finish() }), "cron.updateSizeStats") diff --git a/cron/system_stat.go b/cron/system_stat.go index 3a204a5b4..b79dd27c5 100644 --- a/cron/system_stat.go +++ b/cron/system_stat.go @@ -16,10 +16,10 @@ import ( func updateSystemStats(ctx context.Context, hits []goatcounter.Hit) error { return errors.Wrap(zdb.TX(ctx, func(ctx context.Context) error { type gt struct { - countUnique int - day string - systemID int64 - pathID int64 + count int + day string + systemID int64 + pathID int64 } grouped := map[string]gt{} for _, h := range hits { @@ -37,31 +37,31 @@ func updateSystemStats(ctx context.Context, hits []goatcounter.Hit) error { day := h.CreatedAt.Format("2006-01-02") k := day + strconv.FormatInt(h.SystemID, 10) + strconv.FormatInt(h.PathID, 10) v := grouped[k] - if v.countUnique == 0 { + if v.count == 0 { v.day = day v.systemID = h.SystemID v.pathID = h.PathID } if h.FirstVisit { - v.countUnique += 1 + v.count += 1 } grouped[k] = v } siteID := goatcounter.MustGetSite(ctx).ID ins := zdb.NewBulkInsert(ctx, "system_stats", []string{"site_id", "day", - "path_id", "system_id", "count_unique"}) + "path_id", "system_id", "count"}) if zdb.SQLDialect(ctx) == zdb.DialectPostgreSQL { ins.OnConflict(`on conflict on constraint "system_stats#site_id#path_id#day#system_id" do update set - count_unique = system_stats.count_unique + excluded.count_unique`) + count = system_stats.count + excluded.count`) } else { ins.OnConflict(`on conflict(site_id, path_id, day, system_id) do update set - count_unique = system_stats.count_unique + excluded.count_unique`) + count = system_stats.count + excluded.count`) } for _, v := range grouped { - ins.Values(siteID, v.day, v.pathID, v.systemID, v.countUnique) + ins.Values(siteID, v.day, v.pathID, v.systemID, v.count) } return ins.Finish() }), "cron.updateSystemStats") diff --git a/cron/tasks_test.go b/cron/tasks_test.go index 4825d3b48..fe70191c7 100644 --- a/cron/tasks_test.go +++ b/cron/tasks_test.go @@ -51,14 +51,14 @@ func TestDataRetention(t *testing.T) { } var stats goatcounter.HitLists - displayUnique, more, err := stats.List(ctx, + display, more, err := stats.List(ctx, ztime.NewRange(past.Add(-1*24*time.Hour)).To(now), nil, nil, 10, false) if err != nil { t.Fatal(err) } - out := fmt.Sprintf("%d %t %v", displayUnique, more, err) + out := fmt.Sprintf("%d %t %v", display, more, err) want := `1 false ` if out != want { t.Errorf("\ngot: %s\nwant: %s", out, want) diff --git a/db/migrate/2022-11-03-2-ununique.sql b/db/migrate/2022-11-03-2-ununique.sql new file mode 100644 index 000000000..11ed3bb27 --- /dev/null +++ b/db/migrate/2022-11-03-2-ununique.sql @@ -0,0 +1,9 @@ +alter table hit_counts rename column total_unique to total; +alter table ref_counts rename column total_unique to total; +alter table hit_stats rename column stats_unique to stats; +alter table browser_stats rename column count_unique to count; +alter table system_stats rename column count_unique to count; +alter table location_stats rename column count_unique to count; +alter table size_stats rename column count_unique to count; +alter table language_stats rename column count_unique to count; +alter table campaign_stats rename column count_unique to count; diff --git a/db/query/hit_list.DiffTotal.sql b/db/query/hit_list.DiffTotal.sql index 0fcf36a26..8d4875140 100644 --- a/db/query/hit_list.DiffTotal.sql +++ b/db/query/hit_list.DiffTotal.sql @@ -1,7 +1,7 @@ with prev as ( select path_id, - sum(total_unique) as total + sum(total) as total from hit_counts where site_id = :site and path_id in (:paths) and @@ -11,7 +11,7 @@ with prev as ( cur as ( select path_id, - sum(c.total_unique) as total + sum(c.total) as total from hit_counts c where site_id = :site and path_id in (:paths) and diff --git a/db/query/hit_list.GetTotalCount.sql b/db/query/hit_list.GetTotalCount.sql index 12e553966..7d2b717a0 100644 --- a/db/query/hit_list.GetTotalCount.sql +++ b/db/query/hit_list.GetTotalCount.sql @@ -1,13 +1,13 @@ with x as ( select - coalesce(sum(total_unique), 0) as total_unique + coalesce(sum(total), 0) as total from hit_counts where site_id = :site and hour >= :start and hour <= :end {{:filter and path_id in (:filter)}} ), y as ( select - coalesce(sum(total_unique), 0) as total_events_unique + coalesce(sum(total), 0) as total_events from hit_counts join paths using (site_id, path_id) where @@ -15,7 +15,7 @@ with x as ( {{:filter and path_id in (:filter)}} ), z as ( select - coalesce(sum(total_unique), 0) as total_unique_utc + coalesce(sum(total), 0) as total_utc from hit_counts where site_id = :site and hour >= :start_utc and hour <= :end_utc @@ -28,12 +28,12 @@ select -- Get the UTC offset for the browser, screen size, etc. charts, which are -- always stored in UTC. Instead of calculating everything again, substract the -- pageviews outside of the UTC range, which is a lot faster. - -- x.total_unique - ( - -- select coalesce(sum(total_unique), 0) + -- x.total - ( + -- select coalesce(sum(total), 0) -- from hit_counts -- where site_id = :site and -- {{:filter path_id in (:filter) and}} -- (hour >= :start and hour <= cast(:start as timestamp) + :tz * interval '1 minute') or -- (hour >= :end and hour <= cast(:end as timestamp) + :tz * interval '1 minute') - -- ) as total_unique_utc + -- ) as total_utc from x, y, z; diff --git a/db/query/hit_list.ListPathsLike.gotxt b/db/query/hit_list.ListPathsLike.gotxt index 8b12256a5..e76c656f0 100644 --- a/db/query/hit_list.ListPathsLike.gotxt +++ b/db/query/hit_list.ListPathsLike.gotxt @@ -12,9 +12,9 @@ with x as ( ) select path_id, path, title, - sum(total_unique) as count_unique + sum(total) as count from hit_counts join x using(path_id) where site_id = :site group by path_id, path, title -order by count_unique desc +order by count desc diff --git a/db/query/hit_list.PathCount.sql b/db/query/hit_list.PathCount.sql index 00ef417a7..9bcc7fc20 100644 --- a/db/query/hit_list.PathCount.sql +++ b/db/query/hit_list.PathCount.sql @@ -4,7 +4,7 @@ with x as ( ) select x.path, - coalesce(sum(total_unique), 0) as count_unique + coalesce(sum(total), 0) as count from hit_counts join x using (path_id) where diff --git a/db/query/hit_list.Totals.sql b/db/query/hit_list.Totals.sql index bdc4173d9..2b4b56b55 100644 --- a/db/query/hit_list.Totals.sql +++ b/db/query/hit_list.Totals.sql @@ -1,6 +1,6 @@ select hour, - sum(total_unique) as total_unique + sum(total) as total from hit_counts {{:no_events join paths using (path_id)}} where diff --git a/db/query/hit_stats.ByRef.sql b/db/query/hit_stats.ByRef.sql index a6bb5db1e..b6ddce946 100644 --- a/db/query/hit_stats.ByRef.sql +++ b/db/query/hit_stats.ByRef.sql @@ -1,18 +1,18 @@ with x as ( select path_id, - coalesce(sum(total_unique), 0) as count_unique + coalesce(sum(total), 0) as count from ref_counts where site_id = :site and hour >= :start and hour <= :end and {{:filter path_id in (:filter) and}} ref = :ref group by path_id - order by count_unique desc + order by count desc limit :limit offset :offset ) select paths.path as name, - x.count_unique + x.count from x join paths using(path_id) diff --git a/db/query/hit_stats.ListBrowser.sql b/db/query/hit_stats.ListBrowser.sql index b721c997a..373793789 100644 --- a/db/query/hit_stats.ListBrowser.sql +++ b/db/query/hit_stats.ListBrowser.sql @@ -1,6 +1,6 @@ select trim(name || ' ' || version) as name, - sum(count_unique) as count_unique + sum(count) as count from browser_stats join browsers using (browser_id) where @@ -8,5 +8,5 @@ where {{:filter path_id in (:filter) and}} lower(name) = lower(:browser) group by name, version -order by count_unique desc, name asc +order by count desc, name asc limit :limit offset :offset diff --git a/db/query/hit_stats.ListBrowsers.sql b/db/query/hit_stats.ListBrowsers.sql index b78046beb..c05b0f58c 100644 --- a/db/query/hit_stats.ListBrowsers.sql +++ b/db/query/hit_stats.ListBrowsers.sql @@ -1,19 +1,19 @@ with x as ( select browser_id, - sum(count_unique) as count_unique + sum(count) as count from browser_stats where site_id = :site and day >= :start and day <= :end {{:filter and path_id in (:filter)}} group by browser_id - order by count_unique desc + order by count desc ) select browsers.name, - sum(x.count_unique) as count_unique + sum(x.count) as count from x join browsers using (browser_id) group by browsers.name -order by count_unique desc +order by count desc limit :limit offset :offset diff --git a/db/query/hit_stats.ListCampaign.sql b/db/query/hit_stats.ListCampaign.sql index cb65acab7..76413772e 100644 --- a/db/query/hit_stats.ListCampaign.sql +++ b/db/query/hit_stats.ListCampaign.sql @@ -1,6 +1,6 @@ select ref as name, - sum(count_unique) as count_unique + sum(count) as count from campaign_stats join campaigns using (campaign_id) where @@ -8,5 +8,5 @@ where {{:filter path_id in (:filter) and}} campaign_id = :campaign group by campaign_id, ref -order by count_unique desc, ref asc +order by count desc, ref asc limit :limit offset :offset diff --git a/db/query/hit_stats.ListCampaigns.sql b/db/query/hit_stats.ListCampaigns.sql index f26f9d050..3934fec6a 100644 --- a/db/query/hit_stats.ListCampaigns.sql +++ b/db/query/hit_stats.ListCampaigns.sql @@ -1,19 +1,19 @@ with x as ( select campaign_id, - sum(count_unique) as count_unique + sum(count) as count from campaign_stats where site_id = :site and day >= :start and day <= :end {{:filter and path_id in (:filter)}} group by campaign_id - order by count_unique desc, campaign_id + order by count desc, campaign_id limit :limit offset :offset ) select campaign_id as id, campaigns.name as name, - x.count_unique as count_unique + x.count as count from x join campaigns using (campaign_id) -order by count_unique desc, name asc +order by count desc, name asc diff --git a/db/query/hit_stats.ListLanguages.sql b/db/query/hit_stats.ListLanguages.sql index 3573dfa50..8478b7caf 100644 --- a/db/query/hit_stats.ListLanguages.sql +++ b/db/query/hit_stats.ListLanguages.sql @@ -1,19 +1,19 @@ with x as ( select language, - sum(count_unique) as count_unique + sum(count) as count from language_stats where site_id = :site and day >= :start and day <= :end {{:filter and path_id in (:filter)}} group by language - order by count_unique desc, language + order by count desc, language limit :limit offset :offset ) select languages.iso_639_3 as id, languages.name as name, - x.count_unique as count_unique + x.count as count from x join languages on languages.iso_639_3 = x.language -order by count_unique desc, name asc +order by count desc, name asc diff --git a/db/query/hit_stats.ListLocation.sql b/db/query/hit_stats.ListLocation.sql index 9c6f5eddd..4cf743efc 100644 --- a/db/query/hit_stats.ListLocation.sql +++ b/db/query/hit_stats.ListLocation.sql @@ -1,6 +1,6 @@ select coalesce(region_name, '(unknown)') as name, - sum(count_unique) as count_unique + sum(count) as count from location_stats join locations on location = iso_3166_2 where @@ -8,5 +8,5 @@ where {{:filter path_id in (:filter) and}} country = :country group by iso_3166_2, name -order by count_unique desc, name asc +order by count desc, name asc limit :limit offset :offset diff --git a/db/query/hit_stats.ListLocations.sql b/db/query/hit_stats.ListLocations.sql index c3c15cf61..cee3c1063 100644 --- a/db/query/hit_stats.ListLocations.sql +++ b/db/query/hit_stats.ListLocations.sql @@ -1,19 +1,19 @@ with x as ( select substr(location, 0, 3) as loc, - sum(count_unique) as count_unique + sum(count) as count from location_stats where site_id = :site and day >= :start and day <= :end {{:filter and path_id in (:filter)}} group by loc - order by count_unique desc, loc + order by count desc, loc limit :limit offset :offset ) select locations.iso_3166_2 as id, locations.country_name as name, - x.count_unique as count_unique + x.count as count from x join locations on locations.iso_3166_2 = x.loc -order by count_unique desc, name asc +order by count desc, name asc diff --git a/db/query/hit_stats.ListSize.sql b/db/query/hit_stats.ListSize.sql index 2f569d9b8..ce810fd57 100644 --- a/db/query/hit_stats.ListSize.sql +++ b/db/query/hit_stats.ListSize.sql @@ -1,6 +1,6 @@ select '↔ ' || width || 'px' as name, - sum(count_unique) as count_unique + sum(count) as count from size_stats where site_id = :site and day >= :start and day <= :end @@ -8,5 +8,5 @@ where {{:max_size and width != 0 and width > :min_size and width <= :max_size}} {{:empty and width = 0}} group by width -order by count_unique desc, name asc +order by count desc, name asc limit :limit offset :offset diff --git a/db/query/hit_stats.ListSizes.sql b/db/query/hit_stats.ListSizes.sql index fe94e8ef7..59d8e8c7f 100644 --- a/db/query/hit_stats.ListSizes.sql +++ b/db/query/hit_stats.ListSizes.sql @@ -1,9 +1,9 @@ select width as name, - sum(count_unique) as count_unique + sum(count) as count from size_stats where site_id = :site and day >= :start and day <= :end {{:filter and path_id in (:filter)}} group by width -order by count_unique desc, name asc +order by count desc, name asc diff --git a/db/query/hit_stats.ListSystem.sql b/db/query/hit_stats.ListSystem.sql index 5cfda0dea..43c0587a8 100644 --- a/db/query/hit_stats.ListSystem.sql +++ b/db/query/hit_stats.ListSystem.sql @@ -1,6 +1,6 @@ select trim(name || ' ' || version) as name, - sum(count_unique) as count_unique + sum(count) as count from system_stats join systems using (system_id) where @@ -8,5 +8,5 @@ where {{:filter path_id in (:filter) and}} lower(name) = lower(:system) group by name, version -order by count_unique desc, name asc +order by count desc, name asc limit :limit offset :offset diff --git a/db/query/hit_stats.ListSystems.sql b/db/query/hit_stats.ListSystems.sql index ecc37f3bf..3d7d3a5d3 100644 --- a/db/query/hit_stats.ListSystems.sql +++ b/db/query/hit_stats.ListSystems.sql @@ -1,19 +1,19 @@ with x as ( select system_id, - sum(count_unique) as count_unique + sum(count) as count from system_stats where site_id = :site and day >= :start and day <= :end {{:filter and path_id in (:filter)}} group by system_id - order by count_unique desc + order by count desc ) select systems.name, - sum(x.count_unique) as count_unique + sum(x.count) as count from x join systems using (system_id) group by systems.name -order by count_unique desc +order by count desc limit :limit offset :offset diff --git a/db/query/ref.ListRefsByPath.sql b/db/query/ref.ListRefsByPath.sql index ad90687eb..e5201da5c 100644 --- a/db/query/ref.ListRefsByPath.sql +++ b/db/query/ref.ListRefsByPath.sql @@ -3,7 +3,7 @@ with x as ( where site_id = :site and lower(path) = lower(:path) ) select - coalesce(sum(total_unique), 0) as count_unique, + coalesce(sum(total), 0) as count, max(ref_scheme) as ref_scheme, ref as name from ref_counts @@ -11,5 +11,5 @@ join x using (path_id) where site_id = :site and hour >= :start and hour <= :end group by ref -order by count_unique desc, ref desc +order by count desc, ref desc limit :limit offset :offset diff --git a/db/query/ref.ListRefsByPathID.sql b/db/query/ref.ListRefsByPathID.sql index e29613a10..b8b61abcb 100644 --- a/db/query/ref.ListRefsByPathID.sql +++ b/db/query/ref.ListRefsByPathID.sql @@ -1,5 +1,5 @@ select - coalesce(sum(total_unique), 0) as count_unique, + coalesce(sum(total), 0) as count, max(ref_scheme) as ref_scheme, ref as name from ref_counts @@ -8,6 +8,6 @@ where path_id = :path and hour >= :start and hour <= :end group by ref -order by count_unique desc, ref desc +order by count desc, ref desc limit :limit offset :offset diff --git a/db/query/ref.ListTopRefs.sql b/db/query/ref.ListTopRefs.sql index aeb01bbf0..8efe38487 100644 --- a/db/query/ref.ListTopRefs.sql +++ b/db/query/ref.ListTopRefs.sql @@ -1,5 +1,5 @@ select - coalesce(sum(total_unique), 0) as count_unique, + coalesce(sum(total), 0) as count, max(ref_scheme) as ref_scheme, ref as name from ref_counts @@ -8,5 +8,5 @@ where {{:filter and path_id in (:filter)}} {{:has_domain and ref not like :ref}} group by ref -order by count_unique desc, ref +order by count desc, ref limit :limit offset :offset diff --git a/handlers/api.go b/handlers/api.go index 9514d9083..acf619471 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -846,7 +846,7 @@ type ( Hits goatcounter.HitLists `json:"hits"` // Total number of visitors in the returned result. - TotalUnique int `json:"total_unique"` + Total int `json:"total"` // More hits after this? More bool `json:"more"` @@ -892,9 +892,9 @@ func (h api) hits(w http.ResponseWriter, r *http.Request) error { } return zhttp.JSON(w, apiHitsResponse{ - TotalUnique: tdu, - Hits: pages, - More: more, + Total: tdu, + Hits: pages, + More: more, }) } diff --git a/handlers/api_test.go b/handlers/api_test.go index 682253343..d8c9db188 100644 --- a/handlers/api_test.go +++ b/handlers/api_test.go @@ -697,131 +697,131 @@ func TestAPIHits(t *testing.T) { setup func(context.Context, *testing.T) want string }{ - {"no hits", "", 200, nil, `{"more": false, "total_unique": 0, "hits": []}`}, + {"no hits", "", 200, nil, `{"more": false, "total": 0, "hits": []}`}, {"works", "limit=3", 200, func(ctx context.Context, t *testing.T) { many(ctx, t) }, `{ "more": true, - "total_unique": 3, + "total": 3, "hits": [{ - "count_unique": 1, + "count": 1, "event": false, "max": 1, "path": "/50", "path_id": 50, "title": "title - 50", "stats": [{ - "daily_unique": 0, + "daily": 0, "day": "2020-06-11", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-12", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-13", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-14", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-15", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-16", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-17", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 1, + "daily": 1, "day": "2020-06-18", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }] }, { - "count_unique": 1, + "count": 1, "event": false, "max": 1, "path": "/49", "path_id": 49, "title": "title - 49", "stats": [{ - "daily_unique": 0, + "daily": 0, "day": "2020-06-11", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-12", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-13", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-14", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-15", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-16", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-17", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 1, + "daily": 1, "day": "2020-06-18", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }] }, { - "count_unique": 1, + "count": 1, "event": false, "max": 1, "path": "/48", "path_id": 48, "title": "title - 48", "stats": [{ - "daily_unique": 0, + "daily": 0, "day": "2020-06-11", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-12", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-13", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-14", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-15", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-16", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-17", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 1, + "daily": 1, "day": "2020-06-18", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }] }] }`}, @@ -829,26 +829,26 @@ func TestAPIHits(t *testing.T) { {"exclude", "limit=1&exclude_paths=50,49&daily=true&start=2020-06-17&end=2020-06-19", 200, func(ctx context.Context, t *testing.T) { many(ctx, t) }, `{ "more": true, - "total_unique": 1, + "total": 1, "hits": [{ - "count_unique": 1, + "count": 1, "event": false, "max": 1, "path": "/48", "path_id": 48, "title": "title - 48", "stats": [{ - "daily_unique": 0, + "daily": 0, "day": "2020-06-17", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 1, + "daily": 1, "day": "2020-06-18", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-19", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }] }] }`}, @@ -856,26 +856,26 @@ func TestAPIHits(t *testing.T) { {"include", "limit=1&exclude_paths=&include_paths=10&daily=true&start=2020-06-17&end=2020-06-19", 200, func(ctx context.Context, t *testing.T) { many(ctx, t) }, `{ "more": false, - "total_unique": 1, + "total": 1, "hits": [{ - "count_unique": 1, + "count": 1, "event": false, "max": 1, "path": "/10", "path_id": 10, "title": "title - 10", "stats": [{ - "daily_unique": 0, + "daily": 0, "day": "2020-06-17", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 1, + "daily": 1, "day": "2020-06-18", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, { - "daily_unique": 0, + "daily": 0, "day": "2020-06-19", - "hourly_unique": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + "hourly": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }] }] }`}, @@ -938,8 +938,8 @@ func TestAPIStats(t *testing.T) { `{ "more": false, "stats": [ - {"count_unique": 35, "id": "Firefox", "name": "Firefox"}, - {"count_unique": 15, "id": "Chrome", "name": "Chrome"} + {"count": 35, "id": "Firefox", "name": "Firefox"}, + {"count": 15, "id": "Chrome", "name": "Chrome"} ] }`}, } @@ -1001,9 +1001,9 @@ func TestAPIStatsDetail(t *testing.T) { `{ "more": true, "stats": [ - {"count_unique": 1, "name": "Firefox 0"}, - {"count_unique": 1, "name": "Firefox 1"}, - {"count_unique": 1, "name": "Firefox 10"} + {"count": 1, "name": "Firefox 0"}, + {"count": 1, "name": "Firefox 1"}, + {"count": 1, "name": "Firefox 10"} ] }`}, } diff --git a/handlers/backend_test.go b/handlers/backend_test.go index 900085e44..e6d02c55c 100644 --- a/handlers/backend_test.go +++ b/handlers/backend_test.go @@ -120,7 +120,7 @@ func TestBackendPagesMore(t *testing.T) { wantJSON := `{ "max": 10, "more": false, - "total_unique_display": 5 + "total_display": 5 }` if d := ztest.Diff(haveHTML, wantHTML, ztest.DiffNormalizeWhitespace); d != "" { diff --git a/handlers/dashboard.go b/handlers/dashboard.go index 192599bf7..08b47436b 100644 --- a/handlers/dashboard.go +++ b/handlers/dashboard.go @@ -191,7 +191,7 @@ func (h backend) dashboard(w http.ResponseWriter, r *http.Request) error { // Set shared params. tc := wid.GetOne("totalcount").(*widgets.TotalCount) - shared.TotalUnique, shared.TotalUniqueUTC, shared.TotalEventsUnique = tc.TotalUnique, tc.TotalUniqueUTC, tc.TotalEventsUnique + shared.Total, shared.TotalUTC, shared.TotalEvents = tc.Total, tc.TotalUTC, tc.TotalEvents // Render widget templates. func() { @@ -269,19 +269,19 @@ func (h backend) dashboard(w http.ResponseWriter, r *http.Request) error { return zhttp.Template(w, "dashboard.gohtml", struct { Globals - CountDomain string - SubSites []string - ShowRefs string - Period ztime.Range - PathFilter []int64 - ForcedDaily bool - Widgets widgets.List - View goatcounter.View - TotalUnique int - TotalUniqueUTC int - ConnectID zint.Uint128 + CountDomain string + SubSites []string + ShowRefs string + Period ztime.Range + PathFilter []int64 + ForcedDaily bool + Widgets widgets.List + View goatcounter.View + Total int + TotalUTC int + ConnectID zint.Uint128 }{newGlobals(w, r), cd, subs, showRefs, rng, - args.PathFilter, forcedDaily, wid, view, shared.TotalUnique, shared.TotalUniqueUTC, + args.PathFilter, forcedDaily, wid, view, shared.Total, shared.TotalUTC, connectID}) } @@ -305,11 +305,11 @@ func (h backend) loadWidget(w http.ResponseWriter, r *http.Request) error { } args := widgets.SharedData{ - Site: Site(r.Context()), - User: User(r.Context()), - TotalUniqueUTC: total, - TotalUnique: total, - RowsOnly: key != "" || offset > 0, + Site: Site(r.Context()), + User: User(r.Context()), + TotalUTC: total, + Total: total, + RowsOnly: key != "" || offset > 0, Args: widgets.Args{ Rng: rng, PathFilter: pathFilter, @@ -357,7 +357,7 @@ func (h backend) loadWidget(w http.ResponseWriter, r *http.Request) error { switch wid.Name() { case "pages": p := wid.(*widgets.Pages) - ret["total_unique_display"] = p.UniqueDisplay + ret["total_display"] = p.Display ret["max"] = p.Max } diff --git a/handlers/vcounter.go b/handlers/vcounter.go index 357a7fac3..ef28f4445 100644 --- a/handlers/vcounter.go +++ b/handlers/vcounter.go @@ -148,7 +148,7 @@ func (h vcounter) counter(w http.ResponseWriter, r *http.Request) error { if zdb.ErrNoRows(err) { w.WriteHeader(404) } - count := tplfunc.Number(hl.CountUnique, site.UserDefaults.NumberFormat) + count := tplfunc.Number(hl.Count, site.UserDefaults.NumberFormat) switch ext { default: diff --git a/helper.go b/helper.go index b0cbdd7a6..5ee1a37f5 100644 --- a/helper.go +++ b/helper.go @@ -85,7 +85,7 @@ func ChunkStat(stats []HitListStat) (int, []int) { n = 0 ) for _, stat := range stats { - for _, h := range stat.HourlyUnique { + for _, h := range stat.Hourly { i++ chunk += h if i == chunkSize { diff --git a/hit_list.go b/hit_list.go index be6368d6a..362e98d85 100644 --- a/hit_list.go +++ b/hit_list.go @@ -20,7 +20,7 @@ import ( type HitList struct { // Number of visitors for the selected date range. - CountUnique int `db:"count_unique" json:"count_unique"` + Count int `db:"count" json:"count"` // Path ID PathID int64 `db:"path_id" json:"path_id"` @@ -51,12 +51,12 @@ type HitList struct { } type HitListStat struct { - Day string `json:"day"` // Day these statistics are for {date}. - HourlyUnique []int `json:"hourly_unique"` // Visitors per hour. - DailyUnique int `json:"daily_unique"` // Total visitors for this day. + Day string `json:"day"` // Day these statistics are for {date}. + Hourly []int `json:"hourly"` // Visitors per hour. + Daily int `json:"daily"` // Total visitors for this day. } -// PathCount gets the total and total_unique for one path. +// PathCount gets the visit count for one path. func (h *HitList) PathCount(ctx context.Context, path string, rng ztime.Range) error { err := zdb.Get(ctx, h, "load:hit_list.PathCount", zdb.P{ "site": MustGetSite(ctx).ID, @@ -67,13 +67,11 @@ func (h *HitList) PathCount(ctx context.Context, path string, rng ztime.Range) e return errors.Wrap(err, "HitList.PathCount") } -// SiteTotal gets the total counts for all paths. -// -// This always uses UTC. +// SiteTotal gets the total counts for all paths. This always uses UTC. func (h *HitList) SiteTotalUTC(ctx context.Context, rng ztime.Range) error { err := zdb.Get(ctx, h, `/* *HitList.SiteTotalUTC */ select - coalesce(sum(total_unique), 0) as count_unique + coalesce(sum(total), 0) as count from hit_counts where site_id = :site {{:start and hour >= :start}} @@ -120,7 +118,7 @@ func (h *HitLists) List( {{:filter path_id in (:filter) and}} hour>=:start and hour<=:end group by path_id - order by sum(total_unique) desc, path_id desc + order by sum(total) desc, path_id desc limit :limit ) select path_id, paths.path, paths.title, paths.event from x @@ -153,9 +151,9 @@ func (h *HitLists) List( // Get stats for every page. hh := *h var st []struct { - PathID int64 `db:"path_id"` - Day time.Time `db:"day"` - StatsUnique []byte `db:"stats_unique"` + PathID int64 `db:"path_id"` + Day time.Time `db:"day"` + Stats []byte `db:"stats"` } { paths := make([]int64, len(hh)) @@ -164,7 +162,7 @@ func (h *HitLists) List( } err := zdb.Select(ctx, &st, `/* HitLists.List */ - select path_id, day, stats_unique + select path_id, day, stats from hit_stats where hit_stats.site_id = :site and @@ -188,10 +186,10 @@ func (h *HitLists) List( for _, s := range st { if s.PathID == hh[i].PathID { var y []int - zjson.MustUnmarshal(s.StatsUnique, &y) + zjson.MustUnmarshal(s.Stats, &y) hh[i].Stats = append(hh[i].Stats, HitListStat{ - Day: s.Day.Format("2006-01-02"), - HourlyUnique: y, + Day: s.Day.Format("2006-01-02"), + Hourly: y, }) } } @@ -205,10 +203,10 @@ func (h *HitLists) List( applyOffset(hh, user.Settings.Timezone) // Add total and max. - var totalUniqueDisplay int - addTotals(hh, daily, &totalUniqueDisplay) + var totalDisplay int + addTotals(hh, daily, &totalDisplay) - return totalUniqueDisplay, more, nil + return totalDisplay, more, nil } // PathTotals is a special path to indicate this is the "total" overview. @@ -222,8 +220,8 @@ func (h *HitList) Totals(ctx context.Context, rng ztime.Range, pathFilter []int6 user := MustGetUser(ctx) var tc []struct { - Hour time.Time `db:"hour"` - TotalUnique int `db:"total_unique"` + Hour time.Time `db:"hour"` + Total int `db:"total"` } err := zdb.Select(ctx, &tc, "load:hit_list.Totals", zdb.P{ "site": site.ID, @@ -247,13 +245,13 @@ func (h *HitList) Totals(ctx context.Context, rng ztime.Range, pathFilter []int6 s, ok := stats[d] if !ok { s = HitListStat{ - Day: d, - HourlyUnique: make([]int, 24), + Day: d, + Hourly: make([]int, 24), } } - s.HourlyUnique[hour] += t.TotalUnique - totalst.CountUnique += t.TotalUnique + s.Hourly[hour] += t.Total + totalst.Count += t.Total stats[d] = s } @@ -262,7 +260,7 @@ func (h *HitList) Totals(ctx context.Context, rng ztime.Range, pathFilter []int6 for _, v := range stats { totalst.Stats = append(totalst.Stats, v) if !daily { - for _, x := range v.HourlyUnique { + for _, x := range v.Hourly { if x > max { max = x } @@ -280,11 +278,11 @@ func (h *HitList) Totals(ctx context.Context, rng ztime.Range, pathFilter []int6 if daily { for i := range hh[0].Stats { - for _, n := range hh[0].Stats[i].HourlyUnique { - hh[0].Stats[i].DailyUnique += n + for _, n := range hh[0].Stats[i].Hourly { + hh[0].Stats[i].Daily += n } - if daily && hh[0].Stats[i].DailyUnique > max { - max = hh[0].Stats[i].DailyUnique + if daily && hh[0].Stats[i].Daily > max { + max = hh[0].Stats[i].Daily } } } @@ -343,10 +341,10 @@ func applyOffset(hh HitLists, tz *tz.Zone) { popped := make([]int, offset) for i := range stats { - stats[i].HourlyUnique = append(popped, stats[i].HourlyUnique...) - o := len(stats[i].HourlyUnique) - offset - popped = stats[i].HourlyUnique[o:] - stats[i].HourlyUnique = stats[i].HourlyUnique[:o] + stats[i].Hourly = append(popped, stats[i].Hourly...) + o := len(stats[i].Hourly) - offset + popped = stats[i].Hourly[o:] + stats[i].Hourly = stats[i].Hourly[:o] } hh[i].Stats = stats[1:] // Overselect a day to get the stats for it, remove it. } @@ -359,9 +357,9 @@ func applyOffset(hh HitLists, tz *tz.Zone) { popped := make([]int, offset) for i := len(stats) - 1; i >= 0; i-- { - stats[i].HourlyUnique = append(stats[i].HourlyUnique, popped...) - popped = stats[i].HourlyUnique[:offset] - stats[i].HourlyUnique = stats[i].HourlyUnique[offset:] + stats[i].Hourly = append(stats[i].Hourly, popped...) + popped = stats[i].Hourly[:offset] + stats[i].Hourly = stats[i].Hourly[offset:] } hh[i].Stats = stats[:len(stats)-1] // Overselect a day to get the stats for it, remove it. } @@ -391,7 +389,7 @@ func fillBlankDays(hh HitLists, rng ztime.Range) { newStat = append(newStat, hh[i].Stats[j]) j++ } else { - newStat = append(newStat, HitListStat{Day: dayFmt, HourlyUnique: allDays}) + newStat = append(newStat, HitListStat{Day: dayFmt, Hourly: allDays}) } if dayFmt == endFmt { break @@ -402,23 +400,23 @@ func fillBlankDays(hh HitLists, rng ztime.Range) { } } -func addTotals(hh HitLists, daily bool, totalUniqueDisplay *int) { +func addTotals(hh HitLists, daily bool, totalDisplay *int) { for i := range hh { for j := range hh[i].Stats { - for k := range hh[i].Stats[j].HourlyUnique { - hh[i].Stats[j].DailyUnique += hh[i].Stats[j].HourlyUnique[k] - if !daily && hh[i].Stats[j].HourlyUnique[k] > hh[i].Max { - hh[i].Max = hh[i].Stats[j].HourlyUnique[k] + for k := range hh[i].Stats[j].Hourly { + hh[i].Stats[j].Daily += hh[i].Stats[j].Hourly[k] + if !daily && hh[i].Stats[j].Hourly[k] > hh[i].Max { + hh[i].Max = hh[i].Stats[j].Hourly[k] } } - hh[i].CountUnique += hh[i].Stats[j].DailyUnique - if daily && hh[i].Stats[j].DailyUnique > hh[i].Max { - hh[i].Max = hh[i].Stats[j].DailyUnique + hh[i].Count += hh[i].Stats[j].Daily + if daily && hh[i].Stats[j].Daily > hh[i].Max { + hh[i].Max = hh[i].Stats[j].Daily } } - *totalUniqueDisplay += hh[i].CountUnique + *totalDisplay += hh[i].Count } // We sort in SQL, but this is not always 100% correct after applying @@ -431,15 +429,15 @@ func addTotals(hh HitLists, daily bool, totalUniqueDisplay *int) { // configured TZ, but that would make changing the TZ expensive, I'm not // 100% sure yet what a good solution here is. For now, this is "good // enough". - sort.Slice(hh, func(i, j int) bool { return hh[i].CountUnique > hh[j].CountUnique }) + sort.Slice(hh, func(i, j int) bool { return hh[i].Count > hh[j].Count }) } type TotalCount struct { - TotalUnique int `db:"total_unique" json:"total_unique"` // Total number of visitors (including events). - TotalEventsUnique int `db:"total_events_unique" json:"total_events_unique"` // Total number of visitors for events. + Total int `db:"total" json:"total"` // Total number of visitors (including events). + TotalEvents int `db:"total_events" json:"total_events"` // Total number of visitors for events. // Total number of visitors in UTC. The browser, system, etc, stats are // always in UTC. - TotalUniqueUTC int `db:"total_unique_utc" json:"total_unique_utc"` + TotalUTC int `db:"total_utc" json:"total_utc"` } // GetTotalCount gets the total number of pageviews for the selected timeview in diff --git a/hit_list_test.go b/hit_list_test.go index a56405d2c..9248de0b4 100644 --- a/hit_list_test.go +++ b/hit_list_test.go @@ -40,25 +40,25 @@ func TestHitListsList(t *testing.T) { }, wantReturn: "3 false ", wantStats: HitLists{ - HitList{CountUnique: 2, Path: "/asd", RefScheme: nil, Stats: []HitListStat{ - {Day: "2019-08-10", HourlyUnique: dayStat(map[int]int{14: 1})}, - {Day: "2019-08-11", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-12", HourlyUnique: dayStat(map[int]int{6: 1})}, - {Day: "2019-08-13", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-14", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-15", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-16", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-17", HourlyUnique: dayStat(nil)}, + HitList{Count: 2, Path: "/asd", RefScheme: nil, Stats: []HitListStat{ + {Day: "2019-08-10", Hourly: dayStat(map[int]int{14: 1})}, + {Day: "2019-08-11", Hourly: dayStat(nil)}, + {Day: "2019-08-12", Hourly: dayStat(map[int]int{6: 1})}, + {Day: "2019-08-13", Hourly: dayStat(nil)}, + {Day: "2019-08-14", Hourly: dayStat(nil)}, + {Day: "2019-08-15", Hourly: dayStat(nil)}, + {Day: "2019-08-16", Hourly: dayStat(nil)}, + {Day: "2019-08-17", Hourly: dayStat(nil)}, }}, - HitList{CountUnique: 1, Path: "/zxc", RefScheme: nil, Stats: []HitListStat{ - {Day: "2019-08-10", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-11", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-12", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-13", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-14", HourlyUnique: dayStat(map[int]int{18: 1})}, - {Day: "2019-08-15", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-16", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-17", HourlyUnique: dayStat(nil)}, + HitList{Count: 1, Path: "/zxc", RefScheme: nil, Stats: []HitListStat{ + {Day: "2019-08-10", Hourly: dayStat(nil)}, + {Day: "2019-08-11", Hourly: dayStat(nil)}, + {Day: "2019-08-12", Hourly: dayStat(nil)}, + {Day: "2019-08-13", Hourly: dayStat(nil)}, + {Day: "2019-08-14", Hourly: dayStat(map[int]int{18: 1})}, + {Day: "2019-08-15", Hourly: dayStat(nil)}, + {Day: "2019-08-16", Hourly: dayStat(nil)}, + {Day: "2019-08-17", Hourly: dayStat(nil)}, }}, }, }, @@ -70,15 +70,15 @@ func TestHitListsList(t *testing.T) { inFilter: "x", wantReturn: "1 false ", wantStats: HitLists{ - HitList{CountUnique: 1, Path: "/zxc", RefScheme: nil, Stats: []HitListStat{ - {Day: "2019-08-10", HourlyUnique: dayStat(map[int]int{14: 1})}, - {Day: "2019-08-11", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-12", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-13", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-14", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-15", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-16", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-17", HourlyUnique: dayStat(nil)}, + HitList{Count: 1, Path: "/zxc", RefScheme: nil, Stats: []HitListStat{ + {Day: "2019-08-10", Hourly: dayStat(map[int]int{14: 1})}, + {Day: "2019-08-11", Hourly: dayStat(nil)}, + {Day: "2019-08-12", Hourly: dayStat(nil)}, + {Day: "2019-08-13", Hourly: dayStat(nil)}, + {Day: "2019-08-14", Hourly: dayStat(nil)}, + {Day: "2019-08-15", Hourly: dayStat(nil)}, + {Day: "2019-08-16", Hourly: dayStat(nil)}, + {Day: "2019-08-17", Hourly: dayStat(nil)}, }}, }, }, @@ -92,25 +92,25 @@ func TestHitListsList(t *testing.T) { inFilter: "a", wantReturn: "2 true ", wantStats: HitLists{ - HitList{CountUnique: 1, Path: "/aaaa", RefScheme: nil, Stats: []HitListStat{ - {Day: "2019-08-10", HourlyUnique: dayStat(map[int]int{14: 1})}, - {Day: "2019-08-11", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-12", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-13", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-14", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-15", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-16", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-17", HourlyUnique: dayStat(nil)}, + HitList{Count: 1, Path: "/aaaa", RefScheme: nil, Stats: []HitListStat{ + {Day: "2019-08-10", Hourly: dayStat(map[int]int{14: 1})}, + {Day: "2019-08-11", Hourly: dayStat(nil)}, + {Day: "2019-08-12", Hourly: dayStat(nil)}, + {Day: "2019-08-13", Hourly: dayStat(nil)}, + {Day: "2019-08-14", Hourly: dayStat(nil)}, + {Day: "2019-08-15", Hourly: dayStat(nil)}, + {Day: "2019-08-16", Hourly: dayStat(nil)}, + {Day: "2019-08-17", Hourly: dayStat(nil)}, }}, - HitList{CountUnique: 1, Path: "/aaa", RefScheme: nil, Stats: []HitListStat{ - {Day: "2019-08-10", HourlyUnique: dayStat(map[int]int{14: 1})}, - {Day: "2019-08-11", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-12", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-13", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-14", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-15", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-16", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-17", HourlyUnique: dayStat(nil)}, + HitList{Count: 1, Path: "/aaa", RefScheme: nil, Stats: []HitListStat{ + {Day: "2019-08-10", Hourly: dayStat(map[int]int{14: 1})}, + {Day: "2019-08-11", Hourly: dayStat(nil)}, + {Day: "2019-08-12", Hourly: dayStat(nil)}, + {Day: "2019-08-13", Hourly: dayStat(nil)}, + {Day: "2019-08-14", Hourly: dayStat(nil)}, + {Day: "2019-08-15", Hourly: dayStat(nil)}, + {Day: "2019-08-16", Hourly: dayStat(nil)}, + {Day: "2019-08-17", Hourly: dayStat(nil)}, }}, }, }, @@ -125,25 +125,25 @@ func TestHitListsList(t *testing.T) { inExclude: []int64{4, 3}, wantReturn: "2 false ", wantStats: HitLists{ - HitList{CountUnique: 1, Path: "/aa", RefScheme: nil, Stats: []HitListStat{ - {Day: "2019-08-10", HourlyUnique: dayStat(map[int]int{14: 1})}, - {Day: "2019-08-11", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-12", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-13", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-14", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-15", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-16", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-17", HourlyUnique: dayStat(nil)}, + HitList{Count: 1, Path: "/aa", RefScheme: nil, Stats: []HitListStat{ + {Day: "2019-08-10", Hourly: dayStat(map[int]int{14: 1})}, + {Day: "2019-08-11", Hourly: dayStat(nil)}, + {Day: "2019-08-12", Hourly: dayStat(nil)}, + {Day: "2019-08-13", Hourly: dayStat(nil)}, + {Day: "2019-08-14", Hourly: dayStat(nil)}, + {Day: "2019-08-15", Hourly: dayStat(nil)}, + {Day: "2019-08-16", Hourly: dayStat(nil)}, + {Day: "2019-08-17", Hourly: dayStat(nil)}, }}, - HitList{CountUnique: 1, Path: "/a", RefScheme: nil, Stats: []HitListStat{ - {Day: "2019-08-10", HourlyUnique: dayStat(map[int]int{14: 1})}, - {Day: "2019-08-11", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-12", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-13", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-14", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-15", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-16", HourlyUnique: dayStat(nil)}, - {Day: "2019-08-17", HourlyUnique: dayStat(nil)}, + HitList{Count: 1, Path: "/a", RefScheme: nil, Stats: []HitListStat{ + {Day: "2019-08-10", Hourly: dayStat(map[int]int{14: 1})}, + {Day: "2019-08-11", Hourly: dayStat(nil)}, + {Day: "2019-08-12", Hourly: dayStat(nil)}, + {Day: "2019-08-13", Hourly: dayStat(nil)}, + {Day: "2019-08-14", Hourly: dayStat(nil)}, + {Day: "2019-08-15", Hourly: dayStat(nil)}, + {Day: "2019-08-16", Hourly: dayStat(nil)}, + {Day: "2019-08-17", Hourly: dayStat(nil)}, }}, }, }, @@ -207,9 +207,9 @@ func TestGetTotalCount(t *testing.T) { } want := `{ - "total_unique": 3, - "total_events_unique": 1, - "total_unique_utc": 3 + "total": 3, + "total_events": 1, + "total_utc": 3 }` if d := ztest.Diff(zjson.MustMarshalString(have), want, ztest.DiffJSON); d != "" { t.Error(d) @@ -241,7 +241,7 @@ func TestHitListTotals(t *testing.T) { want := [][]string{ {`10`, `{ - "count_unique": 2, + "count": 2, "path_id": 0, "path": "TOTAL ", "event": false, @@ -249,12 +249,12 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 0 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], + "daily": 0 }]}`}, {`10`, `{ - "count_unique": 1, + "count": 1, "path_id": 0, "path": "TOTAL ", "event": false, @@ -262,12 +262,12 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 0 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], + "daily": 0 }]}`}, {`10`, `{ - "count_unique": 1, + "count": 1, "path_id": 0, "path": "TOTAL ", "event": false, @@ -275,12 +275,12 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 0 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], + "daily": 0 }]}`}, {`10`, `{ - "count_unique": 2, + "count": 2, "path_id": 0, "path": "TOTAL ", "event": false, @@ -288,8 +288,8 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 0 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], + "daily": 0 }]}`}, } for i, filter := range [][]int64{nil, []int64{1}, []int64{2}, []int64{1, 2}} { @@ -315,7 +315,7 @@ func TestHitListTotals(t *testing.T) { want := [][]string{ {`10`, `{ - "count_unique": 2, + "count": 2, "path_id": 0, "path": "TOTAL ", "event": false, @@ -323,12 +323,12 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 2 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], + "daily": 2 }]}`}, {`10`, `{ - "count_unique": 1, + "count": 1, "path_id": 0, "path": "TOTAL ", "event": false, @@ -336,12 +336,12 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 1 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], + "daily": 1 }]}`}, {`10`, `{ - "count_unique": 1, + "count": 1, "path_id": 0, "path": "TOTAL ", "event": false, @@ -349,12 +349,12 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 1 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], + "daily": 1 }]}`}, {`10`, `{ - "count_unique": 2, + "count": 2, "path_id": 0, "path": "TOTAL ", "event": false, @@ -362,8 +362,8 @@ func TestHitListTotals(t *testing.T) { "max": 0, "stats":[{ "day": "2020-06-18", - "hourly_unique": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], - "daily_unique": 2 + "hourly": [0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0], + "daily": 2 }]}`}, } @@ -410,7 +410,7 @@ func TestHitListsPathCount(t *testing.T) { } want := `{ - "count_unique": 5, + "count": 5, "event": false, "max": 0, "path": "/", @@ -433,7 +433,7 @@ func TestHitListsPathCount(t *testing.T) { } want := `{ - "count_unique": 2, + "count": 2, "event": false, "max": 0, "path": "/", @@ -471,7 +471,7 @@ func TestHitListSiteTotalUnique(t *testing.T) { } want := `{ - "count_unique": 7, + "count": 7, "event": false, "max": 0, "path": "", @@ -494,7 +494,7 @@ func TestHitListSiteTotalUnique(t *testing.T) { } want := `{ - "count_unique": 3, + "count": 3, "event": false, "max": 0, "path": "", diff --git a/hit_stats.go b/hit_stats.go index f2eb0169b..06c44c5f0 100644 --- a/hit_stats.go +++ b/hit_stats.go @@ -17,9 +17,9 @@ import ( type HitStat struct { // ID for selecting more details; not present in the detail view. - ID string `db:"id" json:"id,omitempty"` - Name string `db:"name" json:"name"` // Display name. - CountUnique int `db:"count_unique" json:"count_unique"` // Number of visitors. + ID string `db:"id" json:"id,omitempty"` + Name string `db:"name" json:"name"` // Display name. + Count int `db:"count" json:"count"` // Number of visitors. // What kind of referral this is; only set when retrieving referrals {enum: h g c o}. // @@ -184,29 +184,29 @@ func (h *HitStats) ListSizes(ctx context.Context, rng ztime.Range, pathFilter [] // Group a bit more user-friendly. ns := []HitStat{ - {Name: "Phones", ID: sizePhones, CountUnique: 0}, - {Name: "Large phones, small tablets", ID: sizeLargePhones, CountUnique: 0}, - {Name: "Tablets and small laptops", ID: sizeTablets, CountUnique: 0}, - {Name: "Computer monitors", ID: sizeDesktop, CountUnique: 0}, - {Name: "Computer monitors larger than HD", ID: sizeDesktopHD, CountUnique: 0}, - {Name: "(unknown)", ID: sizeUnknown, CountUnique: 0}, + {Name: "Phones", ID: sizePhones, Count: 0}, + {Name: "Large phones, small tablets", ID: sizeLargePhones, Count: 0}, + {Name: "Tablets and small laptops", ID: sizeTablets, Count: 0}, + {Name: "Computer monitors", ID: sizeDesktop, Count: 0}, + {Name: "Computer monitors larger than HD", ID: sizeDesktopHD, Count: 0}, + {Name: "(unknown)", ID: sizeUnknown, Count: 0}, } for i := range h.Stats { x, _ := strconv.ParseInt(h.Stats[i].Name, 10, 16) switch { case x == 0: - ns[5].CountUnique += h.Stats[i].CountUnique + ns[5].Count += h.Stats[i].Count case x <= 384: - ns[0].CountUnique += h.Stats[i].CountUnique + ns[0].Count += h.Stats[i].Count case x <= 1024: - ns[1].CountUnique += h.Stats[i].CountUnique + ns[1].Count += h.Stats[i].Count case x <= 1440: - ns[2].CountUnique += h.Stats[i].CountUnique + ns[2].Count += h.Stats[i].Count case x <= 1920: - ns[3].CountUnique += h.Stats[i].CountUnique + ns[3].Count += h.Stats[i].Count default: - ns[4].CountUnique += h.Stats[i].CountUnique + ns[4].Count += h.Stats[i].Count } } h.Stats = ns diff --git a/hit_stats_test.go b/hit_stats_test.go index 0e102ea4a..c13344444 100644 --- a/hit_stats_test.go +++ b/hit_stats_test.go @@ -65,7 +65,7 @@ func TestHitStats(t *testing.T) { "stats": [ { "name": "Firefox", - "count_unique": 2 + "count": 2 } ] }{ @@ -73,11 +73,11 @@ func TestHitStats(t *testing.T) { "stats": [ { "name": "Firefox 79", - "count_unique": 1 + "count": 1 }, { "name": "Firefox 81", - "count_unique": 1 + "count": 1 } ] }`, list, get) @@ -100,7 +100,7 @@ func TestHitStats(t *testing.T) { "stats": [ { "name": "Linux", - "count_unique": 2 + "count": 2 } ] }{ @@ -108,11 +108,11 @@ func TestHitStats(t *testing.T) { "stats": [ { "name": "Linux", - "count_unique": 1 + "count": 1 }, { "name": "Linux Ubuntu", - "count_unique": 1 + "count": 1 } ] }`, list, get) @@ -136,32 +136,32 @@ func TestHitStats(t *testing.T) { { "id": "phone", "name": "Phones", - "count_unique": 0 + "count": 0 }, { "id": "largephone", "name": "Large phones, small tablets", - "count_unique": 1 + "count": 1 }, { "id": "tablet", "name": "Tablets and small laptops", - "count_unique": 0 + "count": 0 }, { "id": "desktop", "name": "Computer monitors", - "count_unique": 1 + "count": 1 }, { "id": "desktophd", "name": "Computer monitors larger than HD", - "count_unique": 0 + "count": 0 }, { "id": "unknown", "name": "(unknown)", - "count_unique": 0 + "count": 0 } ] }{ @@ -169,7 +169,7 @@ func TestHitStats(t *testing.T) { "stats": [ { "name": "↔\ufe0e 1920px", - "count_unique": 1 + "count": 1 } ] }`, `\ufe0e`, "\ufe0e"), list, get) @@ -207,12 +207,12 @@ func TestHitStats(t *testing.T) { { "id": "ID", "name": "Indonesia", - "count_unique": 1 + "count": 1 }, { "id": "NL", "name": "Netherlands", - "count_unique": 1 + "count": 1 } ] }{ @@ -220,7 +220,7 @@ func TestHitStats(t *testing.T) { "stats": [ { "name": "", - "count_unique": 1 + "count": 1 } ] }{ @@ -228,7 +228,7 @@ func TestHitStats(t *testing.T) { "stats": [ { "name": "Bali", - "count_unique": 1 + "count": 1 } ] }`, list, get, getRegion) @@ -289,32 +289,32 @@ func TestListSizes(t *testing.T) { { "id": "phone", "name": "Phones", - "count_unique": 1 + "count": 1 }, { "id": "largephone", "name": "Large phones, small tablets", - "count_unique": 1 + "count": 1 }, { "id": "tablet", "name": "Tablets and small laptops", - "count_unique": 1 + "count": 1 }, { "id": "desktop", "name": "Computer monitors", - "count_unique": 1 + "count": 1 }, { "id": "desktophd", "name": "Computer monitors larger than HD", - "count_unique": 3 + "count": 3 }, { "id": "unknown", "name": "(unknown)", - "count_unique": 1 + "count": 1 } ] }` @@ -340,7 +340,7 @@ func TestListSizes(t *testing.T) { "stats": [ { "name": "↔\ufe0e 0px", - "count_unique": 1 + "count": 1 } ] }{ @@ -348,7 +348,7 @@ func TestListSizes(t *testing.T) { "stats": [ { "name": "↔\ufe0e 300px", - "count_unique": 1 + "count": 1 } ] }{ @@ -356,7 +356,7 @@ func TestListSizes(t *testing.T) { "stats": [ { "name": "↔\ufe0e 1000px", - "count_unique": 1 + "count": 1 } ] }{ @@ -364,7 +364,7 @@ func TestListSizes(t *testing.T) { "stats": [ { "name": "↔\ufe0e 1100px", - "count_unique": 1 + "count": 1 } ] }{ @@ -372,7 +372,7 @@ func TestListSizes(t *testing.T) { "stats": [ { "name": "↔\ufe0e 1920px", - "count_unique": 1 + "count": 1 } ] }{ @@ -380,15 +380,15 @@ func TestListSizes(t *testing.T) { "stats": [ { "name": "↔\ufe0e 3000px", - "count_unique": 1 + "count": 1 }, { "name": "↔\ufe0e 4000px", - "count_unique": 1 + "count": 1 }, { "name": "↔\ufe0e 4200px", - "count_unique": 1 + "count": 1 } ] }`, `\ufe0e`, "\ufe0e") @@ -416,7 +416,7 @@ func TestStatsByRef(t *testing.T) { want := `{ "more": false, "stats": [{ - "count_unique": 0, + "count": 0, "name": "/a" }] }` diff --git a/public/dashboard.js b/public/dashboard.js index a8076a4b8..881096929 100644 --- a/public/dashboard.js +++ b/public/dashboard.js @@ -91,7 +91,7 @@ data['widget'] = wid data['daily'] = $('#daily').is(':checked') data['max'] = get_original_scale() - data['total'] = $('.js-total-unique-utc').text() + data['total'] = $('.js-total-utc').text() jQuery.ajax({ url: '/load-widget', @@ -490,9 +490,9 @@ var data if (daily) - data = stats.map((s) => [s.daily_unique]).reduce((a, b) => a.concat(b)) + data = stats.map((s) => [s.daily]).reduce((a, b) => a.concat(b)) else - data = stats.map((s) => s.hourly_unique).reduce((a, b) => a.concat(b)) + data = stats.map((s) => s.hourly).reduce((a, b) => a.concat(b)) let futureFrom = 0 var chart = charty(ctx, data, { @@ -538,8 +538,8 @@ day = daily ? stats[i] : stats[Math.floor(i / 24)], start = (i % 24) + ':00', end = (i % 24) + ':59', - visits = daily ? day.daily_unique : day.hourly_unique[i%24], - views = daily ? day.daily : day.hourly[i%24] + visits = daily ? day.daily : day.hourly[i%24], + views = daily ? day.daily : day.hourly[i%24] let title = '' let future = futureFrom && x >= futureFrom - 1 @@ -667,8 +667,8 @@ highlight_filter($('#filter-paths').val()) btn.css('display', data.more ? 'inline-block' : 'none') - pages.find('.total-unique-display').each((_, t) => { - $(t).text(format_int(parseInt($(t).text().replace(/[^0-9]/, ''), 10) + data.total_unique_display)) + pages.find('.total-display').each((_, t) => { + $(t).text(format_int(parseInt($(t).text().replace(/[^0-9]/, ''), 10) + data.total_display)) }) done() @@ -735,7 +735,7 @@ // Paginate and show details for the horizontal charts. var hchart_detail = function() { - var get_total = () => $('.js-total-unique-utc').text() + var get_total = () => $('.js-total-utc').text() // Paginate the horizontal charts. $('.hcharts').on('click', '.load-more', function(e) { diff --git a/ref_test.go b/ref_test.go index 3624dbe7d..4cbff2b70 100644 --- a/ref_test.go +++ b/ref_test.go @@ -35,11 +35,11 @@ func TestListRefsByPath(t *testing.T) { want := `{ "more": false, "stats": [{ - "count_unique": 0, + "count": 0, "name": "example.org", "ref_scheme": "h" }, { - "count_unique": 0, + "count": 0, "name": "example.com", "ref_scheme": "h" }]}` @@ -71,11 +71,11 @@ func TestListTopRefs(t *testing.T) { "more": false, "stats": [{ "name": "example.com", - "count_unique": 1, + "count": 1, "ref_scheme": "h" }, { "name": "example.org", - "count_unique": 1, + "count": 1, "ref_scheme": "h" }] }` @@ -95,7 +95,7 @@ func TestListTopRefs(t *testing.T) { "more": false, "stats": [{ "name": "example.org", - "count_unique": 1, + "count": 1, "ref_scheme": "h" }] }` diff --git a/tpl.go b/tpl.go index 6571f56a2..16df1ca0a 100644 --- a/tpl.go +++ b/tpl.go @@ -418,10 +418,10 @@ func HorizontalChart(ctx context.Context, stats HitStats, total int, link, pagin ) b.WriteString(`
`) for _, s := range stats.Stats { - displayed += s.CountUnique + displayed += s.Count var ( - p = float64(s.CountUnique) / float64(total) * 100 + p = float64(s.Count) / float64(total) * 100 perc string ) switch { @@ -486,7 +486,7 @@ func HorizontalChart(ctx context.Context, stats HitStats, total int, link, pagin ncol := "" if !user.Settings.FewerNumbers { - ncol = tplfunc.Number(s.CountUnique, user.Settings.NumberFormat) + ncol = tplfunc.Number(s.Count, user.Settings.NumberFormat) } id := s.ID diff --git a/tpl/_dashboard_hchart.gohtml b/tpl/_dashboard_hchart.gohtml index 6c1487ea8..ea98815eb 100644 --- a/tpl/_dashboard_hchart.gohtml +++ b/tpl/_dashboard_hchart.gohtml @@ -1,5 +1,5 @@ {{- $x := (t $.Context "dashboard/loading|Loading…") -}} -{{- if $.Loaded -}}{{- $x = horizontal_chart .Context .Stats .TotalUniqueUTC (and (not .RowsOnly) .HasSubMenu) true -}}{{- end -}} +{{- if $.Loaded -}}{{- $x = horizontal_chart .Context .Stats .TotalUTC (and (not .RowsOnly) .HasSubMenu) true -}}{{- end -}} {{- if .RowsOnly -}} {{- $x -}} {{- else -}} diff --git a/tpl/_dashboard_pages.gohtml b/tpl/_dashboard_pages.gohtml index 2b7440fdd..862a36010 100644 --- a/tpl/_dashboard_pages.gohtml +++ b/tpl/_dashboard_pages.gohtml @@ -5,8 +5,8 @@ {{if not $.User.Settings.FewerNumbers}} {{t .Context `dashboard/pages/num-visits|%(num-visits) out of %(total-visits) visits shown` (map - "num-visits" (tag "span" `class="total-unique-display"` (nformat .TotalUniqueDisplay $.User)) - "total-visits" (tag "span" `class="total-unique"` (nformat .TotalUnique $.User)) + "num-visits" (tag "span" `class="total-display"` (nformat .TotalDisplay $.User)) + "total-visits" (tag "span" `class="total"` (nformat .Total $.User)) )}} {{end}} diff --git a/tpl/_dashboard_pages_refs.gohtml b/tpl/_dashboard_pages_refs.gohtml index c87665c20..27b58aca4 100644 --- a/tpl/_dashboard_pages_refs.gohtml +++ b/tpl/_dashboard_pages_refs.gohtml @@ -1 +1 @@ -{{horizontal_chart .Context .Refs .CountUnique false true}} +{{horizontal_chart .Context .Refs .Count false true}} diff --git a/tpl/_dashboard_pages_rows.gohtml b/tpl/_dashboard_pages_rows.gohtml index 6f69d7b4e..cb87546a9 100644 --- a/tpl/_dashboard_pages_rows.gohtml +++ b/tpl/_dashboard_pages_rows.gohtml @@ -1,10 +1,10 @@ {{range $i, $h := .Pages}} - {{if not $.User.Settings.FewerNumbers}} - {{nformat $h.CountUnique $.User}} + {{nformat $h.Count $.User}} {{end}} @@ -48,7 +48,7 @@
{{if and $.Refs (eq $.ShowRefs $h.Path)}} - {{template "_dashboard_pages_refs.gohtml" (map "Context" $.Context "Refs" $.Refs "CountUnique" $h.CountUnique)}} + {{template "_dashboard_pages_refs.gohtml" (map "Context" $.Context "Refs" $.Refs "Count" $h.Count)}} {{end}}
diff --git a/tpl/_dashboard_pages_text.gohtml b/tpl/_dashboard_pages_text.gohtml index 729d5ccd7..631564ef1 100644 --- a/tpl/_dashboard_pages_text.gohtml +++ b/tpl/_dashboard_pages_text.gohtml @@ -4,8 +4,8 @@ {{if not $.User.Settings.FewerNumbers}} {{t .Context `dashboard/pages/num-visits|%(num-visits) out of %(total-visits) visits shown` (map - "num-visits" (tag "span" `class="total-unique-display"` (nformat .TotalUniqueDisplay $.User)) - "total-visits" (tag "span" `class="total-unique"` (nformat .TotalUnique $.User)) + "num-visits" (tag "span" `class="total-display"` (nformat .TotalDisplay $.User)) + "total-visits" (tag "span" `class="total"` (nformat .Total $.User)) )}} {{end}} diff --git a/tpl/_dashboard_pages_text_rows.gohtml b/tpl/_dashboard_pages_text_rows.gohtml index 23479ad60..9a8374900 100644 --- a/tpl/_dashboard_pages_text_rows.gohtml +++ b/tpl/_dashboard_pages_text_rows.gohtml @@ -4,7 +4,7 @@ > {{sum $.Offset $i}} {{if not $.User.Settings.FewerNumbers}} - {{nformat $h.CountUnique $.User}} + {{nformat $h.Count $.User}} {{end}} {{$h.Path}} @@ -17,7 +17,7 @@
{{if and $.Refs (eq $.ShowRefs $h.Path)}} - {{template "_dashboard_pages_refs.gohtml" (map "Context" $.Context "Refs" $.Refs "CountUnique" $h.CountUnique)}} + {{template "_dashboard_pages_refs.gohtml" (map "Context" $.Context "Refs" $.Refs "Count" $h.Count)}} {{end}}
diff --git a/tpl/_dashboard_toprefs.gohtml b/tpl/_dashboard_toprefs.gohtml index 1939c7a7c..e4075e7b1 100644 --- a/tpl/_dashboard_toprefs.gohtml +++ b/tpl/_dashboard_toprefs.gohtml @@ -1,5 +1,5 @@ {{- $x := (t $.Context "dashboard/loading|Loading…") -}} -{{- if .Loaded -}}{{- $x = horizontal_chart .Context .Stats .TotalUnique (not .RowsOnly) true -}}{{- end -}} +{{- if .Loaded -}}{{- $x = horizontal_chart .Context .Stats .Total (not .RowsOnly) true -}}{{- end -}} {{- if .RowsOnly -}} {{- $x -}} {{- else -}} diff --git a/tpl/_dashboard_totals.gohtml b/tpl/_dashboard_totals.gohtml index 41a25b0ca..4232b8265 100644 --- a/tpl/_dashboard_totals.gohtml +++ b/tpl/_dashboard_totals.gohtml @@ -5,12 +5,12 @@ {{if .NoEvents}} {{t .Context `dashboard/totals/num-visits|%(num-visits) visits; excluding events` (map - "num-visits" (tag "span" `` (nformat (sub .TotalUnique .TotalEventsUnique) $.User)) + "num-visits" (tag "span" `` (nformat (sub .Total .TotalEvents) $.User)) )}} {{else}} {{t .Context `dashboard/totals/num-visits|%(num-visits) visits` (map - "num-visits" (tag "span" `` (nformat .TotalUnique $.User)) + "num-visits" (tag "span" `` (nformat .Total $.User)) )}} {{end}} {{end}} diff --git a/tpl/api.html b/tpl/api.html index bd578bf34..685ea6c47 100644 --- a/tpl/api.html +++ b/tpl/api.html @@ -689,7 +689,7 @@

permissions integer

goatcounter.HitList

-

count_unique integer

+

count integer

Number of visitors for the selected date range.

path_id integer

Path ID

@@ -716,9 +716,9 @@

goatcounter.HitListStat

-

total_unique integer

+

total integer

Total number of visitors (including events).

-

total_events_unique integer

+

total_events integer

Total number of visitors for events.

-

total_unique_utc integer

+

total_utc integer

Total number of visitors in UTC. The browser, system, etc, stats are always in UTC.

@@ -1008,7 +1008,7 @@

handlers.apiHitsResponse

goatcounter.HitList]

Sorted list of paths with their visitor and pageview count.

-

total_unique integer

+

total integer

Total number of visitors in the returned result.

more boolean

More hits after this?

diff --git a/tpl/api.json b/tpl/api.json index c3b2e510f..a35c26543 100644 --- a/tpl/api.json +++ b/tpl/api.json @@ -1014,7 +1014,7 @@ "title": "HitList", "type": "object", "properties": { - "count_unique": { + "count": { "description": "Number of visitors for the selected date range.", "type": "integer" }, @@ -1062,7 +1062,7 @@ "title": "HitListStat", "type": "object", "properties": { - "daily_unique": { + "daily": { "description": "Total visitors for this day.", "type": "integer" }, @@ -1071,7 +1071,7 @@ "type": "string", "format": "date" }, - "hourly_unique": { + "hourly": { "description": "Visitors per hour.", "type": "array", "items": { @@ -1084,7 +1084,7 @@ "title": "HitStat", "type": "object", "properties": { - "count_unique": { + "count": { "description": "Number of visitors.", "type": "integer" }, @@ -1235,15 +1235,15 @@ "title": "TotalCount", "type": "object", "properties": { - "total_events_unique": { - "description": "Total number of visitors for events.", + "total": { + "description": "Total number of visitors (including events).", "type": "integer" }, - "total_unique": { - "description": "Total number of visitors (including events).", + "total_events": { + "description": "Total number of visitors for events.", "type": "integer" }, - "total_unique_utc": { + "total_utc": { "description": "Total number of visitors in UTC. The browser, system, etc, stats are\nalways in UTC.", "type": "integer" } @@ -1507,7 +1507,7 @@ "description": "More hits after this?", "type": "boolean" }, - "total_unique": { + "total": { "description": "Total number of visitors in the returned result.", "type": "integer" } diff --git a/tpl/dashboard.gohtml b/tpl/dashboard.gohtml index edba41371..d4e6b6317 100644 --- a/tpl/dashboard.gohtml +++ b/tpl/dashboard.gohtml @@ -138,8 +138,8 @@
-{{.TotalUnique}} -{{.TotalUniqueUTC}} +{{.Total}} +{{.TotalUTC}} {{.ConnectID}} {{template "_dashboard_widgets.gohtml" .}} diff --git a/tpl/email_report.gohtml b/tpl/email_report.gohtml index d63076370..5ae0135bc 100644 --- a/tpl/email_report.gohtml +++ b/tpl/email_report.gohtml @@ -14,7 +14,7 @@ {{range $i, $p := .Pages}} {{$p.Path}}{{if $p.Event}} event{{end}} - {{nformat $p.CountUnique $.User}} + {{nformat $p.Count $.User}} {{index $.Diffs $i}} {{end}} @@ -29,7 +29,7 @@ {{range $r := .Refs.Stats}} {{if $r.Name}}{{$r.Name}}{{else}}(no data){{end}} - {{nformat $r.CountUnique $.User}} + {{nformat $r.Count $.User}} {{end}} diff --git a/tpl/help/visitor-counter.markdown b/tpl/help/visitor-counter.markdown index 085653093..8ef228706 100644 --- a/tpl/help/visitor-counter.markdown +++ b/tpl/help/visitor-counter.markdown @@ -117,9 +117,11 @@ The `.json` extension will return the pageview count in JSON; you can't use this with a HTML tag but it can be used if you want to build your own counter in JavaScript. -It returns an Object with two values: `count`, which contains the total number -of pageviews, and `count_unique`, which contains the unique visitor count. Both -are a formatted string with thousands separators. +It returns an Object with `count`, containing the total number of visitors +as a formatted string with thousands separators. + +There is also a `count_unique` field for backwards compatibility; the value is +identical to `count`. This should not be used for new code. A simple example usage: @@ -128,7 +130,7 @@ A simple example usage: