From fded071f7aa49a39d1f1107e5c48d0bc27fb7884 Mon Sep 17 00:00:00 2001 From: Danny van Kooten Date: Sat, 26 Nov 2016 17:19:15 +0100 Subject: [PATCH] remove 'period' query parameter in favor of before & after --- api/api.go | 46 +++++++++++++++++++++---------- api/browsers.go | 11 ++++---- api/countries.go | 11 ++++---- api/languages.go | 11 ++++---- api/pageviews.go | 25 ++++++++--------- api/screen-resolutions.go | 10 +++---- api/visits.go | 15 +++++----- assets/js/components/Graph.js | 8 ++++-- assets/js/components/Pageviews.js | 8 ++++-- assets/js/components/Table.js | 6 +++- 10 files changed, 89 insertions(+), 62 deletions(-) diff --git a/api/api.go b/api/api.go index fdcda34..e0fe3a4 100644 --- a/api/api.go +++ b/api/api.go @@ -23,25 +23,34 @@ func checkError(err error) { } } -func fillDatapoints(days int, points []Datapoint) []Datapoint { +func fillDatapoints(start int64, end int64, points []Datapoint) []Datapoint { + // be smart about received timestamps + if start > end { + tmp := end + end = start + start = tmp + } - now := time.Now().AddDate(0, 0, 1) - start := now.AddDate(0, 0, -days) - newPoints := make([]Datapoint, days) + startTime := time.Unix(start, 0) + endTime := time.Unix(end, 0) + newPoints := make([]Datapoint, 0) - for i := 0; i < days; i++ { - newPoints[i] = Datapoint{ + for startTime.Before(endTime) { + point := Datapoint{ Count: 0, - Label: start.AddDate(0, 0, i).Format("2006-01-02"), + Label: startTime.Format("2006-01-02"), } for j, p := range points { - if p.Label == newPoints[i].Label { - newPoints[i].Count = p.Count + if p.Label == point.Label { + point.Count = p.Count points[j] = points[len(points)-1] break } } + + newPoints = append(newPoints, point) + startTime = startTime.AddDate(0, 0, 1) } return newPoints @@ -56,10 +65,19 @@ func getRequestedLimit(r *http.Request) int { return limit } -func getRequestedPeriod(r *http.Request) int { - period, err := strconv.Atoi(r.URL.Query().Get("period")) - if err != nil || period == 0 { - period = defaultPeriod +func getRequestedPeriods(r *http.Request) (int64, int64) { + var before, after int64 + var err error + + before, err = strconv.ParseInt(r.URL.Query().Get("before"), 10, 64) + if err != nil || before == 0 { + before = time.Now().Unix() } - return period + + after, err = strconv.ParseInt(r.URL.Query().Get("after"), 10, 64) + if err != nil || before == 0 { + after = time.Now().AddDate(0, 0, -7).Unix() + } + + return before, after } diff --git a/api/browsers.go b/api/browsers.go index 1cfb5d8..fddc00b 100644 --- a/api/browsers.go +++ b/api/browsers.go @@ -8,18 +8,19 @@ import ( // URL: /api/browsers var GetBrowsersHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) + before, after := getRequestedPeriods(r) // get total stmt, err := core.DB.Prepare(` SELECT COUNT(DISTINCT(ip_address)) FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? + `) checkError(err) defer stmt.Close() var total float32 - stmt.QueryRow(period).Scan(&total) + stmt.QueryRow(before, after).Scan(&total) // get rows stmt, err = core.DB.Prepare(` @@ -27,13 +28,13 @@ var GetBrowsersHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Re browser_name, COUNT(DISTINCT(ip_address)) AS count FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) AND browser_name IS NOT NULL + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? AND browser_name IS NOT NULL GROUP BY browser_name ORDER BY count DESC LIMIT ?`) checkError(err) defer stmt.Close() - rows, err := stmt.Query(period, defaultLimit) + rows, err := stmt.Query(before, after, defaultLimit) checkError(err) defer rows.Close() diff --git a/api/countries.go b/api/countries.go index 93582b2..eca1d98 100644 --- a/api/countries.go +++ b/api/countries.go @@ -8,18 +8,19 @@ import ( // URL: /api/countries var GetCountriesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) + before, after := getRequestedPeriods(r) // get total stmt, err := core.DB.Prepare(` SELECT COUNT(DISTINCT(ip_address)) FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? + `) checkError(err) defer stmt.Close() var total float32 - stmt.QueryRow(period).Scan(&total) + stmt.QueryRow(before, after).Scan(&total) // get rows stmt, err = core.DB.Prepare(` @@ -27,13 +28,13 @@ var GetCountriesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.R country, COUNT(DISTINCT(ip_address)) AS count FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) AND country IS NOT NULL + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? AND country IS NOT NULL GROUP BY country ORDER BY count DESC LIMIT ?`) checkError(err) defer stmt.Close() - rows, err := stmt.Query(period, defaultLimit) + rows, err := stmt.Query(before, after, defaultLimit) checkError(err) defer rows.Close() diff --git a/api/languages.go b/api/languages.go index 89d33d7..5f3a6e2 100644 --- a/api/languages.go +++ b/api/languages.go @@ -8,31 +8,32 @@ import ( // URL: /api/languages var GetLanguagesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) + before, after := getRequestedPeriods(r) stmt, err := core.DB.Prepare(` SELECT COUNT(DISTINCT(ip_address)) FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? + `) checkError(err) defer stmt.Close() var total float32 - stmt.QueryRow(period).Scan(&total) + stmt.QueryRow(before, after).Scan(&total) stmt, err = core.DB.Prepare(` SELECT browser_language, COUNT(DISTINCT(ip_address)) AS count FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? GROUP BY browser_language ORDER BY count DESC LIMIT ?`) checkError(err) defer stmt.Close() - rows, err := stmt.Query(period, defaultLimit) + rows, err := stmt.Query(before, after, defaultLimit) checkError(err) defer rows.Close() diff --git a/api/pageviews.go b/api/pageviews.go index 6e3f12f..0a7f147 100644 --- a/api/pageviews.go +++ b/api/pageviews.go @@ -9,21 +9,20 @@ import ( // URL: /api/pageviews var GetPageviewsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) - + before, after := getRequestedPeriods(r) stmt, err := core.DB.Prepare(`SELECT path, COUNT(ip_address) AS pageviews, COUNT(DISTINCT(ip_address)) AS pageviews_unique FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? GROUP BY path - ORDER BY pageviews DESC + ORDER BY pageviews DESC LIMIT ?`) checkError(err) defer stmt.Close() - rows, err := stmt.Query(period, defaultLimit) + rows, err := stmt.Query(before, after, defaultLimit) checkError(err) defer rows.Close() @@ -45,14 +44,13 @@ var GetPageviewsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.R // URL: /api/pageviews/count var GetPageviewsCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) - stmt, err := core.DB.Prepare(`SELECT COUNT(*) FROM visits WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? day) AND timestamp <= CURRENT_TIMESTAMP`) - + before, after := getRequestedPeriods(r) + stmt, err := core.DB.Prepare(`SELECT COUNT(*) FROM visits WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?`) checkError(err) defer stmt.Close() var result int - stmt.QueryRow(period).Scan(&result) + stmt.QueryRow(before, after).Scan(&result) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(result) @@ -60,17 +58,16 @@ var GetPageviewsCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *h // URL: /api/pageviews/count/day var GetPageviewsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) - + before, after := getRequestedPeriods(r) stmt, err := core.DB.Prepare(`SELECT COUNT(*) AS count, DATE_FORMAT(timestamp, '%Y-%m-%d') AS date_group FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? GROUP BY date_group`) checkError(err) defer stmt.Close() - rows, err := stmt.Query(period) + rows, err := stmt.Query(before, after) checkError(err) defer rows.Close() @@ -82,7 +79,7 @@ var GetPageviewsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r results = append(results, v) } - results = fillDatapoints(period, results) + results = fillDatapoints(before, after, results) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(results) diff --git a/api/screen-resolutions.go b/api/screen-resolutions.go index 91513b0..97b31c4 100644 --- a/api/screen-resolutions.go +++ b/api/screen-resolutions.go @@ -8,18 +8,18 @@ import ( // URL: /api/screen-resolutions var GetScreenResolutionsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) + before, after := getRequestedPeriods(r) // get total stmt, err := core.DB.Prepare(` SELECT COUNT(DISTINCT(ip_address)) FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?`) checkError(err) defer stmt.Close() var total float32 - stmt.QueryRow(period).Scan(&total) + stmt.QueryRow(before, after).Scan(&total) // get rows stmt, err = core.DB.Prepare(` @@ -27,13 +27,13 @@ var GetScreenResolutionsHandler = http.HandlerFunc(func(w http.ResponseWriter, r screen_resolution, COUNT(DISTINCT(ip_address)) AS count FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? GROUP BY screen_resolution ORDER BY count DESC LIMIT ?`) checkError(err) defer stmt.Close() - rows, err := stmt.Query(period, defaultLimit) + rows, err := stmt.Query(before, after, defaultLimit) checkError(err) defer rows.Close() diff --git a/api/visits.go b/api/visits.go index 8c93724..5e5be79 100644 --- a/api/visits.go +++ b/api/visits.go @@ -47,14 +47,14 @@ var GetVisitsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Requ // URL: /api/visits/count var GetVisitsCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - period := getRequestedPeriod(r) - stmt, err := core.DB.Prepare(`SELECT COUNT(DISTINCT(ip_address)) FROM visits WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? day) AND timestamp <= CURRENT_TIMESTAMP`) + before, after := getRequestedPeriods(r) + stmt, err := core.DB.Prepare(`SELECT COUNT(DISTINCT(ip_address)) FROM visits WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?`) checkError(err) defer stmt.Close() var result int - stmt.QueryRow(period).Scan(&result) + stmt.QueryRow(before, after).Scan(&result) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(result) @@ -74,13 +74,13 @@ var GetVisitsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *h stmt, err := core.DB.Prepare(`SELECT COUNT(DISTINCT(ip_address)) AS count, DATE_FORMAT(timestamp, '%Y-%m-%d') AS date_group FROM visits - WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) + WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ? GROUP BY date_group`) checkError(err) defer stmt.Close() - period := getRequestedPeriod(r) - rows, err := stmt.Query(period) + before, after := getRequestedPeriods(r) + rows, err := stmt.Query(before, after) checkError(err) results := make([]Datapoint, 0) @@ -92,8 +92,7 @@ var GetVisitsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *h results = append(results, v) } - results = fillDatapoints(period, results) - + results = fillDatapoints(before, after, results) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(results) }) diff --git a/assets/js/components/Graph.js b/assets/js/components/Graph.js index ebf6589..85eb332 100644 --- a/assets/js/components/Graph.js +++ b/assets/js/components/Graph.js @@ -2,6 +2,7 @@ import { h, render, Component } from 'preact'; import Chart from 'chart.js' +const dayInSeconds = 60 * 60 * 24; Chart.defaults.global.tooltips.xPadding = 10; Chart.defaults.global.tooltips.yPadding = 10; @@ -60,8 +61,11 @@ class Graph extends Component { } fetchData(period) { + const before = Math.round((+new Date() ) / 1000); + const after = before - ( period * dayInSeconds ); + // fetch visitor data - fetch('/api/visits/count/day?period=' + period, { + fetch(`/api/visits/count/day?before=${before}&after=${after}`, { credentials: 'include' }).then((r) => { if( r.ok ) { @@ -74,7 +78,7 @@ class Graph extends Component { }); // fetch pageview data - fetch('/api/pageviews/count/day?period=' + period, { + fetch(`/api/pageviews/count/day?before=${before}&after=${after}`, { credentials: 'include' }).then((r) => { if( r.ok ) { diff --git a/assets/js/components/Pageviews.js b/assets/js/components/Pageviews.js index 608b39f..cf0e6fc 100644 --- a/assets/js/components/Pageviews.js +++ b/assets/js/components/Pageviews.js @@ -1,6 +1,7 @@ 'use strict'; import { h, render, Component } from 'preact'; +const dayInSeconds = 60 * 60 * 24; class Pageviews extends Component { @@ -21,7 +22,10 @@ class Pageviews extends Component { } fetchRecords(period) { - return fetch('/api/pageviews?period=' + period, { + const before = Math.round((+new Date() ) / 1000); + const after = before - ( period * dayInSeconds ); + + return fetch(`/api/pageviews?before=${before}&after=${after}`, { credentials: 'include' }).then((r) => { if( r.ok ) { @@ -31,8 +35,6 @@ class Pageviews extends Component { throw new Error(); }).then((data) => { this.setState({ records: data }) - }).catch((e) => { - }); } diff --git a/assets/js/components/Table.js b/assets/js/components/Table.js index cfd06fb..1964f4e 100644 --- a/assets/js/components/Table.js +++ b/assets/js/components/Table.js @@ -1,6 +1,7 @@ 'use strict'; import { h, render, Component } from 'preact'; +const dayInSeconds = 60 * 60 * 24; class Table extends Component { @@ -33,7 +34,10 @@ class Table extends Component { } fetchRecords(period) { - return fetch('/api/'+this.props.endpoint+'?period=' + period, { + const before = Math.round((+new Date() ) / 1000); + const after = before - ( period * dayInSeconds ); + + return fetch(`/api/${this.props.endpoint}?before=${before}&after=${after}`, { credentials: 'include' }).then((r) => { if( r.ok ) {