diff --git a/blogroll.go b/blogroll.go index b53e914..160f348 100644 --- a/blogroll.go +++ b/blogroll.go @@ -17,7 +17,7 @@ import ( const defaultBlogrollPath = "/blogroll" func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) { - blog := r.Context().Value(blogKey).(string) + blog, bc := a.getBlog(r) outlines, err, _ := a.blogrollCacheGroup.Do(blog, func() (interface{}, error) { return a.getBlogrollOutlines(blog) }) @@ -26,7 +26,7 @@ func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) { a.serveError(w, r, "", http.StatusInternalServerError) return } - c := a.cfg.Blogs[blog].Blogroll + c := bc.Blogroll can := a.getRelativePath(blog, defaultIfEmpty(c.Path, defaultBlogrollPath)) a.render(w, r, templateBlogroll, &renderData{ BlogString: blog, @@ -41,7 +41,7 @@ func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) { } func (a *goBlog) serveBlogrollExport(w http.ResponseWriter, r *http.Request) { - blog := r.Context().Value(blogKey).(string) + blog, _ := a.getBlog(r) outlines, err, _ := a.blogrollCacheGroup.Do(blog, func() (interface{}, error) { return a.getBlogrollOutlines(blog) }) diff --git a/blogstats.go b/blogstats.go index 4db9517..41dcf61 100644 --- a/blogstats.go +++ b/blogstats.go @@ -22,8 +22,7 @@ func (a *goBlog) initBlogStats() { } func (a *goBlog) serveBlogStats(w http.ResponseWriter, r *http.Request) { - blog := r.Context().Value(blogKey).(string) - bc := a.cfg.Blogs[blog] + blog, bc := a.getBlog(r) canonical := bc.getRelativePath(defaultIfEmpty(bc.BlogStats.Path, defaultBlogStatsPath)) a.render(w, r, templateBlogStats, &renderData{ BlogString: blog, diff --git a/config.go b/config.go index f4112e8..65f8464 100644 --- a/config.go +++ b/config.go @@ -3,6 +3,7 @@ package main import ( "errors" "log" + "net/http" "net/url" "strings" @@ -375,3 +376,14 @@ func (a *goBlog) httpsConfigured(checkAddress bool) bool { a.cfg.Server.SecurityHeaders || (checkAddress && strings.HasPrefix(a.cfg.Server.PublicAddress, "https")) } + +func (a *goBlog) getBlog(r *http.Request) (string, *configBlog) { + if r == nil { + return a.cfg.DefaultBlog, a.cfg.Blogs[a.cfg.DefaultBlog] + } + blog := r.Context().Value(blogKey).(string) + if blog == "" { + return a.cfg.DefaultBlog, a.cfg.Blogs[a.cfg.DefaultBlog] + } + return blog, a.cfg.Blogs[blog] +} diff --git a/contact.go b/contact.go index a56402d..875faaf 100644 --- a/contact.go +++ b/contact.go @@ -13,8 +13,8 @@ import ( const defaultContactPath = "/contact" func (a *goBlog) serveContactForm(w http.ResponseWriter, r *http.Request) { - blog := r.Context().Value(blogKey).(string) - cc := a.cfg.Blogs[blog].Contact + blog, bc := a.getBlog(r) + cc := bc.Contact a.render(w, r, templateContact, &renderData{ BlogString: blog, Data: map[string]interface{}{ @@ -58,12 +58,12 @@ func (a *goBlog) sendContactSubmission(w http.ResponseWriter, r *http.Request) { } _, _ = message.WriteString(formMessage) // Send submission - blog := r.Context().Value(blogKey).(string) - if cc := a.cfg.Blogs[blog].Contact; cc != nil && cc.SMTPHost != "" && cc.EmailFrom != "" && cc.EmailTo != "" { + blog, bc := a.getBlog(r) + if cc := bc.Contact; cc != nil && cc.SMTPHost != "" && cc.EmailFrom != "" && cc.EmailTo != "" { // Build email var email bytes.Buffer if ef := cc.EmailFrom; ef != "" { - _, _ = fmt.Fprintf(&email, "From: %s <%s>", defaultIfEmpty(a.cfg.Blogs[blog].Title, "GoBlog"), cc.EmailFrom) + _, _ = fmt.Fprintf(&email, "From: %s <%s>", defaultIfEmpty(bc.Title, "GoBlog"), cc.EmailFrom) _, _ = fmt.Fprintln(&email) } _, _ = fmt.Fprintf(&email, "To: %s", cc.EmailTo) diff --git a/docs/index.md b/docs/index.md index d9546f1..b9e5b23 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,47 @@ License: MIT License [GitHub mirror](https://github.com/jlelse/GoBlog) [Codeberg mirror](https://codeberg.org/jlelse/GoBlog) -More information about GoBlog: +## Features + +Here's an (incomplete) list of features: + +- Single user with multiple blogs +- Publish, edit and delete Markdown posts using Micropub or the web-based editor + - Editor with live preview + - Drafts, private and unlisted posts +- SQLite database for storing posts and data + - Built-in full-text search +- Micropub with media endpoint for uploads + - Local storage for uploads or remote storage via FTP or BunnyCDN + - Automatic image resizing and compression + - Uploads possible via the web-based editor +- Send and receive Webmentions + - Webmention-based commenting +- IndieAuth + - Login with your own blog as an identity on the internet + - Two-factor authentication +- ActivityPub + - Publish posts to the Fediverse (Mastodon etc.) + - ActivityPub-based commenting +- Web feeds + - Multiple feed formats: RSS, Atom, JSON + - Feeds on any archive page +- Sitemap +- Automatic HTTPS using Let's Encrypt +- Tor Hidden Service +- Tailscale integration for private blogs with HTTPS +- Fast in-memory caching for even faster performance +- Automatic asset minification of HTML, CSS and JavaScript +- Statistics page with information about posts +- Map page with a map of all posts with a location +- Option to create post aliases for automatic redirects +- Redirects using regular expressions +- Hooks to execute custom commands on certain events +- Short URLs with option for a separate short domain +- Command to check for broken links +- Command to export all posts to Markdown files + +## More information about GoBlog: - [How to install and run GoBlog](./install.md) - [How to build GoBlog](./build.md) diff --git a/go.mod b/go.mod index ab57961..f83043a 100644 --- a/go.mod +++ b/go.mod @@ -99,7 +99,7 @@ require ( go4.org/intern v0.0.0-20210108033219-3eb7198706b2 // indirect go4.org/mem v0.0.0-20201119185036-c04c5a6ff174 // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 // indirect - golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c // indirect + golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c // indirect diff --git a/go.sum b/go.sum index 1b533d0..5eef9b8 100644 --- a/go.sum +++ b/go.sum @@ -682,8 +682,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c h1:QOfDMdrf/UwlVR0UBq2Mpr58UzNtvgJRXA4BgPfFACs= -golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= diff --git a/httpsCache.go b/httpsCache.go index 4cda15d..05dfc4d 100644 --- a/httpsCache.go +++ b/httpsCache.go @@ -8,6 +8,9 @@ import ( "golang.org/x/crypto/acme/autocert" ) +// Make sure the httpsCache type implements the Cache interface +var _ autocert.Cache = &httpsCache{} + type httpsCache struct { db *database } diff --git a/opensearch.go b/opensearch.go index aba6e07..8b4d26d 100644 --- a/opensearch.go +++ b/opensearch.go @@ -8,8 +8,7 @@ import ( ) func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) { - blog := r.Context().Value(blogKey).(string) - b := a.cfg.Blogs[blog] + _, b := a.getBlog(r) title := a.renderMdTitle(b.Title) sURL := a.getFullAddress(b.getRelativePath(defaultIfEmpty(b.Search.Path, defaultSearchPath))) xml := fmt.Sprintf(""+ diff --git a/pkgs/maprouter/maprouter_test.go b/pkgs/maprouter/maprouter_test.go index c27938c..e6b3a2b 100644 --- a/pkgs/maprouter/maprouter_test.go +++ b/pkgs/maprouter/maprouter_test.go @@ -12,14 +12,14 @@ import ( func TestMapRouter(t *testing.T) { router := &MapRouter{ DefaultHandler: http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("Default")) + _, _ = rw.Write([]byte("Default")) }), Handlers: map[string]http.Handler{ "a.example.org": http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("a")) + _, _ = rw.Write([]byte("a")) }), "b.example.org": http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("b")) + _, _ = rw.Write([]byte("b")) }), }, }