diff options
author | Felix Hanley <felix@userspace.com.au> | 2020-03-16 11:24:04 +0000 |
---|---|---|
committer | Felix Hanley <felix@userspace.com.au> | 2020-03-16 11:24:04 +0000 |
commit | 2248b4d7e1d083a103e94985ee4b373d689ae0e8 (patch) | |
tree | 20a3f12a7d793ddadd5225e3e0cb44fa738682a5 | |
parent | c16f2a68eeb6550743354245f95605a141c1d020 (diff) | |
download | sws-2248b4d7e1d083a103e94985ee4b373d689ae0e8.tar.gz sws-2248b4d7e1d083a103e94985ee4b373d689ae0e8.tar.bz2 |
Update graph displays and supporting helpers
-rw-r--r-- | browser_set.go | 7 | ||||
-rw-r--r-- | cmd/server/helpers.go | 5 | ||||
-rw-r--r-- | cmd/server/hits.go | 3 | ||||
-rw-r--r-- | cmd/server/routes.go | 14 | ||||
-rw-r--r-- | country.go | 7 | ||||
-rw-r--r-- | page_set.go | 22 | ||||
-rw-r--r-- | referrer.go | 7 | ||||
-rw-r--r-- | static/default.css | 31 | ||||
-rw-r--r-- | tmpl/site.tmpl | 59 |
9 files changed, 110 insertions, 45 deletions
diff --git a/browser_set.go b/browser_set.go index b53ddb7..4d3107c 100644 --- a/browser_set.go +++ b/browser_set.go @@ -76,6 +76,13 @@ func (bs BrowserSet) YMax() int { } return max } +func (bs BrowserSet) YSum() int { + sum := 0 + for _, b := range bs { + sum += b.hitSet.Count() + } + return sum +} func (bs BrowserSet) XSeries() []*Browser { return bs } diff --git a/cmd/server/helpers.go b/cmd/server/helpers.go index 01552b2..6c498e5 100644 --- a/cmd/server/helpers.go +++ b/cmd/server/helpers.go @@ -3,6 +3,7 @@ package main import ( "fmt" "html/template" + "math" "net/http" "strconv" "time" @@ -63,6 +64,10 @@ var funcMap = template.FuncMap{ "percentInv": func(a, b int) float64 { return 100.0 - ((float64(a) / float64(b)) * 100) }, + "round": func(n int, a float64) float64 { + n = n * 10 + return math.Round(a*float64(n)) / float64(n) + }, } func httpError(w http.ResponseWriter, code int, msg string) { diff --git a/cmd/server/hits.go b/cmd/server/hits.go index 27bb11d..e5aaf73 100644 --- a/cmd/server/hits.go +++ b/cmd/server/hits.go @@ -99,12 +99,15 @@ func verifyHit(db sws.SiteGetter, h *sws.Hit) (*sws.Site, error) { return nil, err } if site.Name == h.Host { + debug(h.Host, "equals site name:", site.Name) return site, nil } if strings.Contains(site.Aliases, h.Host) { + debug(h.Host, "equals site alias:", site.Name) return site, nil } if site.AcceptSubdomains && strings.HasSuffix(h.Host, site.Name) { + debug(h.Host, "is subdomain:", site.Name) return site, nil } return nil, fmt.Errorf("invalid host") diff --git a/cmd/server/routes.go b/cmd/server/routes.go index 2b9aaec..5b93713 100644 --- a/cmd/server/routes.go +++ b/cmd/server/routes.go @@ -3,6 +3,8 @@ package main import ( "bytes" "context" + "crypto/sha1" + "fmt" "net/http" "path/filepath" "strconv" @@ -79,11 +81,23 @@ func createRouter(db sws.Store, mmdbPath string) (chi.Router, error) { r.Post(loginURL, handleLogin(db, rndr)) + // Static files r.Get("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { p := strings.TrimPrefix(r.URL.Path, "/") debug("loading", p) if b, err := loadTemplate(p); err == nil { name := filepath.Base(p) + etag := fmt.Sprintf(`"%x"`, sha1.Sum(b)) + + if match := r.Header.Get("If-None-Match"); match != "" { + if strings.Contains(match, etag) { + w.WriteHeader(http.StatusNotModified) + return + } + } + + w.Header().Set("Etag", etag) + w.Header().Set("Cache-Control", "no-cache") http.ServeContent(w, r, name, time.Now(), bytes.NewReader(b)) } })) @@ -67,6 +67,13 @@ func (cs CountrySet) YMax() int { } return max } +func (cs CountrySet) YSum() int { + sum := 0 + for _, c := range cs { + sum += c.hitSet.Count() + } + return sum +} func (cs CountrySet) XSeries() []*Country { return cs } diff --git a/page_set.go b/page_set.go index c9a77ff..9e1b57e 100644 --- a/page_set.go +++ b/page_set.go @@ -42,8 +42,8 @@ func NewPageSet(hs *HitSet) (PageSet, error) { func (ps PageSet) Hits() []*Hit { out := make([]*Hit, 0) - for _, p := range ps { - out = append(out, p.hitSet.Hits()...) + for i := 0; i < len(ps); i++ { + out = append(out, ps[i].hitSet.Hits()...) } return out } @@ -61,9 +61,9 @@ func (ps *PageSet) SortByHits() { } func (ps PageSet) GetPage(s string) *Page { - for _, p := range ps { - if p.Path == s { - return p + for i := 0; i < len(ps); i++ { + if ps[i].Path == s { + return ps[i] } } return nil @@ -71,13 +71,17 @@ func (ps PageSet) GetPage(s string) *Page { func (ps PageSet) YMax() int { max := 0 - for _, p := range ps { - if p.Count() > max { - max = p.Count() + for i := 0; i < len(ps); i++ { + if ps[i].Count() > max { + max = ps[i].Count() } } return max } func (ps PageSet) XSeries() []*Page { - return ps + max := 10 + if len(ps) < 10 { + max = len(ps) + } + return ps[0:max] } diff --git a/referrer.go b/referrer.go index 800b98d..337a6ff 100644 --- a/referrer.go +++ b/referrer.go @@ -104,6 +104,13 @@ func (rs ReferrerSet) YMax() int { } return max } +func (rs ReferrerSet) YSum() int { + sum := 0 + for _, r := range rs { + sum += r.hitSet.Count() + } + return sum +} func (rs ReferrerSet) XSeries() []*Referrer { return rs } diff --git a/static/default.css b/static/default.css index e9b18ee..44dde56 100644 --- a/static/default.css +++ b/static/default.css @@ -56,7 +56,10 @@ ul { main { background-color: #f7f7f7; + display: flex; + flex-wrap: wrap; flex: 1; + justify-content: space-between; padding-left: 16px; padding-right: 16px; position: relative; @@ -78,6 +81,7 @@ main { .site__header { margin-bottom: 1em; + flex: 1 0 100%; } .site__title { margin-bottom: 0; @@ -85,6 +89,7 @@ main { .site__summary { display: inline-block; + flex: 1 0 100%; } .summary { float: left; @@ -122,10 +127,14 @@ main { .panel { background-color: #fff; border: 1px solid #e6e9ed; + flex: 0 1 33%; margin-bottom: .5em; margin-top: .5em; padding: .5em; } +.panel--wide { + flex: 1 0 100%; +} .panel__header { border-bottom: 2px solid #e6e9ed; font-size: 1.75em; @@ -158,10 +167,17 @@ main { top: 0; } +.details__percent { + font-weight: bold; +} + /* Figures */ -.graph { +.figure { + margin: 1em .5em; +} +.figure--graph { } -.map svg { +.figure--map svg { max-width: 100%; max-height: 400px; } @@ -176,13 +192,13 @@ main { .chart.time { flex-direction: row; height: 200px; - padding-top: 2em; - padding-bottom: 2em; + padding-top: 1em; + padding-bottom: 1em; } .chart.vertical { align-items: stretch; flex-direction: row; - height: 100px; + min-height: 200px; padding-top: 2em; padding-bottom: 2em; } @@ -201,6 +217,7 @@ main { .chart.horizontal .slot { margin-top: 1px; margin-bottom: 1px; + max-height: 1.5em; } .chart .slot.midnight { border-left: 1px solid #ddd; @@ -257,10 +274,10 @@ main { bottom: 100%; left: 50%; margin-bottom: .5rem; - margin-left: -2.5rem; + margin-left: -3.5rem; position: absolute; text-align: center; - width: 5rem; + width: 7rem; } .chart.time .slot:after, .chart.vertical .slot:after { diff --git a/tmpl/site.tmpl b/tmpl/site.tmpl index ea72abd..923cbc3 100644 --- a/tmpl/site.tmpl +++ b/tmpl/site.tmpl @@ -41,29 +41,13 @@ </li> {{ end }} -{{ define "browserForList" }} - <li> - <h4 class="name">{{ .Name }}</h4> - <span class="last-seen">{{ .LastSeenAt|datetimeLong }}</span> - <span class="count">{{ .Count }}</span> - </li> -{{ end }} - -{{ define "referrerForList" }} - <li> - <h4 class="name">{{ .Name }}</h4> - <span class="last-seen">{{ .LastSeenAt|datetimeLong }}</span> - <span class="count">{{ .Count }}</span> - </li> -{{ end }} - {{ define "siteView" }} <section class="panel panel--wide"> <header class="panel__header"> <h3 class="panel__title">Hits</h3> </header> {{ if .Hits }} - <figure class="graph"> + <figure class="figure figure--graph"> {{ template "timeBarChart" .Hits }} </figure> {{ else }} @@ -73,10 +57,10 @@ <section class="panel"> <header class="panel__header"> - <h3 class="panel__title">Popular pages</h3> + <h3 class="panel__title">Top 10 pages</h3> </header> {{ if .PageSet }} - <figure class="graph"> + <figure class="figure figure--graph"> {{ template "barChartHorizontal" .PageSet }} </figure> @@ -85,7 +69,7 @@ {{ $pages := .PageSet }} {{ range .PageSet }} {{ template "pageForList" . }} - <figure> + <figure class="figure figure--graph"> {{ $pathHits := $pages.GetPage .Path }} {{ template "timeBarChart" $pathHits }} </figure> @@ -102,9 +86,18 @@ <h3 class="panel__title">Countries</h3> </header> {{ if .CountrySet }} - <figure class="map"> + <figure class="figure figure--map"> {{ template "worldMap" .CountrySet }} </figure> + {{ $sum := .CountrySet.YSum }} + <table class="details details--countries"> + {{ range .CountrySet }} + <tr> + <td class="details__name">{{ .Name }}</td> + <td class="details__count"><span class="details__percent">{{ percent .Count $sum | round 1 }}%</span> ({{ .Count }})</td> + </tr> + {{ end }} + </table> {{ else }} <p>No page views yet</p> {{ end }} @@ -115,14 +108,18 @@ <h3 class="panel__title">Referrers</h3> </header> {{ if .ReferrerSet }} - <figure class="graph"> + <figure class="figure figure--graph"> {{ template "barChart" .ReferrerSet }} </figure> - <ul class="referrers"> + {{ $sum := .ReferrerSet.YSum }} + <table class="details details--referrers"> {{ range .ReferrerSet }} - {{ template "referrerForList" . }} + <tr> + <td class="details__name">{{ .Name }}</td> + <td class="details__count"><span class="details__percent">{{ percent .Count $sum | round 1 }}%</span> ({{ .Count }})</td> + </tr> {{ end }} - </ul> + </table> {{ else }} <p>No referrers yet</p> {{ end }} @@ -133,14 +130,18 @@ <h3 class="panel__title">User agents</h3> </header> {{ if .Browsers }} - <figure class="graph"> + <figure class="figure figure--graph"> {{ template "barChart" .Browsers }} </figure> - <ul class="browsers"> + {{ $sum := .Browsers.YSum }} + <table class="details details--browsers"> {{ range .Browsers }} - {{ template "browserForList" . }} + <tr> + <td class="details__name">{{ .Name }}</td> + <td class="details__count"><span class="details__percent">{{ percent .Count $sum | round 1 }}%</span> ({{ .Count }})</td> + </tr> {{ end }} - </ul> + </table> {{ else }} <p>No browsers visits yet</p> {{ end }} |