mirror of
https://github.com/wahyd4/golink.git
synced 2026-08-08 21:01:05 +10:00
cmd/golink: use html/template when rendering pages
Properly use html/template rather than text/template so that we don't have to worry about escaping data that is passed in to the templates. Also move the success page into a template for both better rendering and consistency. Finally, this includes some tailwind changes that apparently got missed in previous commits. Change-Id: Ic658ab940888c44483501e33699da9021be18ecf
This commit is contained in:
@@ -10,7 +10,7 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
texttemplate "text/template"
|
||||
"time"
|
||||
|
||||
"tailscale.com/client/tailscale"
|
||||
@@ -184,6 +184,9 @@ var homeTmpl *template.Template
|
||||
// helpTmpl is the template used by the http://go/.help page
|
||||
var helpTmpl *template.Template
|
||||
|
||||
// successTmpl is the template used when a link is successfully created or updated.
|
||||
var successTmpl *template.Template
|
||||
|
||||
type visitData struct {
|
||||
Short string
|
||||
NumClicks int
|
||||
@@ -198,6 +201,7 @@ type homeData struct {
|
||||
func init() {
|
||||
homeTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/home.html"))
|
||||
helpTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/help.html"))
|
||||
successTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/success.html"))
|
||||
}
|
||||
|
||||
// initStats initializes the in-memory stats counter with counts from db.
|
||||
@@ -244,7 +248,7 @@ func serveHome(w http.ResponseWriter, short string) {
|
||||
stats.mu.Lock()
|
||||
for short, numClicks := range stats.clicks {
|
||||
clicks = append(clicks, visitData{
|
||||
Short: html.EscapeString(short),
|
||||
Short: short,
|
||||
NumClicks: numClicks,
|
||||
})
|
||||
}
|
||||
@@ -261,7 +265,7 @@ func serveHome(w http.ResponseWriter, short string) {
|
||||
})
|
||||
|
||||
homeTmpl.Execute(w, homeData{
|
||||
Short: html.EscapeString(short),
|
||||
Short: short,
|
||||
Clicks: clicks,
|
||||
})
|
||||
}
|
||||
@@ -339,7 +343,7 @@ type expandEnv struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
var expandFuncMap = template.FuncMap{
|
||||
var expandFuncMap = texttemplate.FuncMap{
|
||||
"PathEscape": url.PathEscape,
|
||||
"QueryEscape": url.QueryEscape,
|
||||
}
|
||||
@@ -358,7 +362,7 @@ func expandLink(long string, env expandEnv) (string, error) {
|
||||
long += "{{with .Path}}/{{.}}{{end}}"
|
||||
}
|
||||
}
|
||||
tmpl, err := template.New("").Funcs(expandFuncMap).Parse(long)
|
||||
tmpl, err := texttemplate.New("").Funcs(expandFuncMap).Parse(long)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -419,7 +423,7 @@ func serveSave(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "short may only contain letters, numbers, dash, and period", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if _, err := template.New("").Funcs(expandFuncMap).Parse(long); err != nil {
|
||||
if _, err := texttemplate.New("").Funcs(expandFuncMap).Parse(long); err != nil {
|
||||
http.Error(w, fmt.Sprintf("long contains an invalid template: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@@ -461,7 +465,7 @@ func serveSave(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if strings.Contains(strings.ToLower(r.Header.Get("Accept")), "text/html") {
|
||||
fmt.Fprintf(w, "<h1>saved</h1>made <a href='http://go/%s'>http://go/%s</a>", html.EscapeString(short), html.EscapeString(short))
|
||||
successTmpl.Execute(w, homeData{Short: short})
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(link)
|
||||
|
||||
+9
-26
@@ -672,7 +672,7 @@ select {
|
||||
}
|
||||
|
||||
.prose {
|
||||
color: #333;
|
||||
color: var(--tw-prose-body);
|
||||
max-width: 65ch;
|
||||
}
|
||||
|
||||
@@ -685,15 +685,11 @@ select {
|
||||
}
|
||||
|
||||
.prose :where(a):not(:where([class~="not-prose"] *)) {
|
||||
color: #3182ce;
|
||||
color: var(--tw-prose-links);
|
||||
text-decoration: underline;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.prose :where(a):not(:where([class~="not-prose"] *)):hover {
|
||||
color: #2c5282;
|
||||
}
|
||||
|
||||
.prose :where(strong):not(:where([class~="not-prose"] *)) {
|
||||
color: var(--tw-prose-bold);
|
||||
font-weight: 600;
|
||||
@@ -1138,18 +1134,14 @@ select {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.max-w-4xl {
|
||||
max-width: 56rem;
|
||||
.max-w-5xl {
|
||||
max-width: 64rem;
|
||||
}
|
||||
|
||||
.max-w-full {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.max-w-5xl {
|
||||
max-width: 64rem;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1 1 0%;
|
||||
}
|
||||
@@ -1290,16 +1282,16 @@ select {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
@@ -1327,15 +1319,6 @@ select {
|
||||
color: rgb(159 153 149 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-blue-200 {
|
||||
color: rgba(43, 123, 185, 0.15);
|
||||
}
|
||||
|
||||
.text-blue-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(74 125 221 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-blue-600 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(77 120 200 / var(--tw-text-opacity));
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{{ define "main" }}
|
||||
<h2 class="text-xl font-bold pb-2">Success</h2>
|
||||
|
||||
<p><a class="text-blue-600 hover:underline" href="http://go/{{.Short}}">go/{{.Short}}</a> has been saved.</p>
|
||||
{{ end }}
|
||||
Reference in New Issue
Block a user