%s. Go back to the hypha.
`,
- errMsg,
- name,
- ),
- user.EmptyUser(),
- ),
- )
-}
-
-// This part is present in all html documents.
-var base = views.BaseHTML
-
-func handlerStyle(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
- if _, err := os.Stat(cfg.WikiDir + "/static/common.css"); err == nil {
- http.ServeFile(w, rq, cfg.WikiDir+"/static/common.css")
- } else {
- w.Header().Set("Content-Type", "text/css;charset=utf-8")
- w.Write([]byte(assets.DefaultCSS()))
- }
- if bytes, err := ioutil.ReadFile(cfg.WikiDir + "/static/custom.css"); err == nil {
- w.Write(bytes)
- }
-}
-
-func handlerToolbar(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
- w.Header().Set("Content-Type", "text/javascript;charset=utf-8")
- w.Write([]byte(assets.ToolbarJS()))
-}
-
-// handlerIcon serves the requested icon. All icons are distributed as part of the Mycorrhiza binary.
-//
-// See assets/assets/icon/ for icons themselves, see assets/assets.qtpl for their sources.
-func handlerIcon(w http.ResponseWriter, rq *http.Request) {
- iconName := strings.TrimPrefix(rq.URL.Path, "/assets/icon/")
- if iconName == "https" {
- iconName = "http"
- }
- w.Header().Set("Content-Type", "image/svg+xml")
- icon := func() string {
- switch iconName {
- case "gemini":
- return assets.IconGemini()
- case "mailto":
- return assets.IconMailto()
- case "gopher":
- return assets.IconGopher()
- case "feed":
- return assets.IconFeed()
- default:
- return assets.IconHTTP()
- }
- }()
- _, err := io.WriteString(w, icon)
- if err != nil {
- log.Println(err)
- }
-
-}
-
-func handlerUserList(w http.ResponseWriter, rq *http.Request) {
- w.Header().Set("Content-Type", "text/html;charset=utf-8")
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(base("User list", views.UserListHTML(), user.FromRequest(rq))))
-}
-
-func handlerRobotsTxt(w http.ResponseWriter, rq *http.Request) {
- w.Header().Set("Content-Type", "text/plain")
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(
- `User-agent: *
-Allow: /page/
-Allow: /recent-changes
-Disallow: /
-Crawl-delay: 5`))
-}
-
-func prepareRq(rq *http.Request) {
- log.Println(rq.RequestURI)
- rq.URL.Path = strings.TrimSuffix(rq.URL.Path, "/")
-}
-
func main() {
parseCliArgs()
@@ -131,41 +28,20 @@ func main() {
}
log.Println("Running MycorrhizaWiki")
- if err := os.Chdir(WikiDir); err != nil {
+ if err := os.Chdir(cfg.WikiDir); err != nil {
log.Fatal(err)
}
- log.Println("Wiki storage directory is", WikiDir)
- hyphae.Index(WikiDir)
+ log.Println("Wiki storage directory is", cfg.WikiDir)
+ hyphae.Index(cfg.WikiDir)
log.Println("Indexed", hyphae.Count(), "hyphae")
- // Initialize user database
user.InitUserDatabase()
- history.Start(WikiDir)
+ history.Start(cfg.WikiDir)
shroom.SetHeaderLinks()
go handleGemini()
- // See http_admin.go for /admin, /admin/*
- initAdmin()
- // See http_readers.go for /page/, /hypha/, /text/, /binary/, /attachment/
- // See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/
- // See http_auth.go for /login, /login-data, /logout, /logout-confirm
- http.HandleFunc("/user-list/", handlerUserList)
- // See http_history.go for /history/, /recent-changes
- // See http_stuff.go for list, reindex, update-header-links, random, about
- http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(WikiDir+"/static"))))
- http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) {
- http.ServeFile(w, rq, WikiDir+"/static/favicon.ico")
- })
- http.HandleFunc("/static/common.css", handlerStyle)
- http.HandleFunc("/static/toolbar.js", handlerToolbar)
- http.HandleFunc("/assets/icon/", handlerIcon)
- http.HandleFunc("/robots.txt", handlerRobotsTxt)
- http.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) {
- addr, _ := url.Parse("/hypha/" + cfg.HomeHypha) // Let's pray it never fails
- rq.URL = addr
- handlerHypha(w, rq)
- })
+ web.Init()
log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil))
}
diff --git a/name.go b/name.go
index fd2a742..f05a44f 100644
--- a/name.go
+++ b/name.go
@@ -1,9 +1,7 @@
package main
import (
- "github.com/bouncepaw/mycorrhiza/cfg"
"log"
- "net/http"
"strings"
"git.sr.ht/~adnano/go-gemini"
@@ -11,18 +9,6 @@ import (
"github.com/bouncepaw/mycorrhiza/util"
)
-// HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha".
-func HyphaNameFromRq(rq *http.Request, actions ...string) string {
- p := rq.URL.Path
- for _, action := range actions {
- if strings.HasPrefix(p, "/"+action+"/") {
- return util.CanonicalName(strings.TrimPrefix(p, "/"+action+"/"))
- }
- }
- log.Println("HyphaNameFromRq: this request is invalid, fallback to home hypha")
- return cfg.HomeHypha
-}
-
// geminiHyphaNameFromRq extracts hypha name from gemini request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha".
func geminiHyphaNameFromRq(rq *gemini.Request, actions ...string) string {
p := rq.URL.Path
diff --git a/util/util.go b/util/util.go
index 92fcd68..1f3aced 100644
--- a/util/util.go
+++ b/util/util.go
@@ -4,12 +4,18 @@ import (
"crypto/rand"
"encoding/hex"
"github.com/bouncepaw/mycorrhiza/cfg"
+ "log"
"net/http"
"regexp"
"strings"
"unicode"
)
+func PrepareRq(rq *http.Request) {
+ log.Println(rq.RequestURI)
+ rq.URL.Path = strings.TrimSuffix(rq.URL.Path, "/")
+}
+
// LettersNumbersOnly keeps letters and numbers only in the given string.
func LettersNumbersOnly(s string) string {
var (
@@ -93,3 +99,15 @@ func IsCanonicalName(name string) bool {
func IsPossibleUsername(username string) bool {
return UsernamePattern.MatchString(strings.TrimSpace(username))
}
+
+// HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha".
+func HyphaNameFromRq(rq *http.Request, actions ...string) string {
+ p := rq.URL.Path
+ for _, action := range actions {
+ if strings.HasPrefix(p, "/"+action+"/") {
+ return CanonicalName(strings.TrimPrefix(p, "/"+action+"/"))
+ }
+ }
+ log.Println("HyphaNameFromRq: this request is invalid, fallback to home hypha")
+ return cfg.HomeHypha
+}
diff --git a/web/http_admin.go b/web/http_admin.go
new file mode 100644
index 0000000..0cd01a2
--- /dev/null
+++ b/web/http_admin.go
@@ -0,0 +1,44 @@
+package web
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/bouncepaw/mycorrhiza/cfg"
+ "github.com/bouncepaw/mycorrhiza/user"
+ "github.com/bouncepaw/mycorrhiza/util"
+ "github.com/bouncepaw/mycorrhiza/views"
+)
+
+// InitAdmin sets up /admin routes if auth is used. Call it after you have decided if you want to use auth.
+func InitAdmin() {
+ if user.AuthUsed {
+ http.HandleFunc("/admin", HandlerAdmin)
+ http.HandleFunc("/admin/shutdown", HandlerAdminShutdown)
+ http.HandleFunc("/admin/reindex-users", HandlerAdminReindexUsers)
+ }
+}
+
+func HandlerAdmin(w http.ResponseWriter, rq *http.Request) {
+ util.PrepareRq(rq)
+ if user.CanProceed(rq, "admin") {
+ w.Header().Set("Content-Type", "text/html;charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte(views.BaseHTML("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq))))
+ }
+}
+
+func HandlerAdminShutdown(w http.ResponseWriter, rq *http.Request) {
+ util.PrepareRq(rq)
+ if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" {
+ log.Fatal("An admin commanded the wiki to shutdown")
+ }
+}
+
+func HandlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) {
+ util.PrepareRq(rq)
+ if user.CanProceed(rq, "admin") && rq.Method == "POST" {
+ user.ReadUsersFromFilesystem()
+ http.Redirect(w, rq, "/hypha/"+cfg.UserHypha, http.StatusSeeOther)
+ }
+}
diff --git a/http_auth.go b/web/http_auth.go
similarity index 86%
rename from http_auth.go
rename to web/http_auth.go
index fb0337f..84cdff2 100644
--- a/http_auth.go
+++ b/web/http_auth.go
@@ -1,4 +1,4 @@
-package main
+package web
import (
"github.com/bouncepaw/mycorrhiza/cfg"
@@ -20,14 +20,14 @@ func init() {
}
func handlerRegister(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
if !cfg.UseRegistration {
w.WriteHeader(http.StatusForbidden)
}
if rq.Method == http.MethodGet {
io.WriteString(
w,
- base(
+ views.BaseHTML(
"Register",
views.RegisterHTML(rq),
user.FromRequest(rq),
@@ -61,7 +61,7 @@ func handlerLogout(w http.ResponseWriter, rq *http.Request) {
log.Println("Unknown user tries to log out")
w.WriteHeader(http.StatusForbidden)
}
- w.Write([]byte(base("Logout?", views.LogoutHTML(can), u)))
+ w.Write([]byte(views.BaseHTML("Logout?", views.LogoutHTML(can), u)))
}
func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) {
@@ -70,26 +70,26 @@ func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) {
}
func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
username = util.CanonicalName(rq.PostFormValue("username"))
password = rq.PostFormValue("password")
err = user.LoginDataHTTP(w, rq, username, password)
)
if err != "" {
- w.Write([]byte(base(err, views.LoginErrorHTML(err), user.EmptyUser())))
+ w.Write([]byte(views.BaseHTML(err, views.LoginErrorHTML(err), user.EmptyUser())))
} else {
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
}
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
if user.AuthUsed {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusForbidden)
}
- w.Write([]byte(base("Login", views.LoginHTML(), user.EmptyUser())))
+ w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser())))
}
diff --git a/http_history.go b/web/http_history.go
similarity index 86%
rename from http_history.go
rename to web/http_history.go
index e65e84b..9cba85b 100644
--- a/http_history.go
+++ b/web/http_history.go
@@ -1,4 +1,4 @@
-package main
+package web
import (
"fmt"
@@ -23,8 +23,8 @@ func init() {
// handlerHistory lists all revisions of a hypha
func handlerHistory(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
- hyphaName := HyphaNameFromRq(rq, "history")
+ util.PrepareRq(rq)
+ hyphaName := util.HyphaNameFromRq(rq, "history")
var list string
// History can be found for files that do not exist anymore.
@@ -35,25 +35,25 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) {
log.Println("Found", len(revs), "revisions for", hyphaName)
util.HTTP200Page(w,
- base(hyphaName, views.HistoryHTML(rq, hyphaName, list), user.FromRequest(rq)))
+ views.BaseHTML(hyphaName, views.HistoryHTML(rq, hyphaName, list), user.FromRequest(rq)))
}
// Recent changes
func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
noPrefix = strings.TrimPrefix(rq.URL.String(), "/recent-changes/")
n, err = strconv.Atoi(noPrefix)
)
if err == nil && n < 101 {
- util.HTTP200Page(w, base(strconv.Itoa(n)+" recent changes", views.RecentChangesHTML(n), user.FromRequest(rq)))
+ util.HTTP200Page(w, views.BaseHTML(strconv.Itoa(n)+" recent changes", views.RecentChangesHTML(n), user.FromRequest(rq)))
} else {
http.Redirect(w, rq, "/recent-changes/20", http.StatusSeeOther)
}
}
func genericHandlerOfFeeds(w http.ResponseWriter, rq *http.Request, f func() (string, error), name string) {
- prepareRq(rq)
+ util.PrepareRq(rq)
if content, err := f(); err != nil {
w.Header().Set("Content-Type", "text/plain;charset=utf-8")
w.WriteHeader(http.StatusInternalServerError)
diff --git a/http_mutators.go b/web/http_mutators.go
similarity index 93%
rename from http_mutators.go
rename to web/http_mutators.go
index a3d98aa..fd6a5fc 100644
--- a/http_mutators.go
+++ b/web/http_mutators.go
@@ -1,4 +1,4 @@
-package main
+package web
import (
"fmt"
@@ -35,9 +35,9 @@ func factoryHandlerAsker(
succPageTemplate func(*http.Request, string, bool) string,
) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
- hyphaName = HyphaNameFromRq(rq, actionPath)
+ hyphaName = util.HyphaNameFromRq(rq, actionPath)
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
)
@@ -52,7 +52,7 @@ func factoryHandlerAsker(
}
util.HTTP200Page(
w,
- base(
+ views.BaseHTML(
fmt.Sprintf(succTitleTemplate, hyphaName),
succPageTemplate(rq, hyphaName, h.Exists),
u))
@@ -85,9 +85,9 @@ func factoryHandlerConfirmer(
confirmer func(*hyphae.Hypha, *user.User, *http.Request) (*history.HistoryOp, string),
) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
- hyphaName = HyphaNameFromRq(rq, actionPath)
+ hyphaName = util.HyphaNameFromRq(rq, actionPath)
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
)
@@ -129,9 +129,9 @@ var handlerRenameConfirm = factoryHandlerConfirmer(
// handlerEdit shows the edit form. It doesn't edit anything actually.
func handlerEdit(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
- hyphaName = HyphaNameFromRq(rq, "edit")
+ hyphaName = util.HyphaNameFromRq(rq, "edit")
h = hyphae.ByName(hyphaName)
warning string
textAreaFill string
@@ -158,7 +158,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
}
util.HTTP200Page(
w,
- base(
+ views.BaseHTML(
"Edit "+hyphaName,
views.EditHTML(rq, hyphaName, textAreaFill, warning),
u))
@@ -166,9 +166,9 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
// handlerUploadText uploads a new text part for the hypha.
func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
- hyphaName = HyphaNameFromRq(rq, "upload-text")
+ hyphaName = util.HyphaNameFromRq(rq, "upload-text")
h = hyphae.ByName(hyphaName)
textData = rq.PostFormValue("text")
action = rq.PostFormValue("action")
@@ -190,7 +190,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
if action == "Preview" {
util.HTTP200Page(
w,
- base(
+ views.BaseHTML(
"Preview "+hyphaName,
views.PreviewHTML(
rq,
@@ -206,10 +206,10 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
// handlerUploadBinary uploads a new binary part for the hypha.
func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
rq.ParseMultipartForm(10 << 20) // Set upload limit
var (
- hyphaName = HyphaNameFromRq(rq, "upload-binary")
+ hyphaName = util.HyphaNameFromRq(rq, "upload-binary")
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
file, handler, err = rq.FormFile("binary")
diff --git a/http_readers.go b/web/http_readers.go
similarity index 90%
rename from http_readers.go
rename to web/http_readers.go
index 0d8e492..bd86ff4 100644
--- a/http_readers.go
+++ b/web/http_readers.go
@@ -1,4 +1,4 @@
-package main
+package web
import (
"fmt"
@@ -29,9 +29,9 @@ func init() {
}
func handlerAttachment(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
- hyphaName = HyphaNameFromRq(rq, "attachment")
+ hyphaName = util.HyphaNameFromRq(rq, "attachment")
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
)
@@ -43,7 +43,7 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) {
}
func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
shorterUrl = strings.TrimPrefix(rq.URL.Path, "/primitive-diff/")
firstSlashIndex = strings.IndexRune(shorterUrl, '/')
@@ -61,7 +61,7 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
// handlerRevision displays a specific revision of text part a page
func handlerRevision(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
shorterUrl = strings.TrimPrefix(rq.URL.Path, "/rev/")
firstSlashIndex = strings.IndexRune(shorterUrl, '/')
@@ -83,13 +83,13 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK)
- w.Write([]byte(base(util.BeautifulName(hyphaName), page, u)))
+ w.Write([]byte(views.BaseHTML(util.BeautifulName(hyphaName), page, u)))
}
// handlerText serves raw source text of the hypha.
func handlerText(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
- hyphaName := HyphaNameFromRq(rq, "text")
+ util.PrepareRq(rq)
+ hyphaName := util.HyphaNameFromRq(rq, "text")
if h := hyphae.ByName(hyphaName); h.Exists {
log.Println("Serving", h.TextPath)
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
@@ -99,8 +99,8 @@ func handlerText(w http.ResponseWriter, rq *http.Request) {
// handlerBinary serves binary part of the hypha.
func handlerBinary(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
- hyphaName := HyphaNameFromRq(rq, "binary")
+ util.PrepareRq(rq)
+ hyphaName := util.HyphaNameFromRq(rq, "binary")
if h := hyphae.ByName(hyphaName); h.Exists {
log.Println("Serving", h.BinaryPath)
w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.BinaryPath)))
@@ -110,9 +110,9 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) {
// handlerHypha is the main hypha action that displays the hypha and the binary upload form along with some navigation.
func handlerHypha(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
- hyphaName = HyphaNameFromRq(rq, "page", "hypha")
+ hyphaName = util.HyphaNameFromRq(rq, "page", "hypha")
h = hyphae.ByName(hyphaName)
contents string
openGraph string
diff --git a/http_stuff.go b/web/http_stuff.go
similarity index 87%
rename from http_stuff.go
rename to web/http_stuff.go
index 8984fc1..605a227 100644
--- a/http_stuff.go
+++ b/web/http_stuff.go
@@ -1,5 +1,5 @@
// http_stuff.go is used for meta stuff about the wiki or all hyphae at once.
-package main
+package web
import (
"github.com/bouncepaw/mycorrhiza/cfg"
@@ -25,22 +25,22 @@ func init() {
// handlerList shows a list of all hyphae in the wiki in random order.
func handlerList(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
- util.HTTP200Page(w, base("List of pages", views.HyphaListHTML(), user.FromRequest(rq)))
+ util.PrepareRq(rq)
+ util.HTTP200Page(w, views.BaseHTML("List of pages", views.HyphaListHTML(), user.FromRequest(rq)))
}
// handlerReindex reindexes all hyphae by checking the wiki storage directory anew.
func handlerReindex(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
if ok := user.CanProceed(rq, "reindex"); !ok {
HttpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be an admin to reindex hyphae.")
log.Println("Rejected", rq.URL)
return
}
hyphae.ResetCount()
- log.Println("Wiki storage directory is", WikiDir)
+ log.Println("Wiki storage directory is", cfg.WikiDir)
log.Println("Start indexing hyphae...")
- hyphae.Index(WikiDir)
+ hyphae.Index(cfg.WikiDir)
log.Println("Indexed", hyphae.Count(), "hyphae")
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
@@ -49,7 +49,7 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) {
//
// See https://mycorrhiza.lesarbr.es/hypha/configuration/header
func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
if ok := user.CanProceed(rq, "update-header-links"); !ok {
HttpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be a moderator to update header links.")
log.Println("Rejected", rq.URL)
@@ -61,7 +61,7 @@ func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
// handlerRandom redirects to a random hypha.
func handlerRandom(w http.ResponseWriter, rq *http.Request) {
- prepareRq(rq)
+ util.PrepareRq(rq)
var (
randomHyphaName string
amountOfHyphae = hyphae.Count()
@@ -85,7 +85,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) {
func handlerAbout(w http.ResponseWriter, rq *http.Request) {
w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK)
- _, err := io.WriteString(w, base("About "+cfg.WikiName, views.AboutHTML(), user.FromRequest(rq)))
+ _, err := io.WriteString(w, views.BaseHTML("About "+cfg.WikiName, views.AboutHTML(), user.FromRequest(rq)))
if err != nil {
log.Println(err)
}
diff --git a/web/web.go b/web/web.go
new file mode 100644
index 0000000..6d49f81
--- /dev/null
+++ b/web/web.go
@@ -0,0 +1,127 @@
+package web
+
+import (
+ "fmt"
+ "github.com/bouncepaw/mycorrhiza/assets"
+ "github.com/bouncepaw/mycorrhiza/cfg"
+ "github.com/bouncepaw/mycorrhiza/util"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+
+ "github.com/bouncepaw/mycorrhiza/user"
+ "github.com/bouncepaw/mycorrhiza/views"
+)
+
+// HttpErr is used by many handlers to signal errors in a compact way.
+func HttpErr(w http.ResponseWriter, status int, name, title, errMsg string) {
+ log.Println(errMsg, "for", name)
+ w.Header().Set("Content-Type", "text/html;charset=utf-8")
+ w.WriteHeader(status)
+ fmt.Fprint(
+ w,
+ views.BaseHTML(
+ title,
+ fmt.Sprintf(
+ `