aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Riedstra <mitch@riedstra.dev>2022-09-17 11:41:20 -0400
committerMitchell Riedstra <mitch@riedstra.dev>2022-09-17 11:41:20 -0400
commitccc26c3a0bb65ae2613e222c3ead7f6db377b483 (patch)
tree6124ae75f557fffe863134b967ee7c6bfcc87d3d
parentbf7d9c79cae53f64fcd04527248987bd4e7ca3c4 (diff)
downloadgo-website-ccc26c3a0bb65ae2613e222c3ead7f6db377b483.tar.gz
go-website-ccc26c3a0bb65ae2613e222c3ead7f6db377b483.tar.xz
More work on the editor and update the example site to utilize it.v0.0.18
-rw-r--r--.gitignore4
-rw-r--r--cmd/server/dashboard.go5
-rw-r--r--cmd/server/edit.go14
-rw-r--r--cmd/server/handlers.go23
-rw-r--r--cmd/server/middleware.go114
-rw-r--r--example-site/conf.yml3
-rw-r--r--example-site/login.md21
-rw-r--r--example-site/reIndex.md4
-rw-r--r--example-site/tpl/4xx.md7
-rw-r--r--example-site/tpl/5xx.md30
-rw-r--r--example-site/tpl/base.md (renamed from example-site/inc/base.html)36
-rw-r--r--example-site/tpl/dashboard.md53
-rw-r--r--example-site/tpl/edit.md27
-rw-r--r--example-site/tpl/new-template.md55
14 files changed, 351 insertions, 45 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ca77d1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+example-site/auth.json
+cmd/server/server
+server
+
diff --git a/cmd/server/dashboard.go b/cmd/server/dashboard.go
deleted file mode 100644
index a07e722..0000000
--- a/cmd/server/dashboard.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package main
-
-// func (a *App) DashboardHandler(w http.ResponseWriter, r *http.Request) {
-// page.Render("
-// }
diff --git a/cmd/server/edit.go b/cmd/server/edit.go
index 730e6e9..eb0c4cc 100644
--- a/cmd/server/edit.go
+++ b/cmd/server/edit.go
@@ -8,6 +8,7 @@ import (
"net/http"
"os"
"path/filepath"
+ "strings"
"riedstra.dev/mitch/go-website/page"
)
@@ -17,6 +18,7 @@ func (a *App) EditPage(w http.ResponseWriter, r *http.Request) {
page.Render(w, r, page.TemplateDirectory+"/4xx", map[string]interface{}{
"Title": "Method Not allowed",
"Description": "Method not allowed",
+ "LoggedIn": a.IsLoggedIn(r),
}, http.StatusMethodNotAllowed)
return
@@ -27,12 +29,18 @@ func (a *App) EditPage(w http.ResponseWriter, r *http.Request) {
p = filepath.Clean(p)
fh, err := os.Open("./" + p + page.Suffix)
+ if err != nil && strings.Contains(err.Error(), "no such file or directory") {
+ fh, err = os.Open("./" + page.TemplateDirectory +
+ "/new-template" + page.Suffix)
+ }
+
if err != nil {
log.Printf("opening page: %s", err)
a.Err500Default(w, r)
return
}
+ defer fh.Close()
b, err := io.ReadAll(fh)
if err != nil {
@@ -43,8 +51,9 @@ func (a *App) EditPage(w http.ResponseWriter, r *http.Request) {
}
page.Render(w, r, page.TemplateDirectory+"/edit", map[string]interface{}{
- "Page": p,
- "Content": html.EscapeString(string(b)),
+ "Page": p,
+ "Content": html.EscapeString(string(b)),
+ "LoggedIn": a.IsLoggedIn(r),
}, http.StatusOK)
}
@@ -70,6 +79,7 @@ func (a *App) SaveEditPage(w http.ResponseWriter, r *http.Request) {
return
}
+ defer fh.Close()
c := bytes.ReplaceAll([]byte(content), []byte{'\r'}, []byte{})
diff --git a/cmd/server/handlers.go b/cmd/server/handlers.go
index 1711ae3..c44c19c 100644
--- a/cmd/server/handlers.go
+++ b/cmd/server/handlers.go
@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"path/filepath"
+ "strings"
"github.com/gorilla/mux"
"riedstra.dev/mitch/go-website/page"
@@ -22,7 +23,7 @@ func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rtr.PathPrefix("/edit/").Handler(
a.RequiresLogin(http.StripPrefix("/edit/", http.HandlerFunc(a.SaveEditPage)))).Methods("POST")
- if a.redisPool != nil {
+ if a.redisPool != nil && !a.IsLoggedIn(r) {
rtr.PathPrefix(fmt.Sprintf("/%s/{tag}", a.FeedPrefix)).Handler(
rediscache.HandleWithParams(a.redisPool, a.RedisKey,
http.HandlerFunc(a.FeedHandler)))
@@ -45,9 +46,27 @@ func (a *App) PageHandler(w http.ResponseWriter, r *http.Request) {
u = "/index"
}
+ loggedIn := a.IsLoggedIn(r)
+
+ if u == "/dashboard" && loggedIn {
+ u = page.TemplateDirectory + "/dashboard"
+ }
+
+ // Render nothing inside of the template directory if we're not logged in
+ if strings.HasPrefix(u[1:], filepath.Clean(page.TemplateDirectory)) &&
+ !loggedIn {
+
+ page.Render4xx(w, r, map[string]interface{}{
+ "LoggedIn": loggedIn,
+ }, 404)
+ return
+ }
+
u = filepath.Join(".", u)
- page.RenderForPath(w, r, u)
+ page.RenderWithVars(w, r, u, map[string]interface{}{
+ "LoggedIn": loggedIn,
+ })
}
func (a *App) RebuildIndexHandler(w http.ResponseWriter, r *http.Request) {
diff --git a/cmd/server/middleware.go b/cmd/server/middleware.go
index 5e4bf26..0d332cd 100644
--- a/cmd/server/middleware.go
+++ b/cmd/server/middleware.go
@@ -1,8 +1,10 @@
package main
import (
+ "errors"
"log"
"net/http"
+ "net/url"
"time"
jwt "github.com/dgrijalva/jwt-go"
@@ -30,27 +32,41 @@ func (a *App) LogoutHandler(w http.ResponseWriter, r *http.Request) {
SameSite: a.auth.SameSiteStrict,
Secure: a.auth.Secure,
Value: "logout",
- Expires: time.Now().Add(time.Second * 15), //nolint
+ Expires: time.Now().Add(time.Second), //nolint
})
http.Redirect(w, r, "/", http.StatusFound)
}
func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { //nolint
- if r.Method == "GET" {
+ loggedIn := a.IsLoggedIn(r)
+
+ next, _ := url.Parse(r.URL.Query().Get("next"))
+
+ if r.Method == "GET" && !loggedIn {
page.RenderForPath(w, r, "login")
return
}
+ if r.Method == "GET" && loggedIn {
+ if next.Path != "" {
+ http.Redirect(w, r, next.Path, http.StatusFound)
+
+ return
+ }
+
+ http.Redirect(w, r, "/dashboard", http.StatusFound)
+
+ return
+ }
+
if r.Method != "POST" {
a.Err500Default(w, r)
return
}
- log.Printf("made it")
-
username := r.FormValue("username")
password := r.FormValue("password")
@@ -90,8 +106,6 @@ func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { //nolint
return
}
- log.Println(ss)
-
http.SetCookie(w, &http.Cookie{
Name: "Auth",
HttpOnly: a.auth.HTTPOnly,
@@ -103,40 +117,82 @@ func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { //nolint
http.Redirect(w, r, "/login", http.StatusFound)
}
+func (a *App) IsLoggedIn(r *http.Request) bool {
+ _, err := a.GetAuthToken(r)
+ if err != nil {
+ log.Printf("%s IsLoggedIn: false", r.URL.Path)
+ return false
+ }
+ log.Printf("%s IsLoggedIn: true", r.URL.Path)
+ return true
+}
+
+func (a *App) GetAuthToken(r *http.Request) (*jwt.Token, error) {
+ c, err := r.Cookie("Auth")
+ if err != nil {
+ return nil, err
+ }
+
+ token, err := jwt.Parse(c.Value,
+ func(token *jwt.Token) (interface{}, error) {
+ return []byte(a.auth.TokenKey), nil
+ },
+ )
+
+ if err != nil {
+ return nil, err
+ }
+
+ if !token.Valid {
+ return token, errors.New("IsLoggedIn: token not valid")
+ }
+
+ return token, nil
+}
+
func (a *App) RequiresLogin(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- mustLoginResp := func() {
+
+ if !a.IsLoggedIn(r) {
+ log.Printf("Unauthorized request %s %s", r.Method, r.URL.Path)
page.Render(w, r, "login", map[string]interface{}{
"Error": "You must login to view this page",
}, http.StatusUnauthorized)
- }
-
- c, err := r.Cookie("Auth")
- if err != nil {
- mustLoginResp()
return
}
- token, err := jwt.Parse(c.Value,
- func(token *jwt.Token) (interface{}, error) {
- return []byte(a.auth.TokenKey), nil
- },
- )
-
- if err != nil {
- log.Printf("Unauthorized request %s %s", r.Method, r.URL.Path)
- mustLoginResp()
+ next.ServeHTTP(w, r)
- return
- }
+ })
+}
- if !token.Valid {
- mustLoginResp()
+/*
+// ConditionalMiddleware is used to select one handler or another based on
+// a test function. If the test function returns true, use handler A, otherwise B.
+// This allows the test condition to only be run when the handler is selected
+// rather than trying to do this as a top level and ending up with a condition
+// that is tested on every single request, regardless of whether or not
+// the specific handler is selected
+type ConditionalMiddleware struct {
+ A, B http.Handler
+ Test func(r *http.Request) bool
+}
- return
- }
+func NewConditionalMiddleware(test func(r *http.Request) bool,
+ A, B http.Handler) http.Handler {
+ return &ConditionalMiddleware{
+ Test: test,
+ A: A,
+ B: B,
+ }
+}
- next.ServeHTTP(w, r)
- })
+func (cm *ConditionalMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if cm.Test(r) {
+ cm.A.ServeHTTP(w, r)
+ } else {
+ cm.B.ServeHTTP(w, r)
+ }
}
+*/
diff --git a/example-site/conf.yml b/example-site/conf.yml
index b6f0202..3cdb44d 100644
--- a/example-site/conf.yml
+++ b/example-site/conf.yml
@@ -1,7 +1,8 @@
# All these can be unset
reindexpath: /reIndex
staticdirectory: static
-basetemplate: inc/base.html
+templatedirectory: tpl
+basetemplate: tpl/base.md
documentsplit: "|---\n"
suffix: ".md"
diff --git a/example-site/login.md b/example-site/login.md
new file mode 100644
index 0000000..1b29ddd
--- /dev/null
+++ b/example-site/login.md
@@ -0,0 +1,21 @@
+---
+title: Login
+description: Login page
+|---
+
+<form action="/login" method="POST">
+<label for="username">Username:</label>
+<input type="text" id="username" name="username" />
+
+<label for="password">Password:</label>
+<input type="password" id="password" name="password" />
+
+<input type="submit" value="submit">
+</form>
+
+
+{{if .Vars}}
+```
+{{.Vars}}
+```
+{{else}}{{end}}
diff --git a/example-site/reIndex.md b/example-site/reIndex.md
index 12c608a..88cb278 100644
--- a/example-site/reIndex.md
+++ b/example-site/reIndex.md
@@ -6,7 +6,7 @@ description: >
# {{.Title}}
-{{.ClearRedis}}
+{{.Global.App.ClearRedis}}
this is the reindex page
@@ -22,3 +22,5 @@ This handler adds some information to the page vars:
{{.Vars}}
```
+
+
diff --git a/example-site/tpl/4xx.md b/example-site/tpl/4xx.md
new file mode 100644
index 0000000..3b0103b
--- /dev/null
+++ b/example-site/tpl/4xx.md
@@ -0,0 +1,7 @@
+---
+title: Page not found
+description: Page not found
+|---
+# {{.Title}}
+
+That's all we know. Perhaps you'd like to go back to the [home page](/)?
diff --git a/example-site/tpl/5xx.md b/example-site/tpl/5xx.md
new file mode 100644
index 0000000..43b28b6
--- /dev/null
+++ b/example-site/tpl/5xx.md
@@ -0,0 +1,30 @@
+---
+title: Server Error
+description: Server Error
+|---
+{{if .Vars}}
+
+{{if .Vars.Error}}
+{{.Vars.Error}}
+{{else}}
+# Internal server error <!--no detailed message available -->
+{{end}}
+
+{{else}}
+# Internal server error
+{{end}}
+
+{{if .Vars}}
+
+{{if .Vars.Description}}
+{{.Vars.Description}}
+{{else}}
+That's all we know.
+<!-- No detailed description available -->
+{{end}}
+
+{{else}}
+That's all we know.
+{{end}}
+
+Perhaps you'd like to go back to the [home page](/)?
diff --git a/example-site/inc/base.html b/example-site/tpl/base.md
index 2f93ec7..97842c1 100644
--- a/example-site/inc/base.html
+++ b/example-site/tpl/base.md
@@ -38,14 +38,40 @@
</h1>
{{end}}
+{{block "nav" .}}
<nav>
- <a href="/">Home</a>
-
- <div style="display: block; float: right;">
- <a href="#">Git</a>
- </div>
+ | <a href="/">Home</a> |
+ <div style="display: block; float: right;">
+ | <a href="#">Git</a>
+ {{if .Vars.LoggedIn}}
+<span id="edit">| <a href="#" onClick="editThisPage()">Edit</a></span>
+ | <a href="/dashboard">Dashboard</a>
+ | <a href="/logout">Logout</a> |
+ {{else}}
+ | <a href="/login">Login</a>
+ {{end}}
+ </div>
</nav>
+{{end}}
{{.RenderBody}}
+
+{{if .Vars.LoggedIn}}
+<script>
+function editThisPage()
+{
+ if(window.location.pathname == "/") {
+ window.location = "/edit/index";
+ return;
+ }
+ if(window.location.pathname == "/dashboard") {
+ window.location = "/edit/tpl/dashboard";
+ return;
+ }
+ window.location = "/edit/" + window.location.pathname;
+}
+</script>
+{{end}}
</body>
+
diff --git a/example-site/tpl/dashboard.md b/example-site/tpl/dashboard.md
new file mode 100644
index 0000000..9b90445
--- /dev/null
+++ b/example-site/tpl/dashboard.md
@@ -0,0 +1,53 @@
+---
+title: Website Dashboard
+description: Website dashboard
+|---
+
+# Dashboard page ( File: `tpl/dashboard.md` )
+
+Almost every page on the website can be edited by simply adding `edit/` before
+the path, for instance if we want to edit our `/reIndex` page, we simply go to
+`/edit/reIndex`
+
+There are a few pages where this is not possible, such as with the dashboard and
+other templated pages like 404's and 5xx's. That being said, you can still edit
+them by referencing their path on disk.
+
+You can create new pages that way too, the new page template is
+`tpl/new-template.md` if you wish to change what the defaults are.
+
+You'll also notice there's an `edit` button in the navbar, that's a little bit
+of Javascript trickery that you'll have to edit if you wish to change the
+template directory from `tpl` to anything else.
+
+Some useful edit links:
+
+ * 4xx page [visit](/some/path/that/does/not/exist) [edit](/edit/tpl/4xx)
+ * 5xx page [visit](/tpl/5xx) [edit](/edit/tpl/5xx)
+ * New page template [visit](/tpl/new-template) [edit](/edit/tpl/new-template)
+ * Edit page [visit](/tpl/edit) [edit](/edit/tpl/edit)
+ * Login page [visit](/login) [edit](/edit/login)
+ * Base template [edit](/edit/tpl/base)
+
+A note about the base template page, editing works, but viewing does not.
+
+Pages by tags:
+
+{{range $key, $val := .Index}}
+### {{$key}}:
+
+{{range $v2 := $val}}
+ * {{$v2.Path}} [visit](/{{$v2.Path}}) [edit](/edit/{{$v2.Path}}){{end}}
+
+
+
+{{end}}
+
+
+<script>
+/*
+window.addEventListener('load', (event) => {
+ document.querySelector("#edit").remove();
+});
+*/
+</script>
diff --git a/example-site/tpl/edit.md b/example-site/tpl/edit.md
new file mode 100644
index 0000000..4e55f82
--- /dev/null
+++ b/example-site/tpl/edit.md
@@ -0,0 +1,27 @@
+---
+title: Editing Page
+description: Editor
+|---
+
+<form action="/edit/{{.Vars.Page}}" method="POST">
+<br />
+<label for="content">Page content:</label><br />
+<br />
+
+
+<textarea id="content" name="content" rows="24" cols="80">
+{{.Vars.Content}}
+</textarea>
+
+<br />
+<input type="submit" value="save">
+</form>
+
+
+<!-- test -->
+
+<script>
+window.addEventListener('load', (event) => {
+ document.querySelector("#edit").remove();
+});
+</script>
diff --git a/example-site/tpl/new-template.md b/example-site/tpl/new-template.md
new file mode 100644
index 0000000..c4fdd95
--- /dev/null
+++ b/example-site/tpl/new-template.md
@@ -0,0 +1,55 @@
+---
+# This is the contents of the `tpl/new-template.md` file. You're likely seeing
+# This because you've created a new page, or are trying to edit a page that
+# does not exist. To save yourself some confusion in the future, if you save
+# This page it may be helpful to delete this first paragraph, as it will no
+# longer be true.
+
+# This top section is YAML, this sets up a few of the variables for rendering
+# a web page. Below is also some markdown that's executed as a go template
+# for the page's content
+
+# You can edit this page by editing `tpl/new-template` If you changed the
+# template directory, take that into account.
+
+# Controls whether or not the page is published, this includes the
+# Atom/RSS feed
+published: false
+# What tags should be applied to this page?
+# The default index/home page shows a list of published blog pages
+tags:
+ Blog:
+# This is the meta description, i.e. what you're going to seeing the little blurb
+# if you post the link to in say a discord chat. It's also what shows up in
+# Google and other search engines
+description: >-
+ This is an example description. Note that the line starts with spaces, and
+ not tabs.
+title: New page from `new-template`
+# Used for the RSS/Atom feed, you can also use it in the template below
+date: 09.11.2022 09:59:00 EDT
+
+# This line tells our server to stop parsing yaml and start processing
+# the rest of the text file as a markdown template
+|---
+
+{{/* This is a comment inside of the template */}}
+
+{{/*
+ Print out the date, format information can be found here:
+ https://pkg.go.dev/time#pkg-constants
+*/}}
+`{{.Date.Time.Format "Monday January 2 2006"}}`
+
+# {{.Title}}
+
+Some documentation on the templating language can be found [here](
+https://pkg.go.dev/text/template)
+
+
+A nice markdown reference can be found
+[here](https://www.markdownguide.org/basic-syntax/)
+
+
+Additionally <span style="color: red;">html tags</span> can be used in here as well.
+