mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2025-08-08 14:54:40 +00:00
Move all web-related stuff to a new module
This commit is contained in:
parent
b53a6d5dff
commit
5b4ff5ef68
5
flag.go
5
flag.go
@ -41,9 +41,8 @@ func parseCliArgs() {
|
|||||||
log.Fatal("Error: pass a wiki directory")
|
log.Fatal("Error: pass a wiki directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
wikiDir, err := filepath.Abs(args[0])
|
||||||
WikiDir, err = filepath.Abs(args[0])
|
cfg.WikiDir = wikiDir
|
||||||
cfg.WikiDir = WikiDir
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/bouncepaw/mycorrhiza/user"
|
|
||||||
"github.com/bouncepaw/mycorrhiza/views"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is not init(), because user.AuthUsed is not set at init-stage.
|
|
||||||
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) {
|
|
||||||
prepareRq(rq)
|
|
||||||
if user.CanProceed(rq, "admin") {
|
|
||||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Write([]byte(base("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) {
|
|
||||||
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) {
|
|
||||||
prepareRq(rq)
|
|
||||||
if user.CanProceed(rq, "admin") && rq.Method == "POST" {
|
|
||||||
user.ReadUsersFromFilesystem()
|
|
||||||
http.Redirect(w, rq, "/hypha/"+cfg.UserHypha, http.StatusSeeOther)
|
|
||||||
}
|
|
||||||
}
|
|
142
main.go
142
main.go
@ -5,121 +5,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/bouncepaw/mycorrhiza/assets"
|
|
||||||
"github.com/bouncepaw/mycorrhiza/files"
|
"github.com/bouncepaw/mycorrhiza/files"
|
||||||
"github.com/bouncepaw/mycorrhiza/history"
|
"github.com/bouncepaw/mycorrhiza/history"
|
||||||
"github.com/bouncepaw/mycorrhiza/hyphae"
|
"github.com/bouncepaw/mycorrhiza/hyphae"
|
||||||
"github.com/bouncepaw/mycorrhiza/shroom"
|
"github.com/bouncepaw/mycorrhiza/shroom"
|
||||||
"github.com/bouncepaw/mycorrhiza/user"
|
"github.com/bouncepaw/mycorrhiza/user"
|
||||||
"github.com/bouncepaw/mycorrhiza/views"
|
"github.com/bouncepaw/mycorrhiza/web"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WikiDir is a rooted path to the wiki storage directory.
|
|
||||||
var WikiDir 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)
|
|
||||||
fmt.Fprint(
|
|
||||||
w,
|
|
||||||
base(
|
|
||||||
title,
|
|
||||||
fmt.Sprintf(
|
|
||||||
`<main class="main-width"><p>%s. <a href="/page/%s">Go back to the hypha.<a></p></main>`,
|
|
||||||
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() {
|
func main() {
|
||||||
parseCliArgs()
|
parseCliArgs()
|
||||||
|
|
||||||
@ -131,41 +28,20 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Running MycorrhizaWiki")
|
log.Println("Running MycorrhizaWiki")
|
||||||
if err := os.Chdir(WikiDir); err != nil {
|
if err := os.Chdir(cfg.WikiDir); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Println("Wiki storage directory is", WikiDir)
|
log.Println("Wiki storage directory is", cfg.WikiDir)
|
||||||
hyphae.Index(WikiDir)
|
hyphae.Index(cfg.WikiDir)
|
||||||
log.Println("Indexed", hyphae.Count(), "hyphae")
|
log.Println("Indexed", hyphae.Count(), "hyphae")
|
||||||
|
|
||||||
// Initialize user database
|
|
||||||
user.InitUserDatabase()
|
user.InitUserDatabase()
|
||||||
|
|
||||||
history.Start(WikiDir)
|
history.Start(cfg.WikiDir)
|
||||||
shroom.SetHeaderLinks()
|
shroom.SetHeaderLinks()
|
||||||
|
|
||||||
go handleGemini()
|
go handleGemini()
|
||||||
|
|
||||||
// See http_admin.go for /admin, /admin/*
|
web.Init()
|
||||||
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)
|
|
||||||
})
|
|
||||||
log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil))
|
log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil))
|
||||||
}
|
}
|
||||||
|
14
name.go
14
name.go
@ -1,9 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.sr.ht/~adnano/go-gemini"
|
"git.sr.ht/~adnano/go-gemini"
|
||||||
@ -11,18 +9,6 @@ import (
|
|||||||
"github.com/bouncepaw/mycorrhiza/util"
|
"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".
|
// 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 {
|
func geminiHyphaNameFromRq(rq *gemini.Request, actions ...string) string {
|
||||||
p := rq.URL.Path
|
p := rq.URL.Path
|
||||||
|
18
util/util.go
18
util/util.go
@ -4,12 +4,18 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"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.
|
// LettersNumbersOnly keeps letters and numbers only in the given string.
|
||||||
func LettersNumbersOnly(s string) string {
|
func LettersNumbersOnly(s string) string {
|
||||||
var (
|
var (
|
||||||
@ -93,3 +99,15 @@ func IsCanonicalName(name string) bool {
|
|||||||
func IsPossibleUsername(username string) bool {
|
func IsPossibleUsername(username string) bool {
|
||||||
return UsernamePattern.MatchString(strings.TrimSpace(username))
|
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
|
||||||
|
}
|
||||||
|
44
web/http_admin.go
Normal file
44
web/http_admin.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
||||||
@ -20,14 +20,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handlerRegister(w http.ResponseWriter, rq *http.Request) {
|
func handlerRegister(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
if !cfg.UseRegistration {
|
if !cfg.UseRegistration {
|
||||||
w.WriteHeader(http.StatusForbidden)
|
w.WriteHeader(http.StatusForbidden)
|
||||||
}
|
}
|
||||||
if rq.Method == http.MethodGet {
|
if rq.Method == http.MethodGet {
|
||||||
io.WriteString(
|
io.WriteString(
|
||||||
w,
|
w,
|
||||||
base(
|
views.BaseHTML(
|
||||||
"Register",
|
"Register",
|
||||||
views.RegisterHTML(rq),
|
views.RegisterHTML(rq),
|
||||||
user.FromRequest(rq),
|
user.FromRequest(rq),
|
||||||
@ -61,7 +61,7 @@ func handlerLogout(w http.ResponseWriter, rq *http.Request) {
|
|||||||
log.Println("Unknown user tries to log out")
|
log.Println("Unknown user tries to log out")
|
||||||
w.WriteHeader(http.StatusForbidden)
|
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) {
|
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) {
|
func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
username = util.CanonicalName(rq.PostFormValue("username"))
|
username = util.CanonicalName(rq.PostFormValue("username"))
|
||||||
password = rq.PostFormValue("password")
|
password = rq.PostFormValue("password")
|
||||||
err = user.LoginDataHTTP(w, rq, username, password)
|
err = user.LoginDataHTTP(w, rq, username, password)
|
||||||
)
|
)
|
||||||
if err != "" {
|
if err != "" {
|
||||||
w.Write([]byte(base(err, views.LoginErrorHTML(err), user.EmptyUser())))
|
w.Write([]byte(views.BaseHTML(err, views.LoginErrorHTML(err), user.EmptyUser())))
|
||||||
} else {
|
} else {
|
||||||
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
|
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||||
if user.AuthUsed {
|
if user.AuthUsed {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
} else {
|
} else {
|
||||||
w.WriteHeader(http.StatusForbidden)
|
w.WriteHeader(http.StatusForbidden)
|
||||||
}
|
}
|
||||||
w.Write([]byte(base("Login", views.LoginHTML(), user.EmptyUser())))
|
w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser())))
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -23,8 +23,8 @@ func init() {
|
|||||||
|
|
||||||
// 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) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
hyphaName := HyphaNameFromRq(rq, "history")
|
hyphaName := util.HyphaNameFromRq(rq, "history")
|
||||||
var list string
|
var list string
|
||||||
|
|
||||||
// History can be found for files that do not exist anymore.
|
// 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)
|
log.Println("Found", len(revs), "revisions for", hyphaName)
|
||||||
|
|
||||||
util.HTTP200Page(w,
|
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
|
// Recent changes
|
||||||
func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
|
func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
noPrefix = strings.TrimPrefix(rq.URL.String(), "/recent-changes/")
|
noPrefix = strings.TrimPrefix(rq.URL.String(), "/recent-changes/")
|
||||||
n, err = strconv.Atoi(noPrefix)
|
n, err = strconv.Atoi(noPrefix)
|
||||||
)
|
)
|
||||||
if err == nil && n < 101 {
|
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 {
|
} else {
|
||||||
http.Redirect(w, rq, "/recent-changes/20", http.StatusSeeOther)
|
http.Redirect(w, rq, "/recent-changes/20", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
if content, err := f(); err != nil {
|
if content, err := f(); err != nil {
|
||||||
w.Header().Set("Content-Type", "text/plain;charset=utf-8")
|
w.Header().Set("Content-Type", "text/plain;charset=utf-8")
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -35,9 +35,9 @@ func factoryHandlerAsker(
|
|||||||
succPageTemplate func(*http.Request, string, bool) string,
|
succPageTemplate func(*http.Request, string, bool) string,
|
||||||
) func(http.ResponseWriter, *http.Request) {
|
) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, rq *http.Request) {
|
return func(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = HyphaNameFromRq(rq, actionPath)
|
hyphaName = util.HyphaNameFromRq(rq, actionPath)
|
||||||
h = hyphae.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
)
|
)
|
||||||
@ -52,7 +52,7 @@ func factoryHandlerAsker(
|
|||||||
}
|
}
|
||||||
util.HTTP200Page(
|
util.HTTP200Page(
|
||||||
w,
|
w,
|
||||||
base(
|
views.BaseHTML(
|
||||||
fmt.Sprintf(succTitleTemplate, hyphaName),
|
fmt.Sprintf(succTitleTemplate, hyphaName),
|
||||||
succPageTemplate(rq, hyphaName, h.Exists),
|
succPageTemplate(rq, hyphaName, h.Exists),
|
||||||
u))
|
u))
|
||||||
@ -85,9 +85,9 @@ func factoryHandlerConfirmer(
|
|||||||
confirmer func(*hyphae.Hypha, *user.User, *http.Request) (*history.HistoryOp, string),
|
confirmer func(*hyphae.Hypha, *user.User, *http.Request) (*history.HistoryOp, string),
|
||||||
) func(http.ResponseWriter, *http.Request) {
|
) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, rq *http.Request) {
|
return func(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = HyphaNameFromRq(rq, actionPath)
|
hyphaName = util.HyphaNameFromRq(rq, actionPath)
|
||||||
h = hyphae.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
)
|
)
|
||||||
@ -129,9 +129,9 @@ var handlerRenameConfirm = factoryHandlerConfirmer(
|
|||||||
|
|
||||||
// handlerEdit shows the edit form. It doesn't edit anything actually.
|
// handlerEdit shows the edit form. It doesn't edit anything actually.
|
||||||
func handlerEdit(w http.ResponseWriter, rq *http.Request) {
|
func handlerEdit(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = HyphaNameFromRq(rq, "edit")
|
hyphaName = util.HyphaNameFromRq(rq, "edit")
|
||||||
h = hyphae.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
warning string
|
warning string
|
||||||
textAreaFill string
|
textAreaFill string
|
||||||
@ -158,7 +158,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
|
|||||||
}
|
}
|
||||||
util.HTTP200Page(
|
util.HTTP200Page(
|
||||||
w,
|
w,
|
||||||
base(
|
views.BaseHTML(
|
||||||
"Edit "+hyphaName,
|
"Edit "+hyphaName,
|
||||||
views.EditHTML(rq, hyphaName, textAreaFill, warning),
|
views.EditHTML(rq, hyphaName, textAreaFill, warning),
|
||||||
u))
|
u))
|
||||||
@ -166,9 +166,9 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
|
|||||||
|
|
||||||
// handlerUploadText uploads a new text part for the hypha.
|
// handlerUploadText uploads a new text part for the hypha.
|
||||||
func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
|
func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = HyphaNameFromRq(rq, "upload-text")
|
hyphaName = util.HyphaNameFromRq(rq, "upload-text")
|
||||||
h = hyphae.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
textData = rq.PostFormValue("text")
|
textData = rq.PostFormValue("text")
|
||||||
action = rq.PostFormValue("action")
|
action = rq.PostFormValue("action")
|
||||||
@ -190,7 +190,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
|
|||||||
if action == "Preview" {
|
if action == "Preview" {
|
||||||
util.HTTP200Page(
|
util.HTTP200Page(
|
||||||
w,
|
w,
|
||||||
base(
|
views.BaseHTML(
|
||||||
"Preview "+hyphaName,
|
"Preview "+hyphaName,
|
||||||
views.PreviewHTML(
|
views.PreviewHTML(
|
||||||
rq,
|
rq,
|
||||||
@ -206,10 +206,10 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
|
|||||||
|
|
||||||
// handlerUploadBinary uploads a new binary part for the hypha.
|
// handlerUploadBinary uploads a new binary part for the hypha.
|
||||||
func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
|
func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
rq.ParseMultipartForm(10 << 20) // Set upload limit
|
rq.ParseMultipartForm(10 << 20) // Set upload limit
|
||||||
var (
|
var (
|
||||||
hyphaName = HyphaNameFromRq(rq, "upload-binary")
|
hyphaName = util.HyphaNameFromRq(rq, "upload-binary")
|
||||||
h = hyphae.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
file, handler, err = rq.FormFile("binary")
|
file, handler, err = rq.FormFile("binary")
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -29,9 +29,9 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handlerAttachment(w http.ResponseWriter, rq *http.Request) {
|
func handlerAttachment(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = HyphaNameFromRq(rq, "attachment")
|
hyphaName = util.HyphaNameFromRq(rq, "attachment")
|
||||||
h = hyphae.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
)
|
)
|
||||||
@ -43,7 +43,7 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
|
func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
shorterUrl = strings.TrimPrefix(rq.URL.Path, "/primitive-diff/")
|
shorterUrl = strings.TrimPrefix(rq.URL.Path, "/primitive-diff/")
|
||||||
firstSlashIndex = strings.IndexRune(shorterUrl, '/')
|
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
|
// handlerRevision displays a specific revision of text part a page
|
||||||
func handlerRevision(w http.ResponseWriter, rq *http.Request) {
|
func handlerRevision(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
shorterUrl = strings.TrimPrefix(rq.URL.Path, "/rev/")
|
shorterUrl = strings.TrimPrefix(rq.URL.Path, "/rev/")
|
||||||
firstSlashIndex = strings.IndexRune(shorterUrl, '/')
|
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.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||||
w.WriteHeader(http.StatusOK)
|
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.
|
// handlerText serves raw source text of the hypha.
|
||||||
func handlerText(w http.ResponseWriter, rq *http.Request) {
|
func handlerText(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
hyphaName := HyphaNameFromRq(rq, "text")
|
hyphaName := util.HyphaNameFromRq(rq, "text")
|
||||||
if h := hyphae.ByName(hyphaName); h.Exists {
|
if h := hyphae.ByName(hyphaName); h.Exists {
|
||||||
log.Println("Serving", h.TextPath)
|
log.Println("Serving", h.TextPath)
|
||||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
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.
|
// handlerBinary serves binary part of the hypha.
|
||||||
func handlerBinary(w http.ResponseWriter, rq *http.Request) {
|
func handlerBinary(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
hyphaName := HyphaNameFromRq(rq, "binary")
|
hyphaName := util.HyphaNameFromRq(rq, "binary")
|
||||||
if h := hyphae.ByName(hyphaName); h.Exists {
|
if h := hyphae.ByName(hyphaName); h.Exists {
|
||||||
log.Println("Serving", h.BinaryPath)
|
log.Println("Serving", h.BinaryPath)
|
||||||
w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(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.
|
// 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) {
|
func handlerHypha(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = HyphaNameFromRq(rq, "page", "hypha")
|
hyphaName = util.HyphaNameFromRq(rq, "page", "hypha")
|
||||||
h = hyphae.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
contents string
|
contents string
|
||||||
openGraph string
|
openGraph string
|
@ -1,5 +1,5 @@
|
|||||||
// http_stuff.go is used for meta stuff about the wiki or all hyphae at once.
|
// http_stuff.go is used for meta stuff about the wiki or all hyphae at once.
|
||||||
package main
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/bouncepaw/mycorrhiza/cfg"
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
||||||
@ -25,22 +25,22 @@ func init() {
|
|||||||
|
|
||||||
// handlerList shows a list of all hyphae in the wiki in random order.
|
// handlerList shows a list of all hyphae in the wiki in random order.
|
||||||
func handlerList(w http.ResponseWriter, rq *http.Request) {
|
func handlerList(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
util.HTTP200Page(w, base("List of pages", views.HyphaListHTML(), user.FromRequest(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.
|
// handlerReindex reindexes all hyphae by checking the wiki storage directory anew.
|
||||||
func handlerReindex(w http.ResponseWriter, rq *http.Request) {
|
func handlerReindex(w http.ResponseWriter, rq *http.Request) {
|
||||||
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
|
||||||
}
|
}
|
||||||
hyphae.ResetCount()
|
hyphae.ResetCount()
|
||||||
log.Println("Wiki storage directory is", WikiDir)
|
log.Println("Wiki storage directory is", cfg.WikiDir)
|
||||||
log.Println("Start indexing hyphae...")
|
log.Println("Start indexing hyphae...")
|
||||||
hyphae.Index(WikiDir)
|
hyphae.Index(cfg.WikiDir)
|
||||||
log.Println("Indexed", hyphae.Count(), "hyphae")
|
log.Println("Indexed", hyphae.Count(), "hyphae")
|
||||||
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
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
|
// See https://mycorrhiza.lesarbr.es/hypha/configuration/header
|
||||||
func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
|
func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
|
||||||
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)
|
||||||
@ -61,7 +61,7 @@ func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
|
|||||||
|
|
||||||
// handlerRandom redirects to a random hypha.
|
// handlerRandom redirects to a random hypha.
|
||||||
func handlerRandom(w http.ResponseWriter, rq *http.Request) {
|
func handlerRandom(w http.ResponseWriter, rq *http.Request) {
|
||||||
prepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
randomHyphaName string
|
randomHyphaName string
|
||||||
amountOfHyphae = hyphae.Count()
|
amountOfHyphae = hyphae.Count()
|
||||||
@ -85,7 +85,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) {
|
|||||||
func handlerAbout(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.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||||
w.WriteHeader(http.StatusOK)
|
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 {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
127
web/web.go
Normal file
127
web/web.go
Normal file
@ -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(
|
||||||
|
`<main class="main-width"><p>%s. <a href="/page/%s">Go back to the hypha.<a></p></main>`,
|
||||||
|
errMsg,
|
||||||
|
name,
|
||||||
|
),
|
||||||
|
user.EmptyUser(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlerStyle(w http.ResponseWriter, rq *http.Request) {
|
||||||
|
util.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) {
|
||||||
|
util.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(views.BaseHTML("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 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
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user