remove 'period' query parameter in favor of before & after

This commit is contained in:
Danny van Kooten 2016-11-26 17:19:15 +01:00
parent ab770c6c21
commit fded071f7a
10 changed files with 89 additions and 62 deletions

View File

@ -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) startTime := time.Unix(start, 0)
start := now.AddDate(0, 0, -days) endTime := time.Unix(end, 0)
newPoints := make([]Datapoint, days) newPoints := make([]Datapoint, 0)
for i := 0; i < days; i++ { for startTime.Before(endTime) {
newPoints[i] = Datapoint{ point := Datapoint{
Count: 0, Count: 0,
Label: start.AddDate(0, 0, i).Format("2006-01-02"), Label: startTime.Format("2006-01-02"),
} }
for j, p := range points { for j, p := range points {
if p.Label == newPoints[i].Label { if p.Label == point.Label {
newPoints[i].Count = p.Count point.Count = p.Count
points[j] = points[len(points)-1] points[j] = points[len(points)-1]
break break
} }
} }
newPoints = append(newPoints, point)
startTime = startTime.AddDate(0, 0, 1)
} }
return newPoints return newPoints
@ -56,10 +65,19 @@ func getRequestedLimit(r *http.Request) int {
return limit return limit
} }
func getRequestedPeriod(r *http.Request) int { func getRequestedPeriods(r *http.Request) (int64, int64) {
period, err := strconv.Atoi(r.URL.Query().Get("period")) var before, after int64
if err != nil || period == 0 { var err error
period = defaultPeriod
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
} }

View File

@ -8,18 +8,19 @@ import (
// URL: /api/browsers // URL: /api/browsers
var GetBrowsersHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetBrowsersHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
// get total // get total
stmt, err := core.DB.Prepare(` stmt, err := core.DB.Prepare(`
SELECT SELECT
COUNT(DISTINCT(ip_address)) COUNT(DISTINCT(ip_address))
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
var total float32 var total float32
stmt.QueryRow(period).Scan(&total) stmt.QueryRow(before, after).Scan(&total)
// get rows // get rows
stmt, err = core.DB.Prepare(` stmt, err = core.DB.Prepare(`
@ -27,13 +28,13 @@ var GetBrowsersHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Re
browser_name, browser_name,
COUNT(DISTINCT(ip_address)) AS count COUNT(DISTINCT(ip_address)) AS count
FROM visits 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 GROUP BY browser_name
ORDER BY count DESC ORDER BY count DESC
LIMIT ?`) LIMIT ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
rows, err := stmt.Query(period, defaultLimit) rows, err := stmt.Query(before, after, defaultLimit)
checkError(err) checkError(err)
defer rows.Close() defer rows.Close()

View File

@ -8,18 +8,19 @@ import (
// URL: /api/countries // URL: /api/countries
var GetCountriesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetCountriesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
// get total // get total
stmt, err := core.DB.Prepare(` stmt, err := core.DB.Prepare(`
SELECT SELECT
COUNT(DISTINCT(ip_address)) COUNT(DISTINCT(ip_address))
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
var total float32 var total float32
stmt.QueryRow(period).Scan(&total) stmt.QueryRow(before, after).Scan(&total)
// get rows // get rows
stmt, err = core.DB.Prepare(` stmt, err = core.DB.Prepare(`
@ -27,13 +28,13 @@ var GetCountriesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.R
country, country,
COUNT(DISTINCT(ip_address)) AS count COUNT(DISTINCT(ip_address)) AS count
FROM visits 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 GROUP BY country
ORDER BY count DESC ORDER BY count DESC
LIMIT ?`) LIMIT ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
rows, err := stmt.Query(period, defaultLimit) rows, err := stmt.Query(before, after, defaultLimit)
checkError(err) checkError(err)
defer rows.Close() defer rows.Close()

View File

@ -8,31 +8,32 @@ import (
// URL: /api/languages // URL: /api/languages
var GetLanguagesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetLanguagesHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
stmt, err := core.DB.Prepare(` stmt, err := core.DB.Prepare(`
SELECT SELECT
COUNT(DISTINCT(ip_address)) COUNT(DISTINCT(ip_address))
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
var total float32 var total float32
stmt.QueryRow(period).Scan(&total) stmt.QueryRow(before, after).Scan(&total)
stmt, err = core.DB.Prepare(` stmt, err = core.DB.Prepare(`
SELECT SELECT
browser_language, browser_language,
COUNT(DISTINCT(ip_address)) AS count COUNT(DISTINCT(ip_address)) AS count
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
GROUP BY browser_language GROUP BY browser_language
ORDER BY count DESC ORDER BY count DESC
LIMIT ?`) LIMIT ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
rows, err := stmt.Query(period, defaultLimit) rows, err := stmt.Query(before, after, defaultLimit)
checkError(err) checkError(err)
defer rows.Close() defer rows.Close()

View File

@ -9,21 +9,20 @@ import (
// URL: /api/pageviews // URL: /api/pageviews
var GetPageviewsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetPageviewsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
stmt, err := core.DB.Prepare(`SELECT stmt, err := core.DB.Prepare(`SELECT
path, path,
COUNT(ip_address) AS pageviews, COUNT(ip_address) AS pageviews,
COUNT(DISTINCT(ip_address)) AS pageviews_unique COUNT(DISTINCT(ip_address)) AS pageviews_unique
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
GROUP BY path GROUP BY path
ORDER BY pageviews DESC ORDER BY pageviews DESC
LIMIT ?`) LIMIT ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
rows, err := stmt.Query(period, defaultLimit) rows, err := stmt.Query(before, after, defaultLimit)
checkError(err) checkError(err)
defer rows.Close() defer rows.Close()
@ -45,14 +44,13 @@ var GetPageviewsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.R
// URL: /api/pageviews/count // URL: /api/pageviews/count
var GetPageviewsCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetPageviewsCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
stmt, err := core.DB.Prepare(`SELECT COUNT(*) FROM visits WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? day) AND timestamp <= CURRENT_TIMESTAMP`) stmt, err := core.DB.Prepare(`SELECT COUNT(*) FROM visits WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
var result int var result int
stmt.QueryRow(period).Scan(&result) stmt.QueryRow(before, after).Scan(&result)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result) json.NewEncoder(w).Encode(result)
@ -60,17 +58,16 @@ var GetPageviewsCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *h
// URL: /api/pageviews/count/day // URL: /api/pageviews/count/day
var GetPageviewsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetPageviewsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
stmt, err := core.DB.Prepare(`SELECT stmt, err := core.DB.Prepare(`SELECT
COUNT(*) AS count, DATE_FORMAT(timestamp, '%Y-%m-%d') AS date_group COUNT(*) AS count, DATE_FORMAT(timestamp, '%Y-%m-%d') AS date_group
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
GROUP BY date_group`) GROUP BY date_group`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
rows, err := stmt.Query(period) rows, err := stmt.Query(before, after)
checkError(err) checkError(err)
defer rows.Close() defer rows.Close()
@ -82,7 +79,7 @@ var GetPageviewsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r
results = append(results, v) results = append(results, v)
} }
results = fillDatapoints(period, results) results = fillDatapoints(before, after, results)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(results) json.NewEncoder(w).Encode(results)

View File

@ -8,18 +8,18 @@ import (
// URL: /api/screen-resolutions // URL: /api/screen-resolutions
var GetScreenResolutionsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetScreenResolutionsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
// get total // get total
stmt, err := core.DB.Prepare(` stmt, err := core.DB.Prepare(`
SELECT SELECT
COUNT(DISTINCT(ip_address)) COUNT(DISTINCT(ip_address))
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY)`) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
var total float32 var total float32
stmt.QueryRow(period).Scan(&total) stmt.QueryRow(before, after).Scan(&total)
// get rows // get rows
stmt, err = core.DB.Prepare(` stmt, err = core.DB.Prepare(`
@ -27,13 +27,13 @@ var GetScreenResolutionsHandler = http.HandlerFunc(func(w http.ResponseWriter, r
screen_resolution, screen_resolution,
COUNT(DISTINCT(ip_address)) AS count COUNT(DISTINCT(ip_address)) AS count
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
GROUP BY screen_resolution GROUP BY screen_resolution
ORDER BY count DESC ORDER BY count DESC
LIMIT ?`) LIMIT ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
rows, err := stmt.Query(period, defaultLimit) rows, err := stmt.Query(before, after, defaultLimit)
checkError(err) checkError(err)
defer rows.Close() defer rows.Close()

View File

@ -47,14 +47,14 @@ var GetVisitsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Requ
// URL: /api/visits/count // URL: /api/visits/count
var GetVisitsCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var GetVisitsCountHandler = 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) AND timestamp <= CURRENT_TIMESTAMP`) stmt, err := core.DB.Prepare(`SELECT COUNT(DISTINCT(ip_address)) FROM visits WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
var result int var result int
stmt.QueryRow(period).Scan(&result) stmt.QueryRow(before, after).Scan(&result)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result) 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 stmt, err := core.DB.Prepare(`SELECT
COUNT(DISTINCT(ip_address)) AS count, DATE_FORMAT(timestamp, '%Y-%m-%d') AS date_group COUNT(DISTINCT(ip_address)) AS count, DATE_FORMAT(timestamp, '%Y-%m-%d') AS date_group
FROM visits FROM visits
WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL ? DAY) WHERE UNIX_TIMESTAMP(timestamp) <= ? AND UNIX_TIMESTAMP(timestamp) >= ?
GROUP BY date_group`) GROUP BY date_group`)
checkError(err) checkError(err)
defer stmt.Close() defer stmt.Close()
period := getRequestedPeriod(r) before, after := getRequestedPeriods(r)
rows, err := stmt.Query(period) rows, err := stmt.Query(before, after)
checkError(err) checkError(err)
results := make([]Datapoint, 0) results := make([]Datapoint, 0)
@ -92,8 +92,7 @@ var GetVisitsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *h
results = append(results, v) results = append(results, v)
} }
results = fillDatapoints(period, results) results = fillDatapoints(before, after, results)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(results) json.NewEncoder(w).Encode(results)
}) })

View File

@ -2,6 +2,7 @@
import { h, render, Component } from 'preact'; import { h, render, Component } from 'preact';
import Chart from 'chart.js' import Chart from 'chart.js'
const dayInSeconds = 60 * 60 * 24;
Chart.defaults.global.tooltips.xPadding = 10; Chart.defaults.global.tooltips.xPadding = 10;
Chart.defaults.global.tooltips.yPadding = 10; Chart.defaults.global.tooltips.yPadding = 10;
@ -60,8 +61,11 @@ class Graph extends Component {
} }
fetchData(period) { fetchData(period) {
const before = Math.round((+new Date() ) / 1000);
const after = before - ( period * dayInSeconds );
// fetch visitor data // fetch visitor data
fetch('/api/visits/count/day?period=' + period, { fetch(`/api/visits/count/day?before=${before}&after=${after}`, {
credentials: 'include' credentials: 'include'
}).then((r) => { }).then((r) => {
if( r.ok ) { if( r.ok ) {
@ -74,7 +78,7 @@ class Graph extends Component {
}); });
// fetch pageview data // fetch pageview data
fetch('/api/pageviews/count/day?period=' + period, { fetch(`/api/pageviews/count/day?before=${before}&after=${after}`, {
credentials: 'include' credentials: 'include'
}).then((r) => { }).then((r) => {
if( r.ok ) { if( r.ok ) {

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
import { h, render, Component } from 'preact'; import { h, render, Component } from 'preact';
const dayInSeconds = 60 * 60 * 24;
class Pageviews extends Component { class Pageviews extends Component {
@ -21,7 +22,10 @@ class Pageviews extends Component {
} }
fetchRecords(period) { 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' credentials: 'include'
}).then((r) => { }).then((r) => {
if( r.ok ) { if( r.ok ) {
@ -31,8 +35,6 @@ class Pageviews extends Component {
throw new Error(); throw new Error();
}).then((data) => { }).then((data) => {
this.setState({ records: data }) this.setState({ records: data })
}).catch((e) => {
}); });
} }

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
import { h, render, Component } from 'preact'; import { h, render, Component } from 'preact';
const dayInSeconds = 60 * 60 * 24;
class Table extends Component { class Table extends Component {
@ -33,7 +34,10 @@ class Table extends Component {
} }
fetchRecords(period) { 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' credentials: 'include'
}).then((r) => { }).then((r) => {
if( r.ok ) { if( r.ok ) {