mirror of https://github.com/jlelse/GoBlog
Show admin links when logged in
This commit is contained in:
parent
bb73d4831c
commit
e74afac829
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
@ -25,20 +26,20 @@ func jwtKey() []byte {
|
||||||
|
|
||||||
func authMiddleware(next http.Handler) http.Handler {
|
func authMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Check if already logged in
|
||||||
|
if loggedIn, ok := r.Context().Value(loggedInKey).(bool); ok && loggedIn {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
// 1. Check BasicAuth
|
// 1. Check BasicAuth
|
||||||
if username, password, ok := r.BasicAuth(); ok && checkCredentials(username, password) {
|
if username, password, ok := r.BasicAuth(); ok && checkCredentials(username, password) {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 2. Check JWT
|
// 2. Check JWT
|
||||||
if tokenCookie, err := r.Cookie("token"); err == nil {
|
if checkAuthToken(r) {
|
||||||
claims := &authClaims{}
|
next.ServeHTTP(w, r)
|
||||||
if tkn, err := jwt.ParseWithClaims(tokenCookie.Value, claims, func(t *jwt.Token) (interface{}, error) {
|
return
|
||||||
return jwtKey(), nil
|
|
||||||
}); err == nil && tkn.Valid && claims.TokenType == "login" && checkUsername(claims.Username) {
|
|
||||||
next.ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 3. Show login form
|
// 3. Show login form
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
@ -50,7 +51,7 @@ func authMiddleware(next http.Handler) http.Handler {
|
||||||
_ = r.ParseForm()
|
_ = r.ParseForm()
|
||||||
b = []byte(r.PostForm.Encode())
|
b = []byte(r.PostForm.Encode())
|
||||||
}
|
}
|
||||||
render(w, templateLogin, &renderData{
|
render(w, r, templateLogin, &renderData{
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
"loginmethod": r.Method,
|
"loginmethod": r.Method,
|
||||||
"loginheaders": base64.StdEncoding.EncodeToString(h),
|
"loginheaders": base64.StdEncoding.EncodeToString(h),
|
||||||
|
@ -60,6 +61,32 @@ func authMiddleware(next http.Handler) http.Handler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkAuthToken(r *http.Request) bool {
|
||||||
|
if tokenCookie, err := r.Cookie("token"); err == nil {
|
||||||
|
claims := &authClaims{}
|
||||||
|
if tkn, err := jwt.ParseWithClaims(tokenCookie.Value, claims, func(t *jwt.Token) (interface{}, error) {
|
||||||
|
return jwtKey(), nil
|
||||||
|
}); err == nil && tkn.Valid &&
|
||||||
|
claims.TokenType == "login" &&
|
||||||
|
checkUsername(claims.Username) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const loggedInKey requestContextKey = "loggedIn"
|
||||||
|
|
||||||
|
func checkLoggedIn(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
if checkAuthToken(r) {
|
||||||
|
next.ServeHTTP(rw, r.WithContext(context.WithValue(r.Context(), loggedInKey, true)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(rw, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func checkIsLogin(next http.Handler) http.Handler {
|
func checkIsLogin(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
if !checkLogin(rw, r) {
|
if !checkLogin(rw, r) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serveBlogStats(blog, statsPath string) func(w http.ResponseWriter, r *http.Request) {
|
func serveBlogStats(blog, statsPath string) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Build query
|
// Build query
|
||||||
query, params := buildPostsQuery(&postsRequestConfig{
|
query, params := buildPostsQuery(&postsRequestConfig{
|
||||||
|
@ -36,7 +36,7 @@ func serveBlogStats(blog, statsPath string) func(w http.ResponseWriter, r *http.
|
||||||
counts = append(counts, count)
|
counts = append(counts, count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render(w, templateBlogStats, &renderData{
|
render(w, r, templateBlogStats, &renderData{
|
||||||
BlogString: blog,
|
BlogString: blog,
|
||||||
Canonical: statsPath,
|
Canonical: statsPath,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
|
|
73
cache.go
73
cache.go
|
@ -31,43 +31,52 @@ func initCache() (err error) {
|
||||||
|
|
||||||
func cacheMiddleware(next http.Handler) http.Handler {
|
func cacheMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if appConfig.Cache.Enable &&
|
// Do checks
|
||||||
// check method
|
if !appConfig.Cache.Enable {
|
||||||
(r.Method == http.MethodGet || r.Method == http.MethodHead) &&
|
next.ServeHTTP(w, r)
|
||||||
// check bypass query
|
return
|
||||||
!(r.URL.Query().Get("cache") == "0" || r.URL.Query().Get("cache") == "false") {
|
}
|
||||||
key := cacheKey(r)
|
if !(r.Method == http.MethodGet || r.Method == http.MethodHead) {
|
||||||
// Get cache or render it
|
next.ServeHTTP(w, r)
|
||||||
cacheInterface, _, _ := cacheGroup.Do(key, func() (interface{}, error) {
|
return
|
||||||
return getCache(key, next, r), nil
|
}
|
||||||
})
|
if r.URL.Query().Get("cache") == "0" || r.URL.Query().Get("cache") == "false" {
|
||||||
cache := cacheInterface.(*cacheItem)
|
next.ServeHTTP(w, r)
|
||||||
// copy cached headers
|
return
|
||||||
for k, v := range cache.header {
|
}
|
||||||
w.Header()[k] = v
|
if loggedIn, ok := r.Context().Value(loggedInKey).(bool); ok && loggedIn {
|
||||||
}
|
next.ServeHTTP(w, r)
|
||||||
setCacheHeaders(w, cache)
|
return
|
||||||
// check conditional request
|
}
|
||||||
if ifNoneMatchHeader := r.Header.Get("If-None-Match"); ifNoneMatchHeader != "" && ifNoneMatchHeader == cache.eTag {
|
// Search and serve cache
|
||||||
|
key := cacheKey(r)
|
||||||
|
// Get cache or render it
|
||||||
|
cacheInterface, _, _ := cacheGroup.Do(key, func() (interface{}, error) {
|
||||||
|
return getCache(key, next, r), nil
|
||||||
|
})
|
||||||
|
cache := cacheInterface.(*cacheItem)
|
||||||
|
// copy cached headers
|
||||||
|
for k, v := range cache.header {
|
||||||
|
w.Header()[k] = v
|
||||||
|
}
|
||||||
|
setCacheHeaders(w, cache)
|
||||||
|
// check conditional request
|
||||||
|
if ifNoneMatchHeader := r.Header.Get("If-None-Match"); ifNoneMatchHeader != "" && ifNoneMatchHeader == cache.eTag {
|
||||||
|
// send 304
|
||||||
|
w.WriteHeader(http.StatusNotModified)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ifModifiedSinceHeader := r.Header.Get("If-Modified-Since"); ifModifiedSinceHeader != "" {
|
||||||
|
if t, err := dateparse.ParseAny(ifModifiedSinceHeader); err == nil && t.After(cache.creationTime) {
|
||||||
// send 304
|
// send 304
|
||||||
w.WriteHeader(http.StatusNotModified)
|
w.WriteHeader(http.StatusNotModified)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ifModifiedSinceHeader := r.Header.Get("If-Modified-Since"); ifModifiedSinceHeader != "" {
|
|
||||||
t, err := dateparse.ParseAny(ifModifiedSinceHeader)
|
|
||||||
if err == nil && t.After(cache.creationTime) {
|
|
||||||
// send 304
|
|
||||||
w.WriteHeader(http.StatusNotModified)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set status code
|
|
||||||
w.WriteHeader(cache.code)
|
|
||||||
// write cached body
|
|
||||||
_, _ = w.Write(cache.body)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
next.ServeHTTP(w, r)
|
// set status code
|
||||||
|
w.WriteHeader(cache.code)
|
||||||
|
// write cached body
|
||||||
|
_, _ = w.Write(cache.body)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ func captchaMiddleware(next http.Handler) http.Handler {
|
||||||
_ = r.ParseForm()
|
_ = r.ParseForm()
|
||||||
b = []byte(r.PostForm.Encode())
|
b = []byte(r.PostForm.Encode())
|
||||||
}
|
}
|
||||||
render(w, templateCaptcha, &renderData{
|
render(w, r, templateCaptcha, &renderData{
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
"captchamethod": r.Method,
|
"captchamethod": r.Method,
|
||||||
"captchaheaders": base64.StdEncoding.EncodeToString(h),
|
"captchaheaders": base64.StdEncoding.EncodeToString(h),
|
||||||
|
|
|
@ -41,7 +41,7 @@ func serveComment(blog string) func(http.ResponseWriter, *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("X-Robots-Tag", "noindex")
|
w.Header().Set("X-Robots-Tag", "noindex")
|
||||||
render(w, templateComment, &renderData{
|
render(w, r, templateComment, &renderData{
|
||||||
BlogString: blog,
|
BlogString: blog,
|
||||||
Canonical: appConfig.Server.PublicAddress + appConfig.Blogs[blog].getRelativePath(fmt.Sprintf("/comment/%d", id)),
|
Canonical: appConfig.Server.PublicAddress + appConfig.Blogs[blog].getRelativePath(fmt.Sprintf("/comment/%d", id)),
|
||||||
Data: comment,
|
Data: comment,
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (p *commentsPaginationAdapter) Slice(offset, length int, data interface{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func commentsAdmin(blog, commentPath string) func(w http.ResponseWriter, r *http.Request) {
|
func commentsAdmin(blog, commentPath string) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Adapter
|
// Adapter
|
||||||
pageNoString := chi.URLParam(r, "page")
|
pageNoString := chi.URLParam(r, "page")
|
||||||
|
@ -69,7 +69,7 @@ func commentsAdmin(blog, commentPath string) func(w http.ResponseWriter, r *http
|
||||||
}
|
}
|
||||||
nextPath = fmt.Sprintf("%s/page/%d", commentPath, nextPage)
|
nextPath = fmt.Sprintf("%s/page/%d", commentPath, nextPage)
|
||||||
// Render
|
// Render
|
||||||
render(w, templateCommentsAdmin, &renderData{
|
render(w, r, templateCommentsAdmin, &renderData{
|
||||||
BlogString: blog,
|
BlogString: blog,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"Comments": comments,
|
"Comments": comments,
|
||||||
|
|
|
@ -2,8 +2,8 @@ package main
|
||||||
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
func serveCustomPage(blog *configBlog, page *customPage) func(w http.ResponseWriter, r *http.Request) {
|
func serveCustomPage(blog *configBlog, page *customPage) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, _ *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
if appConfig.Cache != nil && appConfig.Cache.Enable && page.Cache {
|
if appConfig.Cache != nil && appConfig.Cache.Enable && page.Cache {
|
||||||
if page.CacheExpiration != 0 {
|
if page.CacheExpiration != 0 {
|
||||||
setInternalCacheExpirationHeader(w, page.CacheExpiration)
|
setInternalCacheExpirationHeader(w, page.CacheExpiration)
|
||||||
|
@ -11,7 +11,7 @@ func serveCustomPage(blog *configBlog, page *customPage) func(w http.ResponseWri
|
||||||
setInternalCacheExpirationHeader(w, int(appConfig.Cache.Expiration))
|
setInternalCacheExpirationHeader(w, int(appConfig.Cache.Expiration))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render(w, page.Template, &renderData{
|
render(w, r, page.Template, &renderData{
|
||||||
Blog: blog,
|
Blog: blog,
|
||||||
Canonical: appConfig.Server.PublicAddress + page.Path,
|
Canonical: appConfig.Server.PublicAddress + page.Path,
|
||||||
Data: page.Data,
|
Data: page.Data,
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
|
|
||||||
const editorPath = "/editor"
|
const editorPath = "/editor"
|
||||||
|
|
||||||
func serveEditor(blog string) func(w http.ResponseWriter, _ *http.Request) {
|
func serveEditor(blog string) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, _ *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
render(w, templateEditor, &renderData{
|
render(w, r, templateEditor, &renderData{
|
||||||
BlogString: blog,
|
BlogString: blog,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"Drafts": loadDrafts(blog),
|
"Drafts": loadDrafts(blog),
|
||||||
|
@ -38,7 +38,7 @@ func serveEditorPost(blog string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mf := post.toMfItem()
|
mf := post.toMfItem()
|
||||||
render(w, templateEditor, &renderData{
|
render(w, r, templateEditor, &renderData{
|
||||||
BlogString: blog,
|
BlogString: blog,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"UpdatePostURL": parsedURL.String(),
|
"UpdatePostURL": parsedURL.String(),
|
||||||
|
|
|
@ -24,7 +24,7 @@ func serveError(w http.ResponseWriter, r *http.Request, message string, status i
|
||||||
if message == "" {
|
if message == "" {
|
||||||
message = http.StatusText(status)
|
message = http.StatusText(status)
|
||||||
}
|
}
|
||||||
render(w, templateError, &renderData{
|
render(w, r, templateError, &renderData{
|
||||||
Data: &errorData{
|
Data: &errorData{
|
||||||
Title: title,
|
Title: title,
|
||||||
Message: message,
|
Message: message,
|
||||||
|
|
1
http.go
1
http.go
|
@ -98,6 +98,7 @@ func buildHandler() (http.Handler, error) {
|
||||||
}
|
}
|
||||||
r.Use(checkIsLogin)
|
r.Use(checkIsLogin)
|
||||||
r.Use(checkIsCaptcha)
|
r.Use(checkIsCaptcha)
|
||||||
|
r.Use(checkLoggedIn)
|
||||||
|
|
||||||
// Profiler
|
// Profiler
|
||||||
if appConfig.Server.Debug {
|
if appConfig.Server.Debug {
|
||||||
|
|
|
@ -53,7 +53,7 @@ func indieAuthRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
serveError(w, r, "state must not be empty", http.StatusBadRequest)
|
serveError(w, r, "state must not be empty", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
render(w, "indieauth", &renderData{
|
render(w, r, "indieauth", &renderData{
|
||||||
Data: data,
|
Data: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ func notificationsAdmin(notificationPath string) func(http.ResponseWriter, *http
|
||||||
}
|
}
|
||||||
nextPath = fmt.Sprintf("%s/page/%d", notificationPath, nextPage)
|
nextPath = fmt.Sprintf("%s/page/%d", notificationPath, nextPage)
|
||||||
// Render
|
// Render
|
||||||
render(w, templateNotificationsAdmin, &renderData{
|
render(w, r, templateNotificationsAdmin, &renderData{
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"Notifications": notifications,
|
"Notifications": notifications,
|
||||||
"HasPrev": hasPrev,
|
"HasPrev": hasPrev,
|
||||||
|
|
4
posts.go
4
posts.go
|
@ -66,7 +66,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
||||||
template = templateStaticHome
|
template = templateStaticHome
|
||||||
}
|
}
|
||||||
w.Header().Add("Link", fmt.Sprintf("<%s>; rel=shortlink", p.shortURL()))
|
w.Header().Add("Link", fmt.Sprintf("<%s>; rel=shortlink", p.shortURL()))
|
||||||
render(w, template, &renderData{
|
render(w, r, template, &renderData{
|
||||||
BlogString: p.Blog,
|
BlogString: p.Blog,
|
||||||
Canonical: canonical,
|
Canonical: canonical,
|
||||||
Data: p,
|
Data: p,
|
||||||
|
@ -285,7 +285,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
if summaryTemplate == "" {
|
if summaryTemplate == "" {
|
||||||
summaryTemplate = templateSummary
|
summaryTemplate = templateSummary
|
||||||
}
|
}
|
||||||
render(w, templateIndex, &renderData{
|
render(w, r, templateIndex, &renderData{
|
||||||
BlogString: ic.blog,
|
BlogString: ic.blog,
|
||||||
Canonical: appConfig.Server.PublicAddress + path,
|
Canonical: appConfig.Server.PublicAddress + path,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
|
|
19
render.go
19
render.go
|
@ -39,6 +39,7 @@ const (
|
||||||
templateCaptcha = "captcha"
|
templateCaptcha = "captcha"
|
||||||
templateCommentsAdmin = "commentsadmin"
|
templateCommentsAdmin = "commentsadmin"
|
||||||
templateNotificationsAdmin = "notificationsadmin"
|
templateNotificationsAdmin = "notificationsadmin"
|
||||||
|
templateWebmentionAdmin = "webmentionadmin"
|
||||||
)
|
)
|
||||||
|
|
||||||
var templates map[string]*template.Template
|
var templates map[string]*template.Template
|
||||||
|
@ -238,9 +239,10 @@ type renderData struct {
|
||||||
Canonical string
|
Canonical string
|
||||||
Blog *configBlog
|
Blog *configBlog
|
||||||
Data interface{}
|
Data interface{}
|
||||||
|
LoggedIn bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func render(w http.ResponseWriter, template string, data *renderData) {
|
func render(w http.ResponseWriter, r *http.Request, template string, data *renderData) {
|
||||||
// Check render data
|
// Check render data
|
||||||
if data.Blog == nil {
|
if data.Blog == nil {
|
||||||
if len(data.BlogString) == 0 {
|
if len(data.BlogString) == 0 {
|
||||||
|
@ -259,15 +261,20 @@ func render(w http.ResponseWriter, template string, data *renderData) {
|
||||||
if data.Data == nil {
|
if data.Data == nil {
|
||||||
data.Data = map[string]interface{}{}
|
data.Data = map[string]interface{}{}
|
||||||
}
|
}
|
||||||
// We need to use a buffer here to enable minification
|
// Check login
|
||||||
var buffer bytes.Buffer
|
if loggedIn, ok := r.Context().Value(loggedInKey).(bool); ok && loggedIn {
|
||||||
err := templates[template].ExecuteTemplate(&buffer, template, data)
|
data.LoggedIn = true
|
||||||
|
}
|
||||||
|
// Minify and write response
|
||||||
|
mw := minifier.Writer(contentTypeHTML, w)
|
||||||
|
defer func() {
|
||||||
|
_ = mw.Close()
|
||||||
|
}()
|
||||||
|
err := templates[template].ExecuteTemplate(mw, template, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Set content type
|
// Set content type
|
||||||
w.Header().Set(contentType, contentTypeHTMLUTF8)
|
w.Header().Set(contentType, contentTypeHTMLUTF8)
|
||||||
// Write buffered response
|
|
||||||
_, _ = writeMinified(w, contentTypeHTML, buffer.Bytes())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ func serveSearch(blog string, servePath string) func(w http.ResponseWriter, r *h
|
||||||
http.Redirect(w, r, path.Join(servePath, searchEncode(q)), http.StatusFound)
|
http.Redirect(w, r, path.Join(servePath, searchEncode(q)), http.StatusFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
render(w, templateSearch, &renderData{
|
render(w, r, templateSearch, &renderData{
|
||||||
BlogString: blog,
|
BlogString: blog,
|
||||||
Canonical: appConfig.Server.PublicAddress + servePath,
|
Canonical: appConfig.Server.PublicAddress + servePath,
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,7 +9,7 @@ func serveTaxonomy(blog string, tax *taxonomy) func(w http.ResponseWriter, r *ht
|
||||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
render(w, templateTaxonomy, &renderData{
|
render(w, r, templateTaxonomy, &renderData{
|
||||||
BlogString: blog,
|
BlogString: blog,
|
||||||
Canonical: appConfig.Server.PublicAddress + r.URL.Path,
|
Canonical: appConfig.Server.PublicAddress + r.URL.Path,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
|
|
|
@ -4,8 +4,16 @@
|
||||||
{{ with .Blog.Description }}<p><i>{{ . }}</i></p>{{ end }}
|
{{ with .Blog.Description }}<p><i>{{ . }}</i></p>{{ end }}
|
||||||
<nav>
|
<nav>
|
||||||
{{ with menu .Blog "main" }}
|
{{ with menu .Blog "main" }}
|
||||||
{{ range $i, $item := .Items }}{{ if ne $i 0 }} • {{ end }}<a href="{{ $item.Link }}">{{ $item.Title }}</a>{{ end }}
|
{{ range $i, $item := .Items }}{{ if ne $i 0 }} • {{ end }}<a href="{{ $item.Link }}">{{ $item.Title }}</a>{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</nav>
|
</nav>
|
||||||
|
{{ if .LoggedIn }}
|
||||||
|
<nav>
|
||||||
|
<a href="{{ blogrelative .Blog "/editor" }}">{{ string .Blog.Lang "editor" }}</a>
|
||||||
|
• <a href="/notifications">{{ string .Blog.Lang "notifications" }}</a>
|
||||||
|
• <a href="/webmention">{{ string .Blog.Lang "webmentions" }}</a>
|
||||||
|
• <a href="{{ blogrelative .Blog "/comment" }}">{{ string .Blog.Lang "comments" }}</a>
|
||||||
|
</nav>
|
||||||
|
{{ end }}
|
||||||
</header>
|
</header>
|
||||||
{{ end }}
|
{{ end }}
|
|
@ -67,7 +67,7 @@ func webmentionAdmin(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
nextPath = fmt.Sprintf("%s/page/%d", webmentionPath, nextPage)
|
nextPath = fmt.Sprintf("%s/page/%d", webmentionPath, nextPage)
|
||||||
// Render
|
// Render
|
||||||
render(w, "webmentionadmin", &renderData{
|
render(w, r, templateWebmentionAdmin, &renderData{
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"Mentions": mentions,
|
"Mentions": mentions,
|
||||||
"HasPrev": hasPrev,
|
"HasPrev": hasPrev,
|
||||||
|
|
Loading…
Reference in New Issue