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)
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
}

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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
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)

View File

@ -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()

View File

@ -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)
})

View File

@ -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 ) {

View File

@ -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) => {
});
}

View File

@ -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 ) {