1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 03:36:16 +00:00

Reorganise and document the web stuff a little

This commit is contained in:
Timur Ismagilov 2021-05-09 16:09:27 +05:00
parent 5b4ff5ef68
commit d69ce77251
9 changed files with 78 additions and 52 deletions

View File

@ -27,6 +27,8 @@ func Index(path string) {
h.Insert() 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. // 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.

View File

@ -32,16 +32,15 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
log.Println("Wiki storage directory is", cfg.WikiDir) log.Println("Wiki storage directory is", cfg.WikiDir)
// Init the subsystems:
hyphae.Index(cfg.WikiDir) hyphae.Index(cfg.WikiDir)
log.Println("Indexed", hyphae.Count(), "hyphae")
user.InitUserDatabase() user.InitUserDatabase()
history.Start(cfg.WikiDir) history.Start(cfg.WikiDir)
shroom.SetHeaderLinks() shroom.SetHeaderLinks()
// Network:
go handleGemini() go handleGemini()
web.Init() web.Init()
log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil)) log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil))
} }

View File

@ -1,6 +1,7 @@
package web package web
import ( import (
"io"
"log" "log"
"net/http" "net/http"
@ -10,32 +11,38 @@ import (
"github.com/bouncepaw/mycorrhiza/views" "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. // initAdmin sets up /admin routes if auth is used. Call it after you have decided if you want to use auth.
func InitAdmin() { func initAdmin() {
if user.AuthUsed { if user.AuthUsed {
http.HandleFunc("/admin", HandlerAdmin) http.HandleFunc("/admin", handlerAdmin)
http.HandleFunc("/admin/shutdown", HandlerAdminShutdown) http.HandleFunc("/admin/shutdown", handlerAdminShutdown)
http.HandleFunc("/admin/reindex-users", HandlerAdminReindexUsers) 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) util.PrepareRq(rq)
if user.CanProceed(rq, "admin") { if user.CanProceed(rq, "admin") {
w.Header().Set("Content-Type", "text/html;charset=utf-8") w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK) 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) util.PrepareRq(rq)
if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" { if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" {
log.Fatal("An admin commanded the wiki to shutdown") 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) util.PrepareRq(rq)
if user.CanProceed(rq, "admin") && rq.Method == "POST" { if user.CanProceed(rq, "admin") && rq.Method == "POST" {
user.ReadUsersFromFilesystem() user.ReadUsersFromFilesystem()

View File

@ -11,14 +11,20 @@ import (
"github.com/bouncepaw/mycorrhiza/views" "github.com/bouncepaw/mycorrhiza/views"
) )
func init() { func initAuth() {
http.HandleFunc("/register", handlerRegister) if !user.AuthUsed {
return
}
if cfg.UseRegistration {
http.HandleFunc("/register", handlerRegister)
}
http.HandleFunc("/login", handlerLogin) http.HandleFunc("/login", handlerLogin)
http.HandleFunc("/login-data", handlerLoginData) http.HandleFunc("/login-data", handlerLoginData)
http.HandleFunc("/logout", handlerLogout) http.HandleFunc("/logout", handlerLogout)
http.HandleFunc("/logout-confirm", handlerLogoutConfirm) http.HandleFunc("/logout-confirm", handlerLogoutConfirm)
} }
// handlerRegister both displays the register form (GET) and registers users (POST).
func handlerRegister(w http.ResponseWriter, rq *http.Request) { func handlerRegister(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq) util.PrepareRq(rq)
if !cfg.UseRegistration { 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) { func handlerLogout(w http.ResponseWriter, rq *http.Request) {
var ( var (
u = user.FromRequest(rq) 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))) 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) { func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) {
user.LogoutFromRequest(w, rq) user.LogoutFromRequest(w, rq)
http.Redirect(w, rq, "/", http.StatusSeeOther) 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) { func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq) util.PrepareRq(rq)
var ( var (
@ -82,14 +107,3 @@ func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
http.Redirect(w, rq, "/", http.StatusSeeOther) 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())))
}

View File

@ -13,7 +13,7 @@ import (
"github.com/bouncepaw/mycorrhiza/views" "github.com/bouncepaw/mycorrhiza/views"
) )
func init() { func initHistory() {
http.HandleFunc("/history/", handlerHistory) http.HandleFunc("/history/", handlerHistory)
http.HandleFunc("/recent-changes/", handlerRecentChanges) http.HandleFunc("/recent-changes/", handlerRecentChanges)
http.HandleFunc("/recent-changes-rss", handlerRecentChangesRSS) http.HandleFunc("/recent-changes-rss", handlerRecentChangesRSS)
@ -21,7 +21,7 @@ func init() {
http.HandleFunc("/recent-changes-json", handlerRecentChangesJSON) 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) { func handlerHistory(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq) util.PrepareRq(rq)
hyphaName := util.HyphaNameFromRq(rq, "history") 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))) 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) { func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq) util.PrepareRq(rq)
var ( 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) { func genericHandlerOfFeeds(w http.ResponseWriter, rq *http.Request, f func() (string, error), name string) {
util.PrepareRq(rq) util.PrepareRq(rq)
if content, err := f(); err != nil { if content, err := f(); err != nil {

View File

@ -14,7 +14,7 @@ import (
"github.com/bouncepaw/mycorrhiza/views" "github.com/bouncepaw/mycorrhiza/views"
) )
func init() { func initMutators() {
// Those that do not actually mutate anything: // Those that do not actually mutate anything:
http.HandleFunc("/edit/", handlerEdit) http.HandleFunc("/edit/", handlerEdit)
http.HandleFunc("/delete-ask/", handlerDeleteAsk) http.HandleFunc("/delete-ask/", handlerDeleteAsk)
@ -42,7 +42,7 @@ func factoryHandlerAsker(
u = user.FromRequest(rq) u = user.FromRequest(rq)
) )
if err, errtitle := asker(u, h); err != nil { if err, errtitle := asker(u, h); err != nil {
HttpErr( httpErr(
w, w,
http.StatusInternalServerError, http.StatusInternalServerError,
hyphaName, hyphaName,
@ -92,7 +92,7 @@ func factoryHandlerConfirmer(
u = user.FromRequest(rq) u = user.FromRequest(rq)
) )
if hop, errtitle := confirmer(h, u, rq); hop.HasErrors() { if hop, errtitle := confirmer(h, u, rq); hop.HasErrors() {
HttpErr(w, http.StatusInternalServerError, hyphaName, httpErr(w, http.StatusInternalServerError, hyphaName,
errtitle, errtitle,
hop.FirstErrorText()) hop.FirstErrorText())
return return
@ -139,7 +139,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
u = user.FromRequest(rq) u = user.FromRequest(rq)
) )
if err, errtitle := shroom.CanEdit(u, h); err != nil { if err, errtitle := shroom.CanEdit(u, h); err != nil {
HttpErr(w, http.StatusInternalServerError, hyphaName, httpErr(w, http.StatusInternalServerError, hyphaName,
errtitle, errtitle,
err.Error()) err.Error())
return return
@ -148,7 +148,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
textAreaFill, err = shroom.FetchTextPart(h) textAreaFill, err = shroom.FetchTextPart(h)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
HttpErr(w, http.StatusInternalServerError, hyphaName, httpErr(w, http.StatusInternalServerError, hyphaName,
"Error", "Error",
"Could not fetch text data") "Could not fetch text data")
return return
@ -180,7 +180,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
if action != "Preview" { if action != "Preview" {
hop, errtitle = shroom.UploadText(h, []byte(textData), u) hop, errtitle = shroom.UploadText(h, []byte(textData), u)
if hop.HasErrors() { if hop.HasErrors() {
HttpErr(w, http.StatusForbidden, hyphaName, httpErr(w, http.StatusForbidden, hyphaName,
errtitle, errtitle,
hop.FirstErrorText()) hop.FirstErrorText())
return return
@ -215,12 +215,12 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
file, handler, err = rq.FormFile("binary") file, handler, err = rq.FormFile("binary")
) )
if err != nil { if err != nil {
HttpErr(w, http.StatusInternalServerError, hyphaName, httpErr(w, http.StatusInternalServerError, hyphaName,
"Error", "Error",
err.Error()) err.Error())
} }
if err, errtitle := shroom.CanAttach(u, h); err != nil { if err, errtitle := shroom.CanAttach(u, h); err != nil {
HttpErr(w, http.StatusInternalServerError, hyphaName, httpErr(w, http.StatusInternalServerError, hyphaName,
errtitle, errtitle,
err.Error()) err.Error())
} }
@ -240,7 +240,7 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
) )
if hop.HasErrors() { if hop.HasErrors() {
HttpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText()) httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText())
return return
} }
http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther) http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther)

View File

@ -18,7 +18,7 @@ import (
"github.com/bouncepaw/mycorrhiza/views" "github.com/bouncepaw/mycorrhiza/views"
) )
func init() { func initReaders() {
http.HandleFunc("/page/", handlerHypha) http.HandleFunc("/page/", handlerHypha)
http.HandleFunc("/hypha/", handlerHypha) http.HandleFunc("/hypha/", handlerHypha)
http.HandleFunc("/text/", handlerText) http.HandleFunc("/text/", handlerText)

View File

@ -15,7 +15,7 @@ import (
"github.com/bouncepaw/mycorrhiza/views" "github.com/bouncepaw/mycorrhiza/views"
) )
func init() { func initStuff() {
http.HandleFunc("/list/", handlerList) http.HandleFunc("/list/", handlerList)
http.HandleFunc("/reindex/", handlerReindex) http.HandleFunc("/reindex/", handlerReindex)
http.HandleFunc("/update-header-links/", handlerUpdateHeaderLinks) 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) { func handlerReindex(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq) util.PrepareRq(rq)
if ok := user.CanProceed(rq, "reindex"); !ok { 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) log.Println("Rejected", rq.URL)
return return
} }
@ -51,7 +51,7 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) {
func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq) util.PrepareRq(rq)
if ok := user.CanProceed(rq, "update-header-links"); !ok { 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) log.Println("Rejected", rq.URL)
return return
} }
@ -67,7 +67,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) {
amountOfHyphae = hyphae.Count() amountOfHyphae = hyphae.Count()
) )
if amountOfHyphae == 0 { 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") "It is impossible to display a random hypha because the wiki does not contain any hyphae")
return return
} }

View File

@ -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 package web
import ( import (
@ -17,8 +20,8 @@ import (
"github.com/bouncepaw/mycorrhiza/views" "github.com/bouncepaw/mycorrhiza/views"
) )
// HttpErr is used by many handlers to signal errors in a compact way. // httpErr is used by many handlers to signal errors in a compact way.
func HttpErr(w http.ResponseWriter, status int, name, title, errMsg string) { func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) {
log.Println(errMsg, "for", name) log.Println(errMsg, "for", name)
w.Header().Set("Content-Type", "text/html;charset=utf-8") w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(status) w.WriteHeader(status)
@ -103,14 +106,14 @@ Crawl-delay: 5`))
} }
func Init() { func Init() {
// See http_admin.go for /admin, /admin/* initAdmin()
InitAdmin() initReaders()
// See http_readers.go for /page/, /hypha/, /text/, /binary/, /attachment/ initMutators()
// See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/ initAuth()
// See http_auth.go for /login, /login-data, /logout, /logout-confirm initHistory()
initStuff()
http.HandleFunc("/user-list/", handlerUserList) 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.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(cfg.WikiDir+"/static"))))
http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) {
http.ServeFile(w, rq, cfg.WikiDir+"/static/favicon.ico") http.ServeFile(w, rq, cfg.WikiDir+"/static/favicon.ico")