diff --git a/hyphae/files.go b/hyphae/files.go index ad98fd8..082a6df 100644 --- a/hyphae/files.go +++ b/hyphae/files.go @@ -27,6 +27,8 @@ func Index(path string) { h.Insert() } } + + log.Println("Indexed", Count(), "hyphae") } // indexHelper finds all hypha files in the full `path` and sends them to the channel. Handling of duplicate entries and attachment and counting them is up to the caller. diff --git a/main.go b/main.go index da0d6e6..8f08ee6 100644 --- a/main.go +++ b/main.go @@ -32,16 +32,15 @@ func main() { log.Fatal(err) } log.Println("Wiki storage directory is", cfg.WikiDir) + + // Init the subsystems: hyphae.Index(cfg.WikiDir) - log.Println("Indexed", hyphae.Count(), "hyphae") - user.InitUserDatabase() - history.Start(cfg.WikiDir) shroom.SetHeaderLinks() + // Network: go handleGemini() - web.Init() log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil)) } diff --git a/web/http_admin.go b/web/http_admin.go index 0cd01a2..a78f884 100644 --- a/web/http_admin.go +++ b/web/http_admin.go @@ -1,6 +1,7 @@ package web import ( + "io" "log" "net/http" @@ -10,32 +11,38 @@ import ( "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() { +// 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) + http.HandleFunc("/admin", handlerAdmin) + http.HandleFunc("/admin/shutdown", handlerAdminShutdown) + http.HandleFunc("/admin/reindex-users", handlerAdminReindexUsers) } } -func HandlerAdmin(w http.ResponseWriter, rq *http.Request) { +// handlerAdmin provides the admin panel. +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)))) + _, err := io.WriteString(w, views.BaseHTML("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq))) + if err != nil { + log.Println(err) + } } } -func HandlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { +// handlerAdminShutdown kills the wiki. +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) { +// handlerAdminReindexUsers reinitialises the user system. +func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if user.CanProceed(rq, "admin") && rq.Method == "POST" { user.ReadUsersFromFilesystem() diff --git a/web/http_auth.go b/web/http_auth.go index 84cdff2..51a0c89 100644 --- a/web/http_auth.go +++ b/web/http_auth.go @@ -11,14 +11,20 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { - http.HandleFunc("/register", handlerRegister) +func initAuth() { + if !user.AuthUsed { + return + } + if cfg.UseRegistration { + http.HandleFunc("/register", handlerRegister) + } http.HandleFunc("/login", handlerLogin) http.HandleFunc("/login-data", handlerLoginData) http.HandleFunc("/logout", handlerLogout) http.HandleFunc("/logout-confirm", handlerLogoutConfirm) } +// handlerRegister both displays the register form (GET) and registers users (POST). func handlerRegister(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if !cfg.UseRegistration { @@ -48,6 +54,7 @@ func handlerRegister(w http.ResponseWriter, rq *http.Request) { } } +// handlerLogout shows the logout form. func handlerLogout(w http.ResponseWriter, rq *http.Request) { var ( u = user.FromRequest(rq) @@ -64,11 +71,29 @@ func handlerLogout(w http.ResponseWriter, rq *http.Request) { w.Write([]byte(views.BaseHTML("Logout?", views.LogoutHTML(can), u))) } +// handlerLogoutConfirm logs the user out. +// +// TODO: merge into handlerLogout as POST method. func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) { user.LogoutFromRequest(w, rq) http.Redirect(w, rq, "/", http.StatusSeeOther) } +// handlerLogin shows the login form. +func handlerLogin(w http.ResponseWriter, rq *http.Request) { + 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(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser()))) +} + +// handlerLoginData logs the user in. +// +// TODO: merge into handlerLogin as POST method. func handlerLoginData(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( @@ -82,14 +107,3 @@ func handlerLoginData(w http.ResponseWriter, rq *http.Request) { http.Redirect(w, rq, "/", http.StatusSeeOther) } } - -func handlerLogin(w http.ResponseWriter, rq *http.Request) { - 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(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser()))) -} diff --git a/web/http_history.go b/web/http_history.go index 9cba85b..0ad71a8 100644 --- a/web/http_history.go +++ b/web/http_history.go @@ -13,7 +13,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initHistory() { http.HandleFunc("/history/", handlerHistory) http.HandleFunc("/recent-changes/", handlerRecentChanges) http.HandleFunc("/recent-changes-rss", handlerRecentChangesRSS) @@ -21,7 +21,7 @@ func init() { http.HandleFunc("/recent-changes-json", handlerRecentChangesJSON) } -// handlerHistory lists all revisions of a hypha +// handlerHistory lists all revisions of a hypha. func handlerHistory(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) hyphaName := util.HyphaNameFromRq(rq, "history") @@ -38,7 +38,7 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) { views.BaseHTML(hyphaName, views.HistoryHTML(rq, hyphaName, list), user.FromRequest(rq))) } -// Recent changes +// handlerRecentChanges displays the /recent-changes/ page. func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( @@ -52,6 +52,7 @@ func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { } } +// genericHandlerOfFeeds is a helper function for the web feed handlers. func genericHandlerOfFeeds(w http.ResponseWriter, rq *http.Request, f func() (string, error), name string) { util.PrepareRq(rq) if content, err := f(); err != nil { diff --git a/web/http_mutators.go b/web/http_mutators.go index fd6a5fc..c534eff 100644 --- a/web/http_mutators.go +++ b/web/http_mutators.go @@ -14,7 +14,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initMutators() { // Those that do not actually mutate anything: http.HandleFunc("/edit/", handlerEdit) http.HandleFunc("/delete-ask/", handlerDeleteAsk) @@ -42,7 +42,7 @@ func factoryHandlerAsker( u = user.FromRequest(rq) ) if err, errtitle := asker(u, h); err != nil { - HttpErr( + httpErr( w, http.StatusInternalServerError, hyphaName, @@ -92,7 +92,7 @@ func factoryHandlerConfirmer( u = user.FromRequest(rq) ) if hop, errtitle := confirmer(h, u, rq); hop.HasErrors() { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText()) return @@ -139,7 +139,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { u = user.FromRequest(rq) ) if err, errtitle := shroom.CanEdit(u, h); err != nil { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, err.Error()) return @@ -148,7 +148,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { textAreaFill, err = shroom.FetchTextPart(h) if err != nil { log.Println(err) - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, "Error", "Could not fetch text data") return @@ -180,7 +180,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { if action != "Preview" { hop, errtitle = shroom.UploadText(h, []byte(textData), u) if hop.HasErrors() { - HttpErr(w, http.StatusForbidden, hyphaName, + httpErr(w, http.StatusForbidden, hyphaName, errtitle, hop.FirstErrorText()) return @@ -215,12 +215,12 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { file, handler, err = rq.FormFile("binary") ) if err != nil { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, "Error", err.Error()) } if err, errtitle := shroom.CanAttach(u, h); err != nil { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, err.Error()) } @@ -240,7 +240,7 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { ) if hop.HasErrors() { - HttpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText()) + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText()) return } http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther) diff --git a/web/http_readers.go b/web/http_readers.go index bd86ff4..864aa30 100644 --- a/web/http_readers.go +++ b/web/http_readers.go @@ -18,7 +18,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initReaders() { http.HandleFunc("/page/", handlerHypha) http.HandleFunc("/hypha/", handlerHypha) http.HandleFunc("/text/", handlerText) diff --git a/web/http_stuff.go b/web/http_stuff.go index 605a227..edf8c9e 100644 --- a/web/http_stuff.go +++ b/web/http_stuff.go @@ -15,7 +15,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initStuff() { http.HandleFunc("/list/", handlerList) http.HandleFunc("/reindex/", handlerReindex) http.HandleFunc("/update-header-links/", handlerUpdateHeaderLinks) @@ -33,7 +33,7 @@ func handlerList(w http.ResponseWriter, rq *http.Request) { func handlerReindex(w http.ResponseWriter, rq *http.Request) { 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.") + httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be an admin to reindex hyphae.") log.Println("Rejected", rq.URL) return } @@ -51,7 +51,7 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) { func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { 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.") + httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be a moderator to update header links.") log.Println("Rejected", rq.URL) return } @@ -67,7 +67,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) { amountOfHyphae = hyphae.Count() ) if amountOfHyphae == 0 { - HttpErr(w, http.StatusNotFound, cfg.HomeHypha, "There are no hyphae", + httpErr(w, http.StatusNotFound, cfg.HomeHypha, "There are no hyphae", "It is impossible to display a random hypha because the wiki does not contain any hyphae") return } diff --git a/web/web.go b/web/web.go index 6d49f81..7f2fa8e 100644 --- a/web/web.go +++ b/web/web.go @@ -1,3 +1,6 @@ +// Package web contains web handlers and initialization stuff. +// +// It exports just one function: Init. Call it if you want to have web capabilities. package web import ( @@ -17,8 +20,8 @@ import ( "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) { +// 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) @@ -103,14 +106,14 @@ Crawl-delay: 5`)) } func Init() { - // 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 + initAdmin() + initReaders() + initMutators() + initAuth() + initHistory() + initStuff() + 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(cfg.WikiDir+"/static")))) http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { http.ServeFile(w, rq, cfg.WikiDir+"/static/favicon.ico")