From c1367325e62a0e1a880dc101508e4feb4d70afe6 Mon Sep 17 00:00:00 2001 From: Danny van Kooten Date: Fri, 5 Oct 2018 13:09:58 +0200 Subject: [PATCH] modify all routes & queries to take a site ID parameter --- assets/src/js/components/Chart.js | 2 +- assets/src/js/components/Realtime.js | 2 +- assets/src/js/components/Sidebar.js | 2 +- assets/src/js/components/Table.js | 4 +- assets/src/js/pages/dashboard.js | 2 +- cmd/fathom/stats.go | 8 ++- pkg/aggregator/store.go | 6 +- pkg/api/page_stats.go | 4 +- pkg/api/params.go | 31 ++++++--- pkg/api/referrer_stats.go | 4 +- pkg/api/routes.go | 30 ++++----- pkg/api/site_stats.go | 15 ++--- pkg/datastore/datastore.go | 30 ++++----- pkg/datastore/sqlstore/page_stats.go | 31 ++++----- pkg/datastore/sqlstore/referrer_stats.go | 28 ++++----- pkg/datastore/sqlstore/site_stats.go | 80 +++++++++++++----------- 16 files changed, 155 insertions(+), 124 deletions(-) diff --git a/assets/src/js/components/Chart.js b/assets/src/js/components/Chart.js index 9208897..7814fae 100644 --- a/assets/src/js/components/Chart.js +++ b/assets/src/js/components/Chart.js @@ -215,7 +215,7 @@ class Chart extends Component { fetchData(before, after) { this.setState({ loading: true }) - Client.request(`/stats/site/groupby/day?before=${before}&after=${after}`) + Client.request(`/sites/${this.props.site.id}/stats/site/groupby/day?before=${before}&after=${after}`) .then((d) => { // request finished; check if timestamp range is still the one user wants to see if( this.props.before != before || this.props.after != after ) { diff --git a/assets/src/js/components/Realtime.js b/assets/src/js/components/Realtime.js index 602a0db..4ad3316 100644 --- a/assets/src/js/components/Realtime.js +++ b/assets/src/js/components/Realtime.js @@ -33,7 +33,7 @@ class Realtime extends Component { @bind fetchData() { - Client.request(`stats/site/realtime`) + Client.request(`/sites/${this.props.site.id}/stats/site/realtime`) .then((d) => { this.setState({ count: d }) this.setDocumentTitle(); diff --git a/assets/src/js/components/Sidebar.js b/assets/src/js/components/Sidebar.js index d0b5c70..66c1c5a 100644 --- a/assets/src/js/components/Sidebar.js +++ b/assets/src/js/components/Sidebar.js @@ -29,7 +29,7 @@ class Sidebar extends Component { fetchData(before, after) { this.setState({ loading: true }) - Client.request(`stats/site?before=${before}&after=${after}`) + Client.request(`/sites/${this.props.site.id}/stats/site?before=${before}&after=${after}`) .then((data) => { // request finished; check if timestamp range is still the one user wants to see if( this.props.before != before || this.props.after != after ) { diff --git a/assets/src/js/components/Table.js b/assets/src/js/components/Table.js index 5b7ec9c..88aaa58 100644 --- a/assets/src/js/components/Table.js +++ b/assets/src/js/components/Table.js @@ -33,7 +33,7 @@ class Table extends Component { fetchRecords(before, after) { this.setState({ loading: true }); - Client.request(`${this.props.endpoint}?before=${before}&after=${after}&limit=${this.state.limit}`) + Client.request(`/sites/${this.props.site.id}/${this.props.endpoint}?before=${before}&after=${after}&limit=${this.state.limit}`) .then((d) => { // request finished; check if timestamp range is still the one user wants to see if( this.props.before != before || this.props.after != after ) { @@ -47,7 +47,7 @@ class Table extends Component { }); // fetch totals too - Client.request(`${this.props.endpoint}/pageviews?before=${before}&after=${after}`) + Client.request(`/sites/${this.props.site.id}/${this.props.endpoint}/pageviews?before=${before}&after=${after}`) .then((d) => { this.setState({ total: d diff --git a/assets/src/js/pages/dashboard.js b/assets/src/js/pages/dashboard.js index d75da61..0813651 100644 --- a/assets/src/js/pages/dashboard.js +++ b/assets/src/js/pages/dashboard.js @@ -111,7 +111,7 @@ class Dashboard extends Component { -
  • +
  • diff --git a/cmd/fathom/stats.go b/cmd/fathom/stats.go index 4b67b1e..10b481f 100644 --- a/cmd/fathom/stats.go +++ b/cmd/fathom/stats.go @@ -4,9 +4,10 @@ import ( "encoding/json" "errors" "fmt" - "github.com/urfave/cli" "os" "time" + + "github.com/urfave/cli" ) var statsCmd = cli.Command{ @@ -40,7 +41,10 @@ func stats(c *cli.Context) error { return errors.New("Invalid argument: supply a valid --end-date") } - result, err := app.database.GetAggregatedSiteStats(start, end) + // TODO: add flag for this + // TODO: add method for getting total sum of pageviews across sites + var siteID int64 = 0 + result, err := app.database.GetAggregatedSiteStats(siteID, start, end) if err != nil { return err } diff --git a/pkg/aggregator/store.go b/pkg/aggregator/store.go index 6a1b971..9e149bb 100644 --- a/pkg/aggregator/store.go +++ b/pkg/aggregator/store.go @@ -17,7 +17,7 @@ func (agg *aggregator) getSiteStats(r *results, t time.Time) (*models.SiteStats, } // get from db - stats, err := agg.database.GetSiteStats(t) + stats, err := agg.database.GetSiteStats(0, t) if err != nil && err != datastore.ErrNoResults { return nil, err } @@ -44,7 +44,7 @@ func (agg *aggregator) getPageStats(r *results, t time.Time, hostname string, pa return stats, nil } - stats, err := agg.database.GetPageStats(t, hostname, pathname) + stats, err := agg.database.GetPageStats(0, t, hostname, pathname) if err != nil && err != datastore.ErrNoResults { return nil, err } @@ -72,7 +72,7 @@ func (agg *aggregator) getReferrerStats(r *results, t time.Time, hostname string } // get from db - stats, err := agg.database.GetReferrerStats(t, hostname, pathname) + stats, err := agg.database.GetReferrerStats(0, t, hostname, pathname) if err != nil && err != datastore.ErrNoResults { return nil, err } diff --git a/pkg/api/page_stats.go b/pkg/api/page_stats.go index c01a20f..0176acf 100644 --- a/pkg/api/page_stats.go +++ b/pkg/api/page_stats.go @@ -7,7 +7,7 @@ import ( // URL: /api/stats/page func (api *API) GetPageStatsHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetAggregatedPageStats(params.StartDate, params.EndDate, params.Limit) + result, err := api.database.GetAggregatedPageStats(params.SiteID, params.StartDate, params.EndDate, params.Limit) if err != nil { return err } @@ -16,7 +16,7 @@ func (api *API) GetPageStatsHandler(w http.ResponseWriter, r *http.Request) erro func (api *API) GetPageStatsPageviewsHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetAggregatedPageStatsPageviews(params.StartDate, params.EndDate) + result, err := api.database.GetAggregatedPageStatsPageviews(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } diff --git a/pkg/api/params.go b/pkg/api/params.go index aea9164..fd3138e 100644 --- a/pkg/api/params.go +++ b/pkg/api/params.go @@ -5,11 +5,14 @@ import ( "strconv" "strings" "time" + + "github.com/gorilla/mux" ) // Params defines the commonly used API parameters type Params struct { - Limit int + SiteID int64 + Limit int64 StartDate time.Time EndDate time.Time } @@ -17,22 +20,36 @@ type Params struct { // GetRequestParams parses the query parameters and returns commonly used API parameters, with defaults func GetRequestParams(r *http.Request) *Params { params := &Params{ + SiteID: 0, Limit: 20, StartDate: time.Now(), EndDate: time.Now().AddDate(0, 0, -7), } + vars := mux.Vars(r) + if _, ok := vars["id"]; ok { + if siteID, err := strconv.ParseInt(vars["id"], 10, 64); err == nil { + params.SiteID = siteID + } + } + q := r.URL.Query() - if after, err := strconv.ParseInt(q.Get("after"), 10, 64); err == nil && after > 0 { - params.StartDate = time.Unix(after, 0) + if q.Get("after") != "" { + if after, err := strconv.ParseInt(q.Get("after"), 10, 64); err == nil && after > 0 { + params.StartDate = time.Unix(after, 0) + } } - if before, err := strconv.ParseInt(q.Get("before"), 10, 64); err == nil && before > 0 { - params.EndDate = time.Unix(before, 0) + if q.Get("before") != "" { + if before, err := strconv.ParseInt(q.Get("before"), 10, 64); err == nil && before > 0 { + params.EndDate = time.Unix(before, 0) + } } - if limit, err := strconv.Atoi(q.Get("limit")); err == nil && limit > 0 { - params.Limit = limit + if q.Get("limit") != "" { + if limit, err := strconv.ParseInt(q.Get("limit"), 10, 64); err == nil && limit > 0 { + params.Limit = limit + } } return params diff --git a/pkg/api/referrer_stats.go b/pkg/api/referrer_stats.go index 75702fb..c32feca 100644 --- a/pkg/api/referrer_stats.go +++ b/pkg/api/referrer_stats.go @@ -7,7 +7,7 @@ import ( // URL: /api/stats/referrer func (api *API) GetReferrerStatsHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetAggregatedReferrerStats(params.StartDate, params.EndDate, params.Limit) + result, err := api.database.GetAggregatedReferrerStats(params.SiteID, params.StartDate, params.EndDate, params.Limit) if err != nil { return err } @@ -17,7 +17,7 @@ func (api *API) GetReferrerStatsHandler(w http.ResponseWriter, r *http.Request) // URL: /api/stats/referrer/pageviews func (api *API) GetReferrerStatsPageviewsHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetAggregatedReferrerStatsPageviews(params.StartDate, params.EndDate) + result, err := api.database.GetAggregatedReferrerStatsPageviews(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } diff --git a/pkg/api/routes.go b/pkg/api/routes.go index a56fa85..1b555ac 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -12,28 +12,28 @@ func (api *API) Routes() *mux.Router { r := mux.NewRouter() r.Handle("/collect", NewCollector(api.database)).Methods(http.MethodGet) + r.Handle("/api/session", HandlerFunc(api.GetSession)).Methods(http.MethodGet) + r.Handle("/api/session", HandlerFunc(api.CreateSession)).Methods(http.MethodPost) + r.Handle("/api/session", HandlerFunc(api.DeleteSession)).Methods(http.MethodDelete) + r.Handle("/api/sites", api.Authorize(HandlerFunc(api.GetSitesHandler))).Methods(http.MethodGet) r.Handle("/api/sites", api.Authorize(HandlerFunc(api.SaveSiteHandler))).Methods(http.MethodPost) r.Handle("/api/sites/{id:[0-9]+}", api.Authorize(HandlerFunc(api.SaveSiteHandler))).Methods(http.MethodPost) r.Handle("/api/sites/{id:[0-9]+}", api.Authorize(HandlerFunc(api.DeleteSiteHandler))).Methods(http.MethodDelete) - r.Handle("/api/session", HandlerFunc(api.GetSession)).Methods(http.MethodGet) - r.Handle("/api/session", HandlerFunc(api.CreateSession)).Methods(http.MethodPost) - r.Handle("/api/session", HandlerFunc(api.DeleteSession)).Methods(http.MethodDelete) + r.Handle("/api/sites/{id:[0-9]+}/stats/site", api.Authorize(HandlerFunc(api.GetSiteStatsHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/site/groupby/day", api.Authorize(HandlerFunc(api.GetSiteStatsPerDayHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/site/pageviews", api.Authorize(HandlerFunc(api.GetSiteStatsPageviewsHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/site/visitors", api.Authorize(HandlerFunc(api.GetSiteStatsVisitorsHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/site/duration", api.Authorize(HandlerFunc(api.GetSiteStatsDurationHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/site/bounces", api.Authorize(HandlerFunc(api.GetSiteStatsBouncesHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/site/realtime", api.Authorize(HandlerFunc(api.GetSiteStatsRealtimeHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/site", api.Authorize(HandlerFunc(api.GetSiteStatsHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/site/groupby/day", api.Authorize(HandlerFunc(api.GetSiteStatsPerDayHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/site/pageviews", api.Authorize(HandlerFunc(api.GetSiteStatsPageviewsHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/site/visitors", api.Authorize(HandlerFunc(api.GetSiteStatsVisitorsHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/site/duration", api.Authorize(HandlerFunc(api.GetSiteStatsDurationHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/site/bounces", api.Authorize(HandlerFunc(api.GetSiteStatsBouncesHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/site/realtime", api.Authorize(HandlerFunc(api.GetSiteStatsRealtimeHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/pages", api.Authorize(HandlerFunc(api.GetPageStatsHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/pages/pageviews", api.Authorize(HandlerFunc(api.GetPageStatsPageviewsHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/pages", api.Authorize(HandlerFunc(api.GetPageStatsHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/pages/pageviews", api.Authorize(HandlerFunc(api.GetPageStatsPageviewsHandler))).Methods(http.MethodGet) - - r.Handle("/api/stats/referrers", api.Authorize(HandlerFunc(api.GetReferrerStatsHandler))).Methods(http.MethodGet) - r.Handle("/api/stats/referrers/pageviews", api.Authorize(HandlerFunc(api.GetReferrerStatsPageviewsHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/referrers", api.Authorize(HandlerFunc(api.GetReferrerStatsHandler))).Methods(http.MethodGet) + r.Handle("/api/sites/{id:[0-9]+}/stats/referrers/pageviews", api.Authorize(HandlerFunc(api.GetReferrerStatsPageviewsHandler))).Methods(http.MethodGet) r.Handle("/health", HandlerFunc(api.Health)).Methods(http.MethodGet) diff --git a/pkg/api/site_stats.go b/pkg/api/site_stats.go index 6b61653..b3872e2 100644 --- a/pkg/api/site_stats.go +++ b/pkg/api/site_stats.go @@ -7,7 +7,7 @@ import ( // URL: /api/stats/site func (api *API) GetSiteStatsHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetAggregatedSiteStats(params.StartDate, params.EndDate) + result, err := api.database.GetAggregatedSiteStats(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } @@ -17,7 +17,7 @@ func (api *API) GetSiteStatsHandler(w http.ResponseWriter, r *http.Request) erro // URL: /api/stats/site/pageviews func (api *API) GetSiteStatsPageviewsHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetTotalSiteViews(params.StartDate, params.EndDate) + result, err := api.database.GetTotalSiteViews(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } @@ -27,7 +27,7 @@ func (api *API) GetSiteStatsPageviewsHandler(w http.ResponseWriter, r *http.Requ // URL: /api/stats/site/visitors func (api *API) GetSiteStatsVisitorsHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetTotalSiteVisitors(params.StartDate, params.EndDate) + result, err := api.database.GetTotalSiteVisitors(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } @@ -37,7 +37,7 @@ func (api *API) GetSiteStatsVisitorsHandler(w http.ResponseWriter, r *http.Reque // URL: /api/stats/site/duration func (api *API) GetSiteStatsDurationHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetAverageSiteDuration(params.StartDate, params.EndDate) + result, err := api.database.GetAverageSiteDuration(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } @@ -47,7 +47,7 @@ func (api *API) GetSiteStatsDurationHandler(w http.ResponseWriter, r *http.Reque // URL: /api/stats/site/bounces func (api *API) GetSiteStatsBouncesHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetAverageSiteBounceRate(params.StartDate, params.EndDate) + result, err := api.database.GetAverageSiteBounceRate(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } @@ -56,7 +56,8 @@ func (api *API) GetSiteStatsBouncesHandler(w http.ResponseWriter, r *http.Reques // URL: /api/stats/site/realtime func (api *API) GetSiteStatsRealtimeHandler(w http.ResponseWriter, r *http.Request) error { - result, err := api.database.GetRealtimeVisitorCount() + params := GetRequestParams(r) + result, err := api.database.GetRealtimeVisitorCount(params.SiteID) if err != nil { return err } @@ -66,7 +67,7 @@ func (api *API) GetSiteStatsRealtimeHandler(w http.ResponseWriter, r *http.Reque // URL: /api/stats/site/groupby/day func (api *API) GetSiteStatsPerDayHandler(w http.ResponseWriter, r *http.Request) error { params := GetRequestParams(r) - result, err := api.database.GetSiteStatsPerDay(params.StartDate, params.EndDate) + result, err := api.database.GetSiteStatsPerDay(params.SiteID, params.StartDate, params.EndDate) if err != nil { return err } diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go index 9c314d5..c4af534 100644 --- a/pkg/datastore/datastore.go +++ b/pkg/datastore/datastore.go @@ -25,17 +25,17 @@ type Datastore interface { DeleteSite(s *models.Site) error // site stats - GetSiteStats(time.Time) (*models.SiteStats, error) - GetSiteStatsPerDay(time.Time, time.Time) ([]*models.SiteStats, error) + GetSiteStats(int64, time.Time) (*models.SiteStats, error) + GetSiteStatsPerDay(int64, time.Time, time.Time) ([]*models.SiteStats, error) InsertSiteStats(*models.SiteStats) error UpdateSiteStats(*models.SiteStats) error - GetAggregatedSiteStats(time.Time, time.Time) (*models.SiteStats, error) - GetTotalSiteViews(time.Time, time.Time) (int, error) - GetTotalSiteVisitors(time.Time, time.Time) (int, error) - GetTotalSiteSessions(time.Time, time.Time) (int, error) - GetAverageSiteDuration(time.Time, time.Time) (float64, error) - GetAverageSiteBounceRate(time.Time, time.Time) (float64, error) - GetRealtimeVisitorCount() (int, error) + GetAggregatedSiteStats(int64, time.Time, time.Time) (*models.SiteStats, error) + GetTotalSiteViews(int64, time.Time, time.Time) (int64, error) + GetTotalSiteVisitors(int64, time.Time, time.Time) (int64, error) + GetTotalSiteSessions(int64, time.Time, time.Time) (int64, error) + GetAverageSiteDuration(int64, time.Time, time.Time) (float64, error) + GetAverageSiteBounceRate(int64, time.Time, time.Time) (float64, error) + GetRealtimeVisitorCount(int64) (int64, error) // pageviews InsertPageviews([]*models.Pageview) error @@ -45,18 +45,18 @@ type Datastore interface { DeletePageviews([]*models.Pageview) error // page stats - GetPageStats(time.Time, string, string) (*models.PageStats, error) + GetPageStats(int64, time.Time, string, string) (*models.PageStats, error) InsertPageStats(*models.PageStats) error UpdatePageStats(*models.PageStats) error - GetAggregatedPageStats(time.Time, time.Time, int) ([]*models.PageStats, error) - GetAggregatedPageStatsPageviews(time.Time, time.Time) (int, error) + GetAggregatedPageStats(int64, time.Time, time.Time, int64) ([]*models.PageStats, error) + GetAggregatedPageStatsPageviews(int64, time.Time, time.Time) (int64, error) // referrer stats - GetReferrerStats(time.Time, string, string) (*models.ReferrerStats, error) + GetReferrerStats(int64, time.Time, string, string) (*models.ReferrerStats, error) InsertReferrerStats(*models.ReferrerStats) error UpdateReferrerStats(*models.ReferrerStats) error - GetAggregatedReferrerStats(time.Time, time.Time, int) ([]*models.ReferrerStats, error) - GetAggregatedReferrerStatsPageviews(time.Time, time.Time) (int, error) + GetAggregatedReferrerStats(int64, time.Time, time.Time, int64) ([]*models.ReferrerStats, error) + GetAggregatedReferrerStatsPageviews(int64, time.Time, time.Time) (int64, error) // misc Health() error diff --git a/pkg/datastore/sqlstore/page_stats.go b/pkg/datastore/sqlstore/page_stats.go index aeb0a9e..5f6a721 100644 --- a/pkg/datastore/sqlstore/page_stats.go +++ b/pkg/datastore/sqlstore/page_stats.go @@ -2,14 +2,15 @@ package sqlstore import ( "database/sql" - "github.com/usefathom/fathom/pkg/models" "time" + + "github.com/usefathom/fathom/pkg/models" ) -func (db *sqlstore) GetPageStats(date time.Time, hostname string, pathname string) (*models.PageStats, error) { +func (db *sqlstore) GetPageStats(siteID int64, date time.Time, hostname string, pathname string) (*models.PageStats, error) { stats := &models.PageStats{} - query := db.Rebind(`SELECT * FROM daily_page_stats WHERE hostname = ? AND pathname = ? AND date = ? LIMIT 1`) - err := db.Get(stats, query, hostname, pathname, date.Format("2006-01-02")) + query := db.Rebind(`SELECT * FROM daily_page_stats WHERE site_id = ? AND hostname = ? AND pathname = ? AND date = ? LIMIT 1`) + err := db.Get(stats, query, siteID, hostname, pathname, date.Format("2006-01-02")) if err != nil && err == sql.ErrNoRows { return nil, ErrNoResults } @@ -17,18 +18,18 @@ func (db *sqlstore) GetPageStats(date time.Time, hostname string, pathname strin } func (db *sqlstore) InsertPageStats(s *models.PageStats) error { - query := db.Rebind(`INSERT INTO daily_page_stats(pageviews, visitors, entries, bounce_rate, avg_duration, known_durations, hostname, pathname, date) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)`) - _, err := db.Exec(query, s.Pageviews, s.Visitors, s.Entries, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) + query := db.Rebind(`INSERT INTO daily_page_stats(pageviews, visitors, entries, bounce_rate, avg_duration, known_durations, site_id, hostname, pathname, date) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`) + _, err := db.Exec(query, s.Pageviews, s.Visitors, s.Entries, s.BounceRate, s.AvgDuration, s.KnownDurations, s.SiteID, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) return err } func (db *sqlstore) UpdatePageStats(s *models.PageStats) error { - query := db.Rebind(`UPDATE daily_page_stats SET pageviews = ?, visitors = ?, entries = ?, bounce_rate = ROUND(?, 4), avg_duration = ROUND(?, 4), known_durations = ? WHERE hostname = ? AND pathname = ? AND date = ?`) - _, err := db.Exec(query, s.Pageviews, s.Visitors, s.Entries, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) + query := db.Rebind(`UPDATE daily_page_stats SET pageviews = ?, visitors = ?, entries = ?, bounce_rate = ROUND(?, 4), avg_duration = ROUND(?, 4), known_durations = ? WHERE site_id = ? AND hostname = ? AND pathname = ? AND date = ?`) + _, err := db.Exec(query, s.Pageviews, s.Visitors, s.Entries, s.BounceRate, s.AvgDuration, s.KnownDurations, s.SiteID, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) return err } -func (db *sqlstore) GetAggregatedPageStats(startDate time.Time, endDate time.Time, limit int) ([]*models.PageStats, error) { +func (db *sqlstore) GetAggregatedPageStats(siteID int64, startDate time.Time, endDate time.Time, limit int64) ([]*models.PageStats, error) { var result []*models.PageStats query := db.Rebind(`SELECT hostname, @@ -38,16 +39,16 @@ func (db *sqlstore) GetAggregatedPageStats(startDate time.Time, endDate time.Tim SUM(entries) AS entries, COALESCE(ROUND(SUM(entries*bounce_rate) / NULLIF(SUM(entries), 0), 4), 0.00) AS bounce_rate, COALESCE(ROUND(SUM(avg_duration*pageviews) / SUM(pageviews), 4), 0.00) AS avg_duration - FROM daily_page_stats WHERE date >= ? AND date <= ? + FROM daily_page_stats WHERE site_id = ? AND date >= ? AND date <= ? GROUP BY hostname, pathname ORDER BY pageviews DESC LIMIT ?`) - err := db.Select(&result, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02"), limit) + err := db.Select(&result, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02"), limit) return result, err } -func (db *sqlstore) GetAggregatedPageStatsPageviews(startDate time.Time, endDate time.Time) (int, error) { - var result int - query := db.Rebind(`SELECT COALESCE(SUM(pageviews), 0) FROM daily_page_stats WHERE date >= ? AND date <= ?`) - err := db.Get(&result, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) +func (db *sqlstore) GetAggregatedPageStatsPageviews(siteID int64, startDate time.Time, endDate time.Time) (int64, error) { + var result int64 + query := db.Rebind(`SELECT COALESCE(SUM(pageviews), 0) FROM daily_page_stats WHERE site_id = ? AND date >= ? AND date <= ?`) + err := db.Get(&result, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return result, err } diff --git a/pkg/datastore/sqlstore/referrer_stats.go b/pkg/datastore/sqlstore/referrer_stats.go index 6f4aad9..51de8b2 100644 --- a/pkg/datastore/sqlstore/referrer_stats.go +++ b/pkg/datastore/sqlstore/referrer_stats.go @@ -7,10 +7,10 @@ import ( "github.com/usefathom/fathom/pkg/models" ) -func (db *sqlstore) GetReferrerStats(date time.Time, hostname string, pathname string) (*models.ReferrerStats, error) { +func (db *sqlstore) GetReferrerStats(siteID int64, date time.Time, hostname string, pathname string) (*models.ReferrerStats, error) { stats := &models.ReferrerStats{} - query := db.Rebind(`SELECT * FROM daily_referrer_stats WHERE date = ? AND hostname = ? AND pathname = ? LIMIT 1`) - err := db.Get(stats, query, date.Format("2006-01-02"), hostname, pathname) + query := db.Rebind(`SELECT * FROM daily_referrer_stats WHERE site_id = ? AND date = ? AND hostname = ? AND pathname = ? LIMIT 1`) + err := db.Get(stats, query, siteID, date.Format("2006-01-02"), hostname, pathname) if err != nil && err == sql.ErrNoRows { return nil, ErrNoResults } @@ -18,18 +18,18 @@ func (db *sqlstore) GetReferrerStats(date time.Time, hostname string, pathname s } func (db *sqlstore) InsertReferrerStats(s *models.ReferrerStats) error { - query := db.Rebind(`INSERT INTO daily_referrer_stats(visitors, pageviews, bounce_rate, avg_duration, known_durations, groupname, hostname, pathname, date) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)`) - _, err := db.Exec(query, s.Visitors, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Group, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) + query := db.Rebind(`INSERT INTO daily_referrer_stats(visitors, pageviews, bounce_rate, avg_duration, known_durations, groupname, site_id, hostname, pathname, date) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`) + _, err := db.Exec(query, s.Visitors, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Group, s.SiteID, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) return err } func (db *sqlstore) UpdateReferrerStats(s *models.ReferrerStats) error { - query := db.Rebind(`UPDATE daily_referrer_stats SET visitors = ?, pageviews = ?, bounce_rate = ROUND(?, 4), avg_duration = ROUND(?, 4), known_durations = ?, groupname = ? WHERE hostname = ? AND pathname = ? AND date = ?`) - _, err := db.Exec(query, s.Visitors, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Group, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) + query := db.Rebind(`UPDATE daily_referrer_stats SET visitors = ?, pageviews = ?, bounce_rate = ROUND(?, 4), avg_duration = ROUND(?, 4), known_durations = ?, groupname = ? WHERE site_id = ? AND hostname = ? AND pathname = ? AND date = ?`) + _, err := db.Exec(query, s.Visitors, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Group, s.SiteID, s.Hostname, s.Pathname, s.Date.Format("2006-01-02")) return err } -func (db *sqlstore) GetAggregatedReferrerStats(startDate time.Time, endDate time.Time, limit int) ([]*models.ReferrerStats, error) { +func (db *sqlstore) GetAggregatedReferrerStats(siteID int64, startDate time.Time, endDate time.Time, limit int64) ([]*models.ReferrerStats, error) { var result []*models.ReferrerStats sql := `SELECT @@ -41,7 +41,7 @@ func (db *sqlstore) GetAggregatedReferrerStats(startDate time.Time, endDate time COALESCE(ROUND(SUM(pageviews*NULLIF(bounce_rate, 0)) / SUM(pageviews), 4), 0.00) AS bounce_rate, COALESCE(ROUND(SUM(avg_duration*pageviews) / SUM(pageviews), 4), 0.00) AS avg_duration FROM daily_referrer_stats - WHERE date >= ? AND date <= ? ` + WHERE site_id = ? AND date >= ? AND date <= ? ` if db.Config.Driver == "sqlite3" { sql = sql + `GROUP BY COALESCE(NULLIF(groupname, ''), hostname || pathname ) ` @@ -52,13 +52,13 @@ func (db *sqlstore) GetAggregatedReferrerStats(startDate time.Time, endDate time query := db.Rebind(sql) - err := db.Select(&result, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02"), limit) + err := db.Select(&result, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02"), limit) return result, err } -func (db *sqlstore) GetAggregatedReferrerStatsPageviews(startDate time.Time, endDate time.Time) (int, error) { - var result int - query := db.Rebind(`SELECT COALESCE(SUM(pageviews), 0) FROM daily_referrer_stats WHERE date >= ? AND date <= ?`) - err := db.Get(&result, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) +func (db *sqlstore) GetAggregatedReferrerStatsPageviews(siteID int64, startDate time.Time, endDate time.Time) (int64, error) { + var result int64 + query := db.Rebind(`SELECT COALESCE(SUM(pageviews), 0) FROM daily_referrer_stats WHERE site_id = ? AND date >= ? AND date <= ?`) + err := db.Get(&result, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return result, err } diff --git a/pkg/datastore/sqlstore/site_stats.go b/pkg/datastore/sqlstore/site_stats.go index 214cb0e..dbdecfd 100644 --- a/pkg/datastore/sqlstore/site_stats.go +++ b/pkg/datastore/sqlstore/site_stats.go @@ -7,10 +7,10 @@ import ( "github.com/usefathom/fathom/pkg/models" ) -func (db *sqlstore) GetSiteStats(date time.Time) (*models.SiteStats, error) { +func (db *sqlstore) GetSiteStats(siteID int64, date time.Time) (*models.SiteStats, error) { stats := &models.SiteStats{} - query := db.Rebind(`SELECT * FROM daily_site_stats WHERE date = ? LIMIT 1`) - err := db.Get(stats, query, date.Format("2006-01-02")) + query := db.Rebind(`SELECT * FROM daily_site_stats WHERE site_id = ? AND date = ? LIMIT 1`) + err := db.Get(stats, query, siteID, date.Format("2006-01-02")) if err != nil && err == sql.ErrNoRows { return nil, ErrNoResults } @@ -18,26 +18,26 @@ func (db *sqlstore) GetSiteStats(date time.Time) (*models.SiteStats, error) { } func (db *sqlstore) InsertSiteStats(s *models.SiteStats) error { - query := db.Rebind(`INSERT INTO daily_site_stats(visitors, sessions, pageviews, bounce_rate, avg_duration, known_durations, date) VALUES(?, ?, ?, ?, ?, ?, ?)`) - _, err := db.Exec(query, s.Visitors, s.Sessions, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Date.Format("2006-01-02")) + query := db.Rebind(`INSERT INTO daily_site_stats(site_id, visitors, sessions, pageviews, bounce_rate, avg_duration, known_durations, date) VALUES(?, ?, ?, ?, ?, ?, ?)`) + _, err := db.Exec(query, s.SiteID, s.Visitors, s.Sessions, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Date.Format("2006-01-02")) return err } func (db *sqlstore) UpdateSiteStats(s *models.SiteStats) error { - query := db.Rebind(`UPDATE daily_site_stats SET visitors = ?, sessions = ?, pageviews = ?, bounce_rate = ROUND(?, 4), avg_duration = ROUND(?, 4), known_durations = ? WHERE date = ?`) - _, err := db.Exec(query, s.Visitors, s.Sessions, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.Date.Format("2006-01-02")) + query := db.Rebind(`UPDATE daily_site_stats SET visitors = ?, sessions = ?, pageviews = ?, bounce_rate = ROUND(?, 4), avg_duration = ROUND(?, 4), known_durations = ? WHERE site_id = ? AND date = ?`) + _, err := db.Exec(query, s.Visitors, s.Sessions, s.Pageviews, s.BounceRate, s.AvgDuration, s.KnownDurations, s.SiteID, s.Date.Format("2006-01-02")) return err } -func (db *sqlstore) GetSiteStatsPerDay(startDate time.Time, endDate time.Time) ([]*models.SiteStats, error) { +func (db *sqlstore) GetSiteStatsPerDay(siteID int64, startDate time.Time, endDate time.Time) ([]*models.SiteStats, error) { results := []*models.SiteStats{} - sql := `SELECT * FROM daily_site_stats WHERE date >= ? AND date <= ?` + sql := `SELECT * FROM daily_site_stats WHERE site_id = ? AND date >= ? AND date <= ?` query := db.Rebind(sql) - err := db.Select(&results, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + err := db.Select(&results, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return results, err } -func (db *sqlstore) GetAggregatedSiteStats(startDate time.Time, endDate time.Time) (*models.SiteStats, error) { +func (db *sqlstore) GetAggregatedSiteStats(siteID int64, startDate time.Time, endDate time.Time) (*models.SiteStats, error) { stats := &models.SiteStats{} query := db.Rebind(`SELECT COALESCE(SUM(pageviews), 0) AS pageviews, @@ -45,8 +45,8 @@ func (db *sqlstore) GetAggregatedSiteStats(startDate time.Time, endDate time.Tim COALESCE(SUM(sessions), 0) AS sessions, COALESCE(ROUND(SUM(pageviews*avg_duration) / NULLIF(SUM(pageviews), 0), 4), 0.00) AS avg_duration, COALESCE(ROUND(SUM(sessions*bounce_rate) / NULLIF(SUM(sessions), 0), 4), 0.00) AS bounce_rate - FROM daily_site_stats WHERE date >= ? AND date <= ? LIMIT 1`) - err := db.Get(stats, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + FROM daily_site_stats WHERE site_id = ? AND date >= ? AND date <= ? LIMIT 1`) + err := db.Get(stats, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) if err != nil && err == sql.ErrNoRows { return nil, ErrNoResults } @@ -54,50 +54,58 @@ func (db *sqlstore) GetAggregatedSiteStats(startDate time.Time, endDate time.Tim return stats, err } -func (db *sqlstore) GetTotalSiteViews(startDate time.Time, endDate time.Time) (int, error) { - sql := `SELECT COALESCE(SUM(pageviews), 0) FROM daily_site_stats WHERE date >= ? AND date <= ?` +func (db *sqlstore) GetTotalSiteViews(siteID int64, startDate time.Time, endDate time.Time) (int64, error) { + sql := `SELECT COALESCE(SUM(pageviews), 0) FROM daily_site_stats WHERE site_id = ? AND date >= ? AND date <= ?` query := db.Rebind(sql) - var total int - err := db.Get(&total, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + var total int64 + err := db.Get(&total, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return total, err } -func (db *sqlstore) GetTotalSiteVisitors(startDate time.Time, endDate time.Time) (int, error) { - sql := `SELECT COALESCE(SUM(visitors), 0) FROM daily_site_stats WHERE date >= ? AND date <= ?` +func (db *sqlstore) GetTotalSiteVisitors(siteID int64, startDate time.Time, endDate time.Time) (int64, error) { + sql := `SELECT COALESCE(SUM(visitors), 0) FROM daily_site_stats WHERE site_id = ? AND date >= ? AND date <= ?` query := db.Rebind(sql) - var total int - err := db.Get(&total, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + var total int64 + err := db.Get(&total, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return total, err } -func (db *sqlstore) GetTotalSiteSessions(startDate time.Time, endDate time.Time) (int, error) { - sql := `SELECT COALESCE(SUM(sessions), 0) FROM daily_site_stats WHERE date >= ? AND date <= ?` +func (db *sqlstore) GetTotalSiteSessions(siteID int64, startDate time.Time, endDate time.Time) (int64, error) { + sql := `SELECT COALESCE(SUM(sessions), 0) FROM daily_site_stats WHERE site_id = ? AND date >= ? AND date <= ?` query := db.Rebind(sql) - var total int - err := db.Get(&total, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + var total int64 + err := db.Get(&total, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return total, err } -func (db *sqlstore) GetAverageSiteDuration(startDate time.Time, endDate time.Time) (float64, error) { - sql := `SELECT COALESCE(ROUND(SUM(pageviews*avg_duration)/SUM(pageviews), 4), 0.00) FROM daily_site_stats WHERE date >= ? AND date <= ?` +func (db *sqlstore) GetAverageSiteDuration(siteID int64, startDate time.Time, endDate time.Time) (float64, error) { + sql := `SELECT COALESCE(ROUND(SUM(pageviews*avg_duration)/SUM(pageviews), 4), 0.00) FROM daily_site_stats WHERE site_id = ? AND date >= ? AND date <= ?` query := db.Rebind(sql) var total float64 - err := db.Get(&total, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + err := db.Get(&total, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return total, err } -func (db *sqlstore) GetAverageSiteBounceRate(startDate time.Time, endDate time.Time) (float64, error) { - sql := `SELECT COALESCE(ROUND(SUM(sessions*bounce_rate)/SUM(sessions), 4), 0.00) FROM daily_site_stats WHERE date >= ? AND date <= ?` +func (db *sqlstore) GetAverageSiteBounceRate(siteID int64, startDate time.Time, endDate time.Time) (float64, error) { + sql := `SELECT COALESCE(ROUND(SUM(sessions*bounce_rate)/SUM(sessions), 4), 0.00) FROM daily_site_stats WHERE site_id = ? AND date >= ? AND date <= ?` query := db.Rebind(sql) var total float64 - err := db.Get(&total, query, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + err := db.Get(&total, query, siteID, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) return total, err } -func (db *sqlstore) GetRealtimeVisitorCount() (int, error) { - sql := `SELECT COUNT(*) FROM pageviews WHERE ( duration = 0 OR is_bounce = TRUE ) AND timestamp > ?` +func (db *sqlstore) GetRealtimeVisitorCount(siteID int64) (int64, error) { + var siteTrackingID string + var total int64 + if err := db.Get(&siteTrackingID, db.Rebind(`SELECT tracking_id FROM sites WHERE id = ?`), siteID); err != nil && err != sql.ErrNoRows { + return 0, err + } + + sql := `SELECT COUNT(*) FROM pageviews p WHERE site_tracking_id = ? AND ( duration = 0 OR is_bounce = TRUE) AND timestamp > ?` query := db.Rebind(sql) - var total int - err := db.Get(&total, query, time.Now().Add(-5*time.Minute)) - return total, err + if err := db.Get(&total, query, siteTrackingID, time.Now().Add(-5*time.Minute)); err != nil { + return 0, err + } + + return total, nil }