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("/", 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("/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.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)))
|
app.router.PathPrefix("/").Handler(http.FileServer(http.Dir(app.cfg.StaticDir)))
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/writeas/impart"
|
"github.com/writeas/impart"
|
||||||
"github.com/writeas/nerds/store"
|
"github.com/writeas/nerds/store"
|
||||||
|
"github.com/writeas/web-core/bots"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createHouse(app *app, w http.ResponseWriter, r *http.Request) error {
|
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)
|
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) {
|
func getHouseHTML(app *app, houseID string) (string, error) {
|
||||||
var html string
|
var html string
|
||||||
err := app.db.QueryRow("SELECT html FROM houses WHERE id = ?", houseID).Scan(&html)
|
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()) {
|
if r.Method != "HEAD" && !bots.IsBot(r.UserAgent()) {
|
||||||
app.db.Exec("UPDATE houses SET view_count = view_count + 1 WHERE id = ?", houseID)
|
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
|
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;
|
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) {
|
@media all and (min-width: 1280px) {
|
||||||
body#promo {
|
body#promo {
|
||||||
div.heading {
|
div.heading {
|
||||||
|
@ -20,4 +20,5 @@ func (app *app) initTemplates() {
|
|||||||
|
|
||||||
// Initialize dynamic pages
|
// Initialize dynamic pages
|
||||||
initTemplate(app, "editor")
|
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