mirror of
https://github.com/writeas/htmlhouse
synced 2025-07-18 21:08:16 +00:00
Add post stats page
This commit is contained in:
parent
980da45b4f
commit
8c5afe3945
1
app.go
1
app.go
@ -59,6 +59,7 @@ func (app *app) initRouter() {
|
||||
|
||||
app.router.HandleFunc("/", app.handler(getEditor)).Methods("GET").Name("index")
|
||||
app.router.HandleFunc("/edit/{house:[A-Za-z0-9.-]{8}}.html", app.handler(getEditor)).Methods("GET").Name("edit")
|
||||
app.router.HandleFunc("/stats/{house:[A-Za-z0-9.-]{8}}.html", app.handler(viewHouseStats)).Methods("GET").Name("stats")
|
||||
app.router.HandleFunc("/{house:[A-Za-z0-9.-]{8}}.html", app.handler(getHouse)).Methods("GET").Name("get")
|
||||
app.router.PathPrefix("/").Handler(http.FileServer(http.Dir(app.cfg.StaticDir)))
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/writeas/impart"
|
||||
"github.com/writeas/nerds/store"
|
||||
"github.com/writeas/web-core/bots"
|
||||
)
|
||||
|
||||
func createHouse(app *app, w http.ResponseWriter, r *http.Request) error {
|
||||
@ -66,6 +68,21 @@ func renovateHouse(app *app, w http.ResponseWriter, r *http.Request) error {
|
||||
return impart.WriteSuccess(w, resUser, http.StatusOK)
|
||||
}
|
||||
|
||||
func getHouseStats(app *app, houseID string) (*time.Time, int64, error) {
|
||||
var created time.Time
|
||||
var views int64
|
||||
err := app.db.QueryRow("SELECT created, view_count FROM houses WHERE id = ?", houseID).Scan(&created, &views)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
return nil, 0, impart.HTTPError{http.StatusNotFound, "Return to sender. Address unknown."}
|
||||
case err != nil:
|
||||
fmt.Printf("Couldn't fetch: %v\n", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return &created, views, nil
|
||||
}
|
||||
|
||||
func getHouseHTML(app *app, houseID string) (string, error) {
|
||||
var html string
|
||||
err := app.db.QueryRow("SELECT html FROM houses WHERE id = ?", houseID).Scan(&html)
|
||||
@ -127,6 +144,46 @@ func getHouse(app *app, w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method != "HEAD" && !bots.IsBot(r.UserAgent()) {
|
||||
app.db.Exec("UPDATE houses SET view_count = view_count + 1 WHERE id = ?", houseID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func viewHouseStats(app *app, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
houseID := vars["house"]
|
||||
|
||||
created, views, err := getHouseStats(app, houseID)
|
||||
if err != nil {
|
||||
if err, ok := err.(impart.HTTPError); ok {
|
||||
if err.Status == http.StatusNotFound {
|
||||
// TODO: put this logic in one place (shared with getHouse func)
|
||||
page, err := ioutil.ReadFile(app.cfg.StaticDir + "/404.html")
|
||||
if err != nil {
|
||||
page = []byte("<!DOCTYPE html><html><body>HTMLlot.</body></html>")
|
||||
}
|
||||
fmt.Fprintf(w, "%s", page)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
viewsLbl := "view"
|
||||
if views != 1 {
|
||||
viewsLbl = "views"
|
||||
}
|
||||
app.templates["stats"].ExecuteTemplate(w, "stats", &HouseStats{
|
||||
ID: houseID,
|
||||
Stats: []Stat{
|
||||
Stat{
|
||||
Data: fmt.Sprintf("%d", views),
|
||||
Label: viewsLbl,
|
||||
},
|
||||
Stat{
|
||||
Data: created.Format(time.RFC1123),
|
||||
Label: "created",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
13
models.go
Normal file
13
models.go
Normal file
@ -0,0 +1,13 @@
|
||||
package htmlhouse
|
||||
|
||||
type (
|
||||
HouseStats struct {
|
||||
ID string
|
||||
Stats []Stat
|
||||
}
|
||||
|
||||
Stat struct {
|
||||
Data string
|
||||
Label string
|
||||
}
|
||||
)
|
@ -288,6 +288,22 @@ code {
|
||||
max-width: 50em;
|
||||
}
|
||||
|
||||
.stat {
|
||||
display: inline-block;
|
||||
font-size: 1.2em;
|
||||
&+.stat {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.num {
|
||||
font-weight: bold;
|
||||
}
|
||||
.label {
|
||||
font-size: 0.9em;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 1280px) {
|
||||
body#promo {
|
||||
div.heading {
|
||||
|
@ -20,4 +20,5 @@ func (app *app) initTemplates() {
|
||||
|
||||
// Initialize dynamic pages
|
||||
initTemplate(app, "editor")
|
||||
initTemplate(app, "stats")
|
||||
}
|
||||
|
56
templates/stats.html
Normal file
56
templates/stats.html
Normal file
@ -0,0 +1,56 @@
|
||||
{{define "stats"}}<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>{{.ID}}.html stats | HTMLhouse</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/house.css" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/png" href="/img/favicon-chrome.png" sizes="192x192">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#888888" />
|
||||
|
||||
<meta name="description" content="Page stats for {{.ID}}.html">
|
||||
<meta name="application-name" content="HTMLhouse">
|
||||
<meta name="application-url" content="https://html.house">
|
||||
<meta itemprop="name" content="{{.ID}}.html stats | HTMLhouse">
|
||||
<meta itemprop="description" content="Page stats for {{.ID}}.html">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{.ID}}.html stats | HTMLhouse">
|
||||
<meta name="twitter:description" content="Page stats for {{.ID}}.html">
|
||||
<meta property="og:title" content="{{.ID}}.html stats | HTMLhouse" />
|
||||
<meta property="og:site_name" content="HTMLhouse" />
|
||||
<meta property="og:type" content="object" />
|
||||
<meta property="og:url" content="https://html.house/stats/{{.ID}}.html" />
|
||||
<meta property="og:description" content="Page stats for {{.ID}}.html" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>{{.ID}}.html stats</h1>
|
||||
<nav>
|
||||
<a class="home" href="/"><⌂/></a>
|
||||
</nav>
|
||||
<a href="/{{.ID}}.html">view</a>
|
||||
<a href="/edit/{{.ID}}.html">edit</a>
|
||||
</header>
|
||||
|
||||
<div id="wrapper">
|
||||
{{ range .Stats }}<div class="stat">
|
||||
<span class="num">{{.Data}}</span>
|
||||
<span class="label">{{.Label}}</span>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-47877053-8', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>{{end}}
|
Loading…
Reference in New Issue
Block a user