Various small fixes
This commit is contained in:
parent
4a7a87c306
commit
cd575ffb1e
|
@ -4,6 +4,7 @@ package jsondb
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -26,6 +27,7 @@ var (
|
||||||
|
|
||||||
// New initializes the JSON database.
|
// New initializes the JSON database.
|
||||||
func New(root string) *DB {
|
func New(root string) *DB {
|
||||||
|
log.Info("Initialized JsonDB at root: %s", root)
|
||||||
return &DB{
|
return &DB{
|
||||||
Root: root,
|
Root: root,
|
||||||
}
|
}
|
||||||
|
@ -60,14 +62,17 @@ func (db *DB) Commit(document string, v interface{}) error {
|
||||||
path := db.toPath(document)
|
path := db.toPath(document)
|
||||||
|
|
||||||
// Ensure the directory tree is ready.
|
// Ensure the directory tree is ready.
|
||||||
db.makePath(path)
|
err := db.makePath(path)
|
||||||
|
|
||||||
// Write the document.
|
|
||||||
err := db.writeJSON(path, v)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write the document.
|
||||||
|
err = db.writeJSON(path, v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write JSON to path %s: %s", path, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +112,7 @@ func (db *DB) ListAll(path string) ([]string, error) {
|
||||||
func (db *DB) makePath(path string) error {
|
func (db *DB) makePath(path string) error {
|
||||||
parts := strings.Split(path, string(filepath.Separator))
|
parts := strings.Split(path, string(filepath.Separator))
|
||||||
parts = parts[:len(parts)-1] // pop off the filename
|
parts = parts[:len(parts)-1] // pop off the filename
|
||||||
directory := filepath.Join(parts...)
|
directory := "/" + filepath.Join(parts...)
|
||||||
|
|
||||||
if _, err := os.Stat(directory); err != nil {
|
if _, err := os.Stat(directory); err != nil {
|
||||||
log.Debug("[JsonDB] Create directory: %s", directory)
|
log.Debug("[JsonDB] Create directory: %s", directory)
|
||||||
|
|
|
@ -44,8 +44,9 @@ func (b *Blog) Session(r *http.Request) *sessions.Session {
|
||||||
func (b *Blog) CSRFMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
func (b *Blog) CSRFMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
if r.Method == "POST" {
|
if r.Method == "POST" {
|
||||||
session := b.Session(r)
|
session := b.Session(r)
|
||||||
token, ok := session.Values["csrf"].(string)
|
token := b.GenerateCSRFToken(w, r, session)
|
||||||
if !ok || token != r.FormValue("_csrf") {
|
if token != r.FormValue("_csrf") {
|
||||||
|
log.Error("CSRF Mismatch: expected %s, got %s", r.FormValue("_csrf"), token)
|
||||||
b.Forbidden(w, r, "Failed to validate CSRF token. Please try your request again.")
|
b.Forbidden(w, r, "Failed to validate CSRF token. Please try your request again.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (b *Blog) ResolvePath(path string) (Filepath, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("Resolving filepath for URI: %s", path)
|
debug("Resolving filepath for URI: %s", path)
|
||||||
for _, root := range []string{b.DocumentRoot, b.UserRoot} {
|
for _, root := range []string{b.UserRoot, b.DocumentRoot} {
|
||||||
if len(root) == 0 {
|
if len(root) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kirsle/blog/core/forms"
|
"github.com/kirsle/blog/core/forms"
|
||||||
"github.com/kirsle/blog/core/models/settings"
|
"github.com/kirsle/blog/core/models/settings"
|
||||||
|
@ -108,6 +109,7 @@ func (b *Blog) RenderTemplate(w http.ResponseWriter, r *http.Request, path strin
|
||||||
// Useful template functions.
|
// Useful template functions.
|
||||||
t := template.New(filepath.Absolute).Funcs(template.FuncMap{
|
t := template.New(filepath.Absolute).Funcs(template.FuncMap{
|
||||||
"StringsJoin": strings.Join,
|
"StringsJoin": strings.Join,
|
||||||
|
"Now": time.Now,
|
||||||
"RenderPost": b.RenderPost,
|
"RenderPost": b.RenderPost,
|
||||||
"RenderComments": func(subject string, ids ...string) template.HTML {
|
"RenderComments": func(subject string, ids ...string) template.HTML {
|
||||||
session := b.Session(r)
|
session := b.Session(r)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{{ define "title" }}WTF?{{ end }}
|
{{ define "title" }}{{ end }}
|
||||||
{{ define "scripts" }}{{ end }}
|
{{ define "scripts" }}{{ end }}
|
||||||
|
|
||||||
{{ define "layout" }}
|
{{ define "layout" }}
|
||||||
|
|
|
@ -2,162 +2,159 @@
|
||||||
{{ define "content" }}
|
{{ define "content" }}
|
||||||
<form action="/admin/settings" method="POST">
|
<form action="/admin/settings" method="POST">
|
||||||
<input type="hidden" name="_csrf" value="{{ .CSRF }}">
|
<input type="hidden" name="_csrf" value="{{ .CSRF }}">
|
||||||
<div class="card">
|
|
||||||
{{ with .Data.s }}
|
|
||||||
<div class="card-body">
|
|
||||||
<h3>The Basics</h3>
|
|
||||||
|
|
||||||
<div class="form-group">
|
{{ with .Data.s }}
|
||||||
<label for="title">Title</label>
|
<h3>The Basics</h3>
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="title"
|
|
||||||
value="{{ .Site.Title }}"
|
|
||||||
placeholder="Website Title">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="admin-email">Admin Email</label>
|
|
||||||
<small class="text-muted">For getting notifications about comments, etc.</small>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="admin-email"
|
|
||||||
value="{{ .Site.AdminEmail }}"
|
|
||||||
placeholder="name@domain.com">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="admin-email">URL Root</label>
|
|
||||||
<small class="text-muted d-block">
|
|
||||||
The base absolute URL to your website. This is used to generate
|
|
||||||
emails such as comment notifications. If not provided, these
|
|
||||||
emails will not be sent.
|
|
||||||
</small>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="url"
|
|
||||||
value="{{ .Site.URL }}"
|
|
||||||
placeholder="https://www.example.com/">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Redis Cache</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Using a <a href="https://redis.io/" target="_blank">Redis</a> cache can
|
|
||||||
boost the performance of the JSON database by caching documents in
|
|
||||||
memory instead of always reading from disk.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="form-check">
|
|
||||||
<label class="form-check-label">
|
|
||||||
<input type="checkbox"
|
|
||||||
class="form-check-input"
|
|
||||||
name="redis-enabled"
|
|
||||||
value="true"
|
|
||||||
{{ if .Redis.Enabled }}checked{{ end }}>
|
|
||||||
Enable Redis
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="redis-host">Redis Host</label>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="redis-host"
|
|
||||||
value="{{ .Redis.Host }}"
|
|
||||||
placeholder="localhost">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="redis-port">Port</label>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="redis-port"
|
|
||||||
value="{{ .Redis.Port }}"
|
|
||||||
placeholder="6379">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="redis-db">DB Number</label>
|
|
||||||
<small class="text-muted">0-15</small>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="redis-db"
|
|
||||||
value="{{ .Redis.DB }}"
|
|
||||||
placeholder="0">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="redis-prefix">Key Prefix</label>
|
|
||||||
<small class="text-muted">(optional)</small>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="redis-prefix"
|
|
||||||
value="{{ .Redis.Prefix }}"
|
|
||||||
placeholder="blog:">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Email Settings</h3>
|
|
||||||
|
|
||||||
<div class="form-check">
|
|
||||||
<label class="form-check-label">
|
|
||||||
<input type="checkbox"
|
|
||||||
class="form-check-input"
|
|
||||||
name="mail-enabled"
|
|
||||||
value="true"
|
|
||||||
{{ if .Mail.Enabled }}checked{{ end }}>
|
|
||||||
Enable email to be sent by this site
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="mail-sender">Sender Address</label>
|
|
||||||
<input type="email"
|
|
||||||
name="mail-sender"
|
|
||||||
id="mail-sender"
|
|
||||||
class="form-control"
|
|
||||||
value="{{ .Mail.Sender }}"
|
|
||||||
placeholder="no-reply@example.com">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="mail-host">SMTP Host</label>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="mail-host"
|
|
||||||
id="mail-host"
|
|
||||||
value="{{ .Mail.Host }}"
|
|
||||||
placeholder="localhost">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="mail-port">SMTP Port</label>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="mail-port"
|
|
||||||
id="mail-port"
|
|
||||||
value="{{ .Mail.Port }}"
|
|
||||||
placeholder="25">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="mail-username">SMTP Username</label>
|
|
||||||
<small class="text-muted">(optional)</small>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="mail-username"
|
|
||||||
value="{{ .Mail.Username }}"
|
|
||||||
placeholder="">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="mail-password">SMTP Password</label>
|
|
||||||
<small class="text-muted">(optional)</small>
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
name="mail-password"
|
|
||||||
value="{{ .Mail.Password }}"
|
|
||||||
placeholder="">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Save Settings</button>
|
|
||||||
<a href="/admin" class="btn btn-secondary">Cancel</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title">Title</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="title"
|
||||||
|
value="{{ .Site.Title }}"
|
||||||
|
placeholder="Website Title">
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
|
||||||
</div>
|
<div class="form-group">
|
||||||
|
<label for="admin-email">Admin Email</label>
|
||||||
|
<small class="text-muted">For getting notifications about comments, etc.</small>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="admin-email"
|
||||||
|
value="{{ .Site.AdminEmail }}"
|
||||||
|
placeholder="name@domain.com">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="admin-email">URL Root</label>
|
||||||
|
<small class="text-muted d-block">
|
||||||
|
The base absolute URL to your website. This is used to generate
|
||||||
|
emails such as comment notifications. If not provided, these
|
||||||
|
emails will not be sent.
|
||||||
|
</small>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="url"
|
||||||
|
value="{{ .Site.URL }}"
|
||||||
|
placeholder="https://www.example.com/">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Redis Cache</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Using a <a href="https://redis.io/" target="_blank">Redis</a> cache can
|
||||||
|
boost the performance of the JSON database by caching documents in
|
||||||
|
memory instead of always reading from disk.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="form-check">
|
||||||
|
<label class="form-check-label">
|
||||||
|
<input type="checkbox"
|
||||||
|
class="form-check-input"
|
||||||
|
name="redis-enabled"
|
||||||
|
value="true"
|
||||||
|
{{ if .Redis.Enabled }}checked{{ end }}>
|
||||||
|
Enable Redis
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="redis-host">Redis Host</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="redis-host"
|
||||||
|
value="{{ .Redis.Host }}"
|
||||||
|
placeholder="localhost">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="redis-port">Port</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="redis-port"
|
||||||
|
value="{{ .Redis.Port }}"
|
||||||
|
placeholder="6379">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="redis-db">DB Number</label>
|
||||||
|
<small class="text-muted">0-15</small>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="redis-db"
|
||||||
|
value="{{ .Redis.DB }}"
|
||||||
|
placeholder="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="redis-prefix">Key Prefix</label>
|
||||||
|
<small class="text-muted">(optional)</small>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="redis-prefix"
|
||||||
|
value="{{ .Redis.Prefix }}"
|
||||||
|
placeholder="blog:">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Email Settings</h3>
|
||||||
|
|
||||||
|
<div class="form-check">
|
||||||
|
<label class="form-check-label">
|
||||||
|
<input type="checkbox"
|
||||||
|
class="form-check-input"
|
||||||
|
name="mail-enabled"
|
||||||
|
value="true"
|
||||||
|
{{ if .Mail.Enabled }}checked{{ end }}>
|
||||||
|
Enable email to be sent by this site
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="mail-sender">Sender Address</label>
|
||||||
|
<input type="email"
|
||||||
|
name="mail-sender"
|
||||||
|
id="mail-sender"
|
||||||
|
class="form-control"
|
||||||
|
value="{{ .Mail.Sender }}"
|
||||||
|
placeholder="no-reply@example.com">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="mail-host">SMTP Host</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="mail-host"
|
||||||
|
id="mail-host"
|
||||||
|
value="{{ .Mail.Host }}"
|
||||||
|
placeholder="localhost">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="mail-port">SMTP Port</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="mail-port"
|
||||||
|
id="mail-port"
|
||||||
|
value="{{ .Mail.Port }}"
|
||||||
|
placeholder="25">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="mail-username">SMTP Username</label>
|
||||||
|
<small class="text-muted">(optional)</small>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="mail-username"
|
||||||
|
value="{{ .Mail.Username }}"
|
||||||
|
placeholder="">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="mail-password">SMTP Password</label>
|
||||||
|
<small class="text-muted">(optional)</small>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="mail-password"
|
||||||
|
value="{{ .Mail.Password }}"
|
||||||
|
placeholder="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" class="btn btn-primary">Save Settings</button>
|
||||||
|
<a href="/admin" class="btn btn-secondary">Cancel</a>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user