1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-06-26 23:12:51 +00:00

Migrate from log to slog #109 (#255)

* Migrate httpd.go

* Migrate history and main

* Migrate hypview

* Migrate interwiki

* Migrate misc

* Migrate utils

* Migrate backlinks

* Migrate categories

* Reformat some imports

* Migrate hyphae

* Migrate migration

* Reformat more imports

* Migrate user

* Migrate shroom

* Migrate viewutil

* Migrate web

* Migrate others

* Migrate main

* Wording concerns
This commit is contained in:
Timur Ismagilov 2024-09-07 23:55:39 +03:00 committed by GitHub
parent 4c5f385afd
commit a4cc67cd74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 499 additions and 348 deletions

41
flag.go
View File

@ -3,19 +3,20 @@ package main
import ( import (
"bufio" "bufio"
_ "embed" _ "embed"
"errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"log" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"golang.org/x/term"
"github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/files" "github.com/bouncepaw/mycorrhiza/internal/files"
user2 "github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/internal/version" "github.com/bouncepaw/mycorrhiza/internal/version"
"golang.org/x/term"
) )
// CLI options are read and parsed here. // CLI options are read and parsed here.
@ -31,7 +32,7 @@ func printHelp() {
} }
// parseCliArgs parses CLI options and sets several important global variables. Call it early. // parseCliArgs parses CLI options and sets several important global variables. Call it early.
func parseCliArgs() { func parseCliArgs() error {
var createAdminName string var createAdminName string
var versionFlag bool var versionFlag bool
@ -42,43 +43,53 @@ func parseCliArgs() {
flag.Parse() flag.Parse()
if versionFlag { if versionFlag {
fmt.Println("Mycorrhiza Wiki", version.Long) slog.Info("Running Mycorrhiza Wiki", "version", version.Long)
os.Exit(0) os.Exit(0)
} }
args := flag.Args() args := flag.Args()
if len(args) == 0 { if len(args) == 0 {
log.Fatal("error: pass a wiki directory") slog.Error("Pass a wiki directory")
return errors.New("wiki directory not passed")
} }
wikiDir, err := filepath.Abs(args[0]) wikiDir, err := filepath.Abs(args[0])
if err != nil { if err != nil {
log.Fatal(err) slog.Error("Failed to take absolute filepath of wiki directory",
"path", args[0], "err", err)
return err
} }
cfg.WikiDir = wikiDir cfg.WikiDir = wikiDir
if createAdminName != "" { if createAdminName != "" {
createAdminCommand(createAdminName) if err := createAdminCommand(createAdminName); err != nil {
os.Exit(1)
}
os.Exit(0) os.Exit(0)
} }
return nil
} }
func createAdminCommand(name string) { func createAdminCommand(name string) error {
if err := files.PrepareWikiRoot(); err != nil { if err := files.PrepareWikiRoot(); err != nil {
log.Fatal(err) slog.Error("Failed to prepare wiki root", "err", err)
return err
} }
cfg.UseAuth = true cfg.UseAuth = true
cfg.AllowRegistration = true cfg.AllowRegistration = true
user2.InitUserDatabase() user.InitUserDatabase()
password, err := askPass("Password") password, err := askPass("Password")
if err != nil { if err != nil {
log.Fatal(err) slog.Error("Failed to prompt password", "err", err)
return err
} }
if err := user2.Register(name, password, "admin", "local", true); err != nil { if err := user.Register(name, password, "admin", "local", true); err != nil {
log.Fatal(err) slog.Error("Failed to register admin", "err", err)
return err
} }
return nil
} }
func askPass(prompt string) (string, error) { func askPass(prompt string) (string, error) {

View File

@ -3,11 +3,12 @@ package history
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"net/url" "net/url"
"strings" "strings"
"time" "time"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/gorilla/feeds" "github.com/gorilla/feeds"
) )

View File

@ -4,7 +4,7 @@ package history
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"log" "log/slog"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
@ -21,12 +21,14 @@ var renameMsgPattern = regexp.MustCompile(`^Rename (.*) to .*`)
var gitEnv = []string{"GIT_COMMITTER_NAME=wikimind", "GIT_COMMITTER_EMAIL=wikimind@mycorrhiza"} var gitEnv = []string{"GIT_COMMITTER_NAME=wikimind", "GIT_COMMITTER_EMAIL=wikimind@mycorrhiza"}
// Start finds git and initializes git credentials. // Start finds git and initializes git credentials.
func Start() { func Start() error {
path, err := exec.LookPath("git") path, err := exec.LookPath("git")
if err != nil { if err != nil {
log.Fatal("Could not find the git executable. Check your $PATH.") slog.Error("Could not find the Git executable. Check your $PATH.")
return err
} }
gitpath = path gitpath = path
return nil
} }
// InitGitRepo checks a Git repository and initializes it if necessary. // InitGitRepo checks a Git repository and initializes it if necessary.
@ -44,7 +46,7 @@ func InitGitRepo() {
} }
} }
if !isGitRepo { if !isGitRepo {
log.Println("Initializing Git repo at", files.HyphaeDir()) slog.Info("Initializing Git repo", "path", files.HyphaeDir())
gitsh("init") gitsh("init")
gitsh("config", "core.quotePath", "false") gitsh("config", "core.quotePath", "false")
} }
@ -60,7 +62,7 @@ func gitsh(args ...string) (out bytes.Buffer, err error) {
b, err := cmd.CombinedOutput() b, err := cmd.CombinedOutput()
if err != nil { if err != nil {
log.Println("gitsh:", err) slog.Info("Git command failed", "err", err, "output", string(b))
} }
return *bytes.NewBuffer(b), err return *bytes.NewBuffer(b), err
} }
@ -77,7 +79,9 @@ func silentGitsh(args ...string) (out bytes.Buffer, err error) {
// Rename renames from `from` to `to` using `git mv`. // Rename renames from `from` to `to` using `git mv`.
func Rename(from, to string) error { func Rename(from, to string) error {
log.Println(util.ShorterPath(from), util.ShorterPath(to)) slog.Info("Renaming file with git mv",
"from", util.ShorterPath(from),
"to", util.ShorterPath(to))
_, err := gitsh("mv", "--force", from, to) _, err := gitsh("mv", "--force", from, to)
return err return err
} }

View File

@ -4,19 +4,21 @@ package histweb
import ( import (
"embed" "embed"
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/files"
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/util"
viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil"
"github.com/gorilla/mux"
"html/template" "html/template"
"log" "log/slog"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/files"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"github.com/gorilla/mux"
) )
func InitHandlers(rtr *mux.Router) { func InitHandlers(rtr *mux.Router) {
@ -30,9 +32,9 @@ func InitHandlers(rtr *mux.Router) {
rtr.HandleFunc("/recent-changes-atom", handlerRecentChangesAtom) rtr.HandleFunc("/recent-changes-atom", handlerRecentChangesAtom)
rtr.HandleFunc("/recent-changes-json", handlerRecentChangesJSON) rtr.HandleFunc("/recent-changes-json", handlerRecentChangesJSON)
chainPrimitiveDiff = viewutil2.CopyEnRuWith(fs, "view_primitive_diff.html", ruTranslation) chainPrimitiveDiff = viewutil.CopyEnRuWith(fs, "view_primitive_diff.html", ruTranslation)
chainRecentChanges = viewutil2.CopyEnRuWith(fs, "view_recent_changes.html", ruTranslation) chainRecentChanges = viewutil.CopyEnRuWith(fs, "view_recent_changes.html", ruTranslation)
chainHistory = viewutil2.CopyEnRuWith(fs, "view_history.html", ruTranslation) chainHistory = viewutil.CopyEnRuWith(fs, "view_history.html", ruTranslation)
} }
func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
@ -45,12 +47,12 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
} }
var ( var (
mycoFilePath string mycoFilePath string
h = hyphae2.ByName(util.CanonicalName(slug)) h = hyphae.ByName(util.CanonicalName(slug))
) )
switch h := h.(type) { switch h := h.(type) {
case hyphae2.ExistingHypha: case hyphae.ExistingHypha:
mycoFilePath = h.TextFilePath() mycoFilePath = h.TextFilePath()
case *hyphae2.EmptyHypha: case *hyphae.EmptyHypha:
mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco") mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")
} }
text, err := history.PrimitiveDiffAtRevision(mycoFilePath, revHash) text, err := history.PrimitiveDiffAtRevision(mycoFilePath, revHash)
@ -58,7 +60,7 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
primitiveDiff(viewutil2.MetaFrom(w, rq), h, revHash, text) primitiveDiff(viewutil.MetaFrom(w, rq), h, revHash, text)
} }
// handlerRecentChanges displays the /recent-changes/ page. // handlerRecentChanges displays the /recent-changes/ page.
@ -68,7 +70,7 @@ func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
if editCount > 100 { if editCount > 100 {
return return
} }
recentChanges(viewutil2.MetaFrom(w, rq), editCount, history.RecentChanges(editCount)) recentChanges(viewutil.MetaFrom(w, rq), editCount, history.RecentChanges(editCount))
} }
// handlerHistory lists all revisions of a hypha. // handlerHistory lists all revisions of a hypha.
@ -81,9 +83,11 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) {
if err == nil { if err == nil {
list = history.WithRevisions(hyphaName, revs) list = history.WithRevisions(hyphaName, revs)
} }
log.Println("Found", len(revs), "revisions for", hyphaName)
historyView(viewutil2.MetaFrom(w, rq), hyphaName, list) // TODO: extra log, not needed?
slog.Info("Found revisions", "hyphaName", hyphaName, "n", len(revs), "err", err)
historyView(viewutil.MetaFrom(w, rq), hyphaName, list)
} }
// genericHandlerOfFeeds is a helper function for the web feed handlers. // genericHandlerOfFeeds is a helper function for the web feed handlers.
@ -135,20 +139,20 @@ var (
{{define "n recent changes"}}{{.}} свеж{{if eq . 1}}ая правка{{else if le . 4}}их правок{{else}}их правок{{end}}{{end}} {{define "n recent changes"}}{{.}} свеж{{if eq . 1}}ая правка{{else if le . 4}}их правок{{else}}их правок{{end}}{{end}}
{{define "recent empty"}}Правки не найдены.{{end}} {{define "recent empty"}}Правки не найдены.{{end}}
` `
chainPrimitiveDiff, chainRecentChanges, chainHistory viewutil2.Chain chainPrimitiveDiff, chainRecentChanges, chainHistory viewutil.Chain
) )
type recentChangesData struct { type recentChangesData struct {
*viewutil2.BaseData *viewutil.BaseData
EditCount int EditCount int
Changes []history.Revision Changes []history.Revision
UserHypha string UserHypha string
Stops []int Stops []int
} }
func recentChanges(meta viewutil2.Meta, editCount int, changes []history.Revision) { func recentChanges(meta viewutil.Meta, editCount int, changes []history.Revision) {
viewutil2.ExecutePage(meta, chainRecentChanges, recentChangesData{ viewutil.ExecutePage(meta, chainRecentChanges, recentChangesData{
BaseData: &viewutil2.BaseData{}, BaseData: &viewutil.BaseData{},
EditCount: editCount, EditCount: editCount,
Changes: changes, Changes: changes,
UserHypha: cfg.UserHypha, UserHypha: cfg.UserHypha,
@ -157,13 +161,13 @@ func recentChanges(meta viewutil2.Meta, editCount int, changes []history.Revisio
} }
type primitiveDiffData struct { type primitiveDiffData struct {
*viewutil2.BaseData *viewutil.BaseData
HyphaName string HyphaName string
Hash string Hash string
Text template.HTML Text template.HTML
} }
func primitiveDiff(meta viewutil2.Meta, h hyphae2.Hypha, hash, text string) { func primitiveDiff(meta viewutil.Meta, h hyphae.Hypha, hash, text string) {
hunks := history.SplitPrimitiveDiff(text) hunks := history.SplitPrimitiveDiff(text)
if len(hunks) > 0 { if len(hunks) > 0 {
var buf strings.Builder var buf strings.Builder
@ -198,8 +202,8 @@ func primitiveDiff(meta viewutil2.Meta, h hyphae2.Hypha, hash, text string) {
text = fmt.Sprintf( text = fmt.Sprintf(
`<pre class="codeblock"><code>%s</code></pre>`, text) `<pre class="codeblock"><code>%s</code></pre>`, text)
} }
viewutil2.ExecutePage(meta, chainPrimitiveDiff, primitiveDiffData{ viewutil.ExecutePage(meta, chainPrimitiveDiff, primitiveDiffData{
BaseData: &viewutil2.BaseData{}, BaseData: &viewutil.BaseData{},
HyphaName: h.CanonicalName(), HyphaName: h.CanonicalName(),
Hash: hash, Hash: hash,
Text: template.HTML(text), Text: template.HTML(text),
@ -207,14 +211,14 @@ func primitiveDiff(meta viewutil2.Meta, h hyphae2.Hypha, hash, text string) {
} }
type historyData struct { type historyData struct {
*viewutil2.BaseData *viewutil.BaseData
HyphaName string HyphaName string
Contents string Contents string
} }
func historyView(meta viewutil2.Meta, hyphaName, contents string) { func historyView(meta viewutil.Meta, hyphaName, contents string) {
viewutil2.ExecutePage(meta, chainHistory, historyData{ viewutil.ExecutePage(meta, chainHistory, historyData{
BaseData: &viewutil2.BaseData{ BaseData: &viewutil.BaseData{
Addr: "/history/" + util.CanonicalName(hyphaName), Addr: "/history/" + util.CanonicalName(hyphaName),
}, },
HyphaName: hyphaName, HyphaName: hyphaName,

View File

@ -4,11 +4,11 @@ package history
// Things related to writing history. // Things related to writing history.
import ( import (
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/user"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
) )

View File

@ -2,7 +2,8 @@ package history
import ( import (
"fmt" "fmt"
"log" "log/slog"
"os"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -11,9 +12,11 @@ import (
"github.com/bouncepaw/mycorrhiza/internal/files" "github.com/bouncepaw/mycorrhiza/internal/files"
) )
// Revision represents a revision, duh. Hash is usually short. Username is extracted from email. // Revision represents a revision of a hypha.
type Revision struct { type Revision struct {
Hash string // Hash is usually short.
Hash string
// Username is extracted from email.
Username string Username string
Time time.Time Time time.Time
Message string Message string
@ -71,7 +74,9 @@ func (stream *recentChangesStream) next(n int) []Revision {
res, err := gitLog(args...) res, err := gitLog(args...)
if err != nil { if err != nil {
log.Fatal(err) // TODO: return error
slog.Error("Failed to git log", "err", err)
os.Exit(1)
} }
if len(res) != 0 { if len(res) != 0 {
stream.currHash = res[len(res)-1].Hash stream.currHash = res[len(res)-1].Hash
@ -103,14 +108,14 @@ func (stream recentChangesStream) iterator() func() (Revision, bool) {
func RecentChanges(n int) []Revision { func RecentChanges(n int) []Revision {
stream := newRecentChangesStream() stream := newRecentChangesStream()
revs := stream.next(n) revs := stream.next(n)
log.Printf("Found %d recent changes", len(revs)) slog.Info("Found recent changes", "n", len(revs))
return revs return revs
} }
// Revisions returns slice of revisions for the given hypha name, ordered most recent first. // Revisions returns slice of revisions for the given hypha name, ordered most recent first.
func Revisions(hyphaName string) ([]Revision, error) { func Revisions(hyphaName string) ([]Revision, error) {
revs, err := gitLog("--", hyphaName+".*") revs, err := gitLog("--", hyphaName+".*")
log.Printf("Found %d revisions for %s\n", len(revs), hyphaName) slog.Info("Found revisions", "hyphaName", hyphaName, "n", len(revs), "err", err)
return revs, err return revs, err
} }

View File

@ -1,16 +1,18 @@
package main package main
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/cfg" "errors"
"log" "log/slog"
"net" "net"
"net/http" "net/http"
"os" "os"
"strings" "strings"
"time" "time"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
) )
func serveHTTP(handler http.Handler) { func serveHTTP(handler http.Handler) (err error) {
server := &http.Server{ server := &http.Server{
ReadTimeout: 300 * time.Second, ReadTimeout: 300 * time.Second,
WriteTimeout: 300 * time.Second, WriteTimeout: 300 * time.Second,
@ -19,35 +21,51 @@ func serveHTTP(handler http.Handler) {
} }
if strings.HasPrefix(cfg.ListenAddr, "/") { if strings.HasPrefix(cfg.ListenAddr, "/") {
startUnixSocketServer(server, cfg.ListenAddr) err = startUnixSocketServer(server, cfg.ListenAddr)
} else { } else {
server.Addr = cfg.ListenAddr server.Addr = cfg.ListenAddr
startHTTPServer(server) err = startHTTPServer(server)
} }
return err
} }
func startUnixSocketServer(server *http.Server, socketFile string) { func startUnixSocketServer(server *http.Server, socketPath string) error {
os.Remove(socketFile) err := os.Remove(socketPath)
listener, err := net.Listen("unix", socketFile)
if err != nil { if err != nil {
log.Fatalf("Failed to start a server: %v", err) return err
}
defer listener.Close()
if err := os.Chmod(socketFile, 0666); err != nil {
log.Fatalf("Failed to set socket permissions: %v", err)
} }
log.Printf("Listening on Unix socket %s", cfg.ListenAddr) listener, err := net.Listen("unix", socketPath)
if err := server.Serve(listener); err != http.ErrServerClosed { if err != nil {
log.Fatalf("Failed to start a server: %v", err) slog.Error("Failed to start the server", "err", err)
return err
} }
defer func(listener net.Listener) {
_ = listener.Close()
}(listener)
if err := os.Chmod(socketPath, 0666); err != nil {
slog.Error("Failed to set socket permissions", "err", err)
return err
}
slog.Info("Listening Unix socket", "addr", socketPath)
if err := server.Serve(listener); !errors.Is(err, http.ErrServerClosed) {
slog.Error("Failed to start the server", "err", err)
return err
}
return nil
} }
func startHTTPServer(server *http.Server) { func startHTTPServer(server *http.Server) error {
log.Printf("Listening on %s", server.Addr) slog.Info("Listening over HTTP", "addr", server.Addr)
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("Failed to start a server: %v", err) if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
slog.Error("Failed to start the server", "err", err)
return err
} }
return nil
} }

View File

@ -3,7 +3,7 @@ package hypview
import ( import (
"embed" "embed"
"html/template" "html/template"
"log" "log/slog"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/internal/backlinks" "github.com/bouncepaw/mycorrhiza/internal/backlinks"
@ -66,7 +66,7 @@ func NaviTitle(meta viewutil.Meta, hyphaName string) template.HTML {
HomeHypha: cfg.HomeHypha, HomeHypha: cfg.HomeHypha,
}) })
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to render NaviTitle properly; using nevertheless", "err", err)
} }
return template.HTML(buf.String()) return template.HTML(buf.String())
} }

View File

@ -2,8 +2,8 @@
package backlinks package backlinks
import ( import (
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"log" "log/slog"
"os" "os"
"sort" "sort"
@ -14,7 +14,7 @@ import (
func yieldHyphaBacklinks(hyphaName string) <-chan string { func yieldHyphaBacklinks(hyphaName string) <-chan string {
hyphaName = util.CanonicalName(hyphaName) hyphaName = util.CanonicalName(hyphaName)
out := make(chan string) out := make(chan string)
sorted := hyphae2.PathographicSort(out) sorted := hyphae.PathographicSort(out)
go func() { go func() {
backlinks, exists := backlinkIndex[hyphaName] backlinks, exists := backlinkIndex[hyphaName]
if exists { if exists {
@ -43,7 +43,7 @@ var backlinkIndex = make(map[string]linkSet)
// IndexBacklinks traverses all text hyphae, extracts links from them and forms an initial index. Call it when indexing and reindexing hyphae. // IndexBacklinks traverses all text hyphae, extracts links from them and forms an initial index. Call it when indexing and reindexing hyphae.
func IndexBacklinks() { func IndexBacklinks() {
// It is safe to ignore the mutex, because there is only one worker. // It is safe to ignore the mutex, because there is only one worker.
for h := range hyphae2.FilterHyphaeWithText(hyphae2.YieldExistingHyphae()) { for h := range hyphae.FilterHyphaeWithText(hyphae.YieldExistingHyphae()) {
foundLinks := extractHyphaLinksFromContent(h.CanonicalName(), fetchText(h)) foundLinks := extractHyphaLinksFromContent(h.CanonicalName(), fetchText(h))
for _, link := range foundLinks { for _, link := range foundLinks {
if _, exists := backlinkIndex[link]; !exists { if _, exists := backlinkIndex[link]; !exists {
@ -72,7 +72,7 @@ func BacklinksFor(hyphaName string) []string {
func Orphans() []string { func Orphans() []string {
var orphans []string var orphans []string
for h := range hyphae2.YieldExistingHyphae() { for h := range hyphae.YieldExistingHyphae() {
if BacklinksCount(h.CanonicalName()) == 0 { if BacklinksCount(h.CanonicalName()) == 0 {
orphans = append(orphans, h.CanonicalName()) orphans = append(orphans, h.CanonicalName())
} }
@ -92,14 +92,14 @@ func toLinkSet(xs []string) linkSet {
return result return result
} }
func fetchText(h hyphae2.Hypha) string { func fetchText(h hyphae.Hypha) string {
var path string var path string
switch h := h.(type) { switch h := h.(type) {
case *hyphae2.EmptyHypha: case *hyphae.EmptyHypha:
return "" return ""
case *hyphae2.TextualHypha: case *hyphae.TextualHypha:
path = h.TextFilePath() path = h.TextFilePath()
case *hyphae2.MediaHypha: case *hyphae.MediaHypha:
if !h.HasTextFile() { if !h.HasTextFile() {
return "" return ""
} }
@ -108,7 +108,7 @@ func fetchText(h hyphae2.Hypha) string {
text, err := os.ReadFile(path) text, err := os.ReadFile(path)
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to read file", "path", path, "err", err, "hyphaName", h.CanonicalName())
return "" return ""
} }
return string(text) return string(text)

View File

@ -1,12 +1,13 @@
package backlinks package backlinks
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/mycoopts"
"git.sr.ht/~bouncepaw/mycomarkup/v5" "git.sr.ht/~bouncepaw/mycomarkup/v5"
"git.sr.ht/~bouncepaw/mycomarkup/v5/links" "git.sr.ht/~bouncepaw/mycomarkup/v5/links"
"git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext" "git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext"
"git.sr.ht/~bouncepaw/mycomarkup/v5/tools" "git.sr.ht/~bouncepaw/mycomarkup/v5/tools"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/mycoopts"
) )
// UpdateBacklinksAfterEdit is a creation/editing hook for backlinks index // UpdateBacklinksAfterEdit is a creation/editing hook for backlinks index

View File

@ -2,7 +2,7 @@ package categories
import ( import (
"encoding/json" "encoding/json"
"log" "log/slog"
"os" "os"
"slices" "slices"
"sort" "sort"
@ -16,12 +16,11 @@ var categoryToHyphae = map[string]*categoryNode{}
var hyphaToCategories = map[string]*hyphaNode{} var hyphaToCategories = map[string]*hyphaNode{}
// Init initializes the category system. Call it after the Structure is initialized. This function might terminate the program in case of a bad mood or filesystem faults. // Init initializes the category system. Call it after the Structure is initialized. This function might terminate the program in case of a bad mood or filesystem faults.
func Init() { func Init() error {
var ( record, err := readCategoriesFromDisk()
record, err = readCategoriesFromDisk()
)
if err != nil { if err != nil {
log.Fatalln(err) slog.Error("Failed to read categories from disk", "err", err)
return err
} }
for _, cat := range record.Categories { for _, cat := range record.Categories {
@ -46,7 +45,8 @@ func Init() {
} }
} }
log.Println("Found", len(categoryToHyphae), "categories") slog.Info("Indexed categories", "n", len(categoryToHyphae))
return nil
} }
type categoryNode struct { type categoryNode struct {
@ -123,9 +123,7 @@ func readCategoriesFromDisk() (catFileRecord, error) {
var fileMutex sync.Mutex var fileMutex sync.Mutex
func saveToDisk() { func saveToDisk() {
var ( var record catFileRecord
record catFileRecord
)
for name, node := range categoryToHyphae { for name, node := range categoryToHyphae {
record.Categories = append(record.Categories, catRecord{ record.Categories = append(record.Categories, catRecord{
Name: name, Name: name,
@ -134,13 +132,16 @@ func saveToDisk() {
} }
data, err := json.MarshalIndent(record, "", "\t") data, err := json.MarshalIndent(record, "", "\t")
if err != nil { if err != nil {
log.Fatalln(err) // Better fail now, than later slog.Error("Failed to marshal categories record", "err", err)
os.Exit(1) // Better fail now, than later
} }
// TODO: make the data safer somehow?? Back it up before overwriting? // TODO: make the data safer somehow?? Back it up before overwriting?
fileMutex.Lock() fileMutex.Lock()
err = os.WriteFile(files.CategoriesJSON(), data, 0666) err = os.WriteFile(files.CategoriesJSON(), data, 0666)
if err != nil { if err != nil {
log.Fatalln(err) slog.Error("Failed to write categories.json", "err", err)
os.Exit(1)
} }
fileMutex.Unlock() fileMutex.Unlock()
} }

View File

@ -2,11 +2,12 @@
package files package files
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/web/static"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/web/static"
) )
var paths struct { var paths struct {

View File

@ -1,9 +1,10 @@
package hyphae package hyphae
import ( import (
"github.com/bouncepaw/mycorrhiza/util"
"os" "os"
"path/filepath" "path/filepath"
"github.com/bouncepaw/mycorrhiza/util"
) )
// ExistingHypha is not EmptyHypha. *MediaHypha and *TextualHypha implement this interface. // ExistingHypha is not EmptyHypha. *MediaHypha and *TextualHypha implement this interface.

View File

@ -1,11 +1,11 @@
package hyphae package hyphae
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/mimetype"
"log"
"log/slog" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"github.com/bouncepaw/mycorrhiza/internal/mimetype"
) )
// Index finds all hypha files in the full `path` and saves them to the hypha storage. // Index finds all hypha files in the full `path` and saves them to the hypha storage.
@ -51,7 +51,7 @@ func Index(path string) {
} }
} }
} }
log.Println("Indexed", Count(), "hyphae") slog.Info("Indexed hyphae", "n", Count())
} }
// indexHelper finds all hypha files in the full `path` and sends them to the // indexHelper finds all hypha files in the full `path` and sends them to the
@ -60,7 +60,8 @@ func Index(path string) {
func indexHelper(path string, nestLevel uint, ch chan ExistingHypha) { func indexHelper(path string, nestLevel uint, ch chan ExistingHypha) {
nodes, err := os.ReadDir(path) nodes, err := os.ReadDir(path)
if err != nil { if err != nil {
log.Fatal(err) slog.Error("Failed to read directory", "path", path, "err", err)
os.Exit(1)
} }
for _, node := range nodes { for _, node := range nodes {

View File

@ -1,11 +1,13 @@
package migration package migration
import ( import (
"git.sr.ht/~bouncepaw/mycomarkup/v5/tools"
"github.com/bouncepaw/mycorrhiza/internal/files"
"io/ioutil" "io/ioutil"
"log" "log/slog"
"os" "os"
"github.com/bouncepaw/mycorrhiza/internal/files"
"git.sr.ht/~bouncepaw/mycomarkup/v5/tools"
) )
var headingMarkerPath string var headingMarkerPath string
@ -29,7 +31,8 @@ func shouldMigrateHeadings() bool {
return true return true
} }
if err != nil { if err != nil {
log.Fatalln("When checking if heading migration is needed:", err.Error()) slog.Error("Failed to check if heading migration is needed", "err", err)
os.Exit(1)
} }
_ = file.Close() _ = file.Close()
return false return false
@ -42,6 +45,7 @@ func createHeadingMarker() {
0766, 0766,
) )
if err != nil { if err != nil {
log.Fatalln(err) slog.Error("Failed to create heading migration marker", "err", err)
os.Exit(1)
} }
} }

View File

@ -8,14 +8,14 @@
package migration package migration
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/user"
"io" "io"
"log" "log/slog"
"os" "os"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user"
) )
func genericLineMigrator( func genericLineMigrator(
@ -37,7 +37,8 @@ func genericLineMigrator(
file, err := os.OpenFile(hypha.TextFilePath(), os.O_RDWR, 0766) file, err := os.OpenFile(hypha.TextFilePath(), os.O_RDWR, 0766)
if err != nil { if err != nil {
hop.WithErrAbort(err) hop.WithErrAbort(err)
log.Fatal("Something went wrong when opening ", hypha.TextFilePath(), ": ", err.Error()) slog.Error("Failed to open text part file", "path", hypha.TextFilePath(), "err", err)
os.Exit(1)
} }
var buf strings.Builder var buf strings.Builder
@ -45,7 +46,7 @@ func genericLineMigrator(
if err != nil { if err != nil {
hop.WithErrAbort(err) hop.WithErrAbort(err)
_ = file.Close() _ = file.Close()
log.Fatal("Something went wrong when reading ", hypha.TextFilePath(), ": ", err.Error()) slog.Error("Failed to read text part file", "path", hypha.TextFilePath(), "err", err)
} }
var ( var (
@ -59,21 +60,24 @@ func genericLineMigrator(
if err != nil { if err != nil {
hop.WithErrAbort(err) hop.WithErrAbort(err)
_ = file.Close() _ = file.Close()
log.Fatal("Something went wrong when truncating ", hypha.TextFilePath(), ": ", err.Error()) slog.Error("Failed to truncate text part file", "path", hypha.TextFilePath(), "err", err)
os.Exit(1)
} }
_, err = file.Seek(0, 0) _, err = file.Seek(0, 0)
if err != nil { if err != nil {
hop.WithErrAbort(err) hop.WithErrAbort(err)
_ = file.Close() _ = file.Close()
log.Fatal("Something went wrong when seeking in ", hypha.TextFilePath(), ": ", err.Error()) slog.Error("Failed to seek in text part file", "path", hypha.TextFilePath(), "err", err)
os.Exit(1)
} }
_, err = file.WriteString(newText) _, err = file.WriteString(newText)
if err != nil { if err != nil {
hop.WithErrAbort(err) hop.WithErrAbort(err)
_ = file.Close() _ = file.Close()
log.Fatal("Something went wrong when writing to ", hypha.TextFilePath(), ": ", err.Error()) slog.Error("Failed to write to text part file", "path", hypha.TextFilePath(), "err", err)
os.Exit(1)
} }
} }
_ = file.Close() _ = file.Close()
@ -85,8 +89,8 @@ func genericLineMigrator(
} }
if hop.WithFiles(mycoFiles...).Apply().HasErrors() { if hop.WithFiles(mycoFiles...).Apply().HasErrors() {
log.Fatal(commitErrorMessage, hop.FirstErrorText()) slog.Error(commitErrorMessage + hop.FirstErrorText())
} }
log.Println("Migrated", len(mycoFiles), "Mycomarkup documents") slog.Info("Migrated Mycomarkup documents", "n", len(mycoFiles))
} }

View File

@ -1,11 +1,13 @@
package migration package migration
import ( import (
"git.sr.ht/~bouncepaw/mycomarkup/v5/tools"
"github.com/bouncepaw/mycorrhiza/internal/files"
"io/ioutil" "io/ioutil"
"log" "log/slog"
"os" "os"
"github.com/bouncepaw/mycorrhiza/internal/files"
"git.sr.ht/~bouncepaw/mycomarkup/v5/tools"
) )
var rocketMarkerPath string var rocketMarkerPath string
@ -33,7 +35,8 @@ func shouldMigrateRockets() bool {
return true return true
} }
if err != nil { if err != nil {
log.Fatalln("When checking if rocket migration is needed:", err.Error()) slog.Error("Failed to check if rocket migration is needed", "err", err)
os.Exit(1)
} }
_ = file.Close() _ = file.Close()
return false return false
@ -46,6 +49,7 @@ func createRocketLinkMarker() {
0766, 0766,
) )
if err != nil { if err != nil {
log.Fatalln(err) slog.Error("Failed to create rocket link migration marker")
os.Exit(1)
} }
} }

View File

@ -2,23 +2,23 @@ package shroom
import ( import (
"errors" "errors"
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/l18n" "github.com/bouncepaw/mycorrhiza/l18n"
) )
// TODO: get rid of this abomination // TODO: get rid of this abomination
func canFactory( func canFactory(
rejectLogger func(hyphae2.Hypha, *user.User, string), rejectLogger func(hyphae.Hypha, *user.User, string),
action string, action string,
dispatcher func(hyphae2.Hypha, *user.User, *l18n.Localizer) (string, string), dispatcher func(hyphae.Hypha, *user.User, *l18n.Localizer) (string, string),
noRightsMsg string, noRightsMsg string,
notExistsMsg string, notExistsMsg string,
mustExist bool, mustExist bool,
) func(*user.User, hyphae2.Hypha, *l18n.Localizer) error { ) func(*user.User, hyphae.Hypha, *l18n.Localizer) error {
return func(u *user.User, h hyphae2.Hypha, lc *l18n.Localizer) error { return func(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) error {
if !u.CanProceed(action) { if !u.CanProceed(action) {
rejectLogger(h, u, "no rights") rejectLogger(h, u, "no rights")
return errors.New(noRightsMsg) return errors.New(noRightsMsg)
@ -26,7 +26,7 @@ func canFactory(
if mustExist { if mustExist {
switch h.(type) { switch h.(type) {
case *hyphae2.EmptyHypha: case *hyphae.EmptyHypha:
rejectLogger(h, u, "does not exist") rejectLogger(h, u, "does not exist")
return errors.New(notExistsMsg) return errors.New(notExistsMsg)
} }

View File

@ -2,29 +2,30 @@ package shroom
import ( import (
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/internal/backlinks" "github.com/bouncepaw/mycorrhiza/internal/backlinks"
"github.com/bouncepaw/mycorrhiza/internal/categories" "github.com/bouncepaw/mycorrhiza/internal/categories"
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/internal/user"
) )
// Delete deletes the hypha and makes a history record about that. // Delete deletes the hypha and makes a history record about that.
func Delete(u *user.User, h hyphae2.ExistingHypha) error { func Delete(u *user.User, h hyphae.ExistingHypha) error {
hop := history. hop := history.
Operation(history.TypeDeleteHypha). Operation(history.TypeDeleteHypha).
WithMsg(fmt.Sprintf("Delete %s", h.CanonicalName())). WithMsg(fmt.Sprintf("Delete %s", h.CanonicalName())).
WithUser(u) WithUser(u)
originalText, _ := hyphae2.FetchMycomarkupFile(h) originalText, _ := hyphae.FetchMycomarkupFile(h)
switch h := h.(type) { switch h := h.(type) {
case *hyphae2.MediaHypha: case *hyphae.MediaHypha:
if h.HasTextFile() { if h.HasTextFile() {
hop.WithFilesRemoved(h.MediaFilePath(), h.TextFilePath()) hop.WithFilesRemoved(h.MediaFilePath(), h.TextFilePath())
} else { } else {
hop.WithFilesRemoved(h.MediaFilePath()) hop.WithFilesRemoved(h.MediaFilePath())
} }
case *hyphae2.TextualHypha: case *hyphae.TextualHypha:
hop.WithFilesRemoved(h.TextFilePath()) hop.WithFilesRemoved(h.TextFilePath())
} }
if hop.Apply().HasErrors() { if hop.Apply().HasErrors() {
@ -32,6 +33,6 @@ func Delete(u *user.User, h hyphae2.ExistingHypha) error {
} }
backlinks.UpdateBacklinksAfterDelete(h, originalText) backlinks.UpdateBacklinksAfterDelete(h, originalText)
categories.RemoveHyphaFromAllCategories(h.CanonicalName()) categories.RemoveHyphaFromAllCategories(h.CanonicalName())
hyphae2.DeleteHypha(h) hyphae.DeleteHypha(h)
return nil return nil
} }

View File

@ -1,22 +1,24 @@
package shroom package shroom
import ( import (
"os"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/mycoopts"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"git.sr.ht/~bouncepaw/mycomarkup/v5" "git.sr.ht/~bouncepaw/mycomarkup/v5"
"git.sr.ht/~bouncepaw/mycomarkup/v5/blocks" "git.sr.ht/~bouncepaw/mycomarkup/v5/blocks"
"git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext" "git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/mycoopts"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"os"
) )
// SetHeaderLinks initializes header links by reading the configured hypha, if there is any, or resorting to default values. // SetHeaderLinks initializes header links by reading the configured hypha, if there is any, or resorting to default values.
func SetHeaderLinks() { func SetHeaderLinks() {
switch userLinksHypha := hyphae2.ByName(cfg.HeaderLinksHypha).(type) { switch userLinksHypha := hyphae.ByName(cfg.HeaderLinksHypha).(type) {
case *hyphae2.EmptyHypha: case *hyphae.EmptyHypha:
setDefaultHeaderLinks() setDefaultHeaderLinks()
case hyphae2.ExistingHypha: case hyphae.ExistingHypha:
contents, err := os.ReadFile(userLinksHypha.TextFilePath()) contents, err := os.ReadFile(userLinksHypha.TextFilePath())
if err != nil || len(contents) == 0 { if err != nil || len(contents) == 0 {
setDefaultHeaderLinks() setDefaultHeaderLinks()

View File

@ -1,20 +1,36 @@
package shroom package shroom
import ( import (
"log/slog"
"github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/internal/user"
"log"
) )
func rejectRenameLog(h hyphae.Hypha, u *user.User, errmsg string) { func rejectRenameLog(h hyphae.Hypha, u *user.User, errmsg string) {
log.Printf("Reject rename %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) slog.Info("Reject rename",
"hyphaName", h.CanonicalName(),
"username", u.Name,
"errmsg", errmsg)
} }
func rejectRemoveMediaLog(h hyphae.Hypha, u *user.User, errmsg string) { func rejectRemoveMediaLog(h hyphae.Hypha, u *user.User, errmsg string) {
log.Printf("Reject remove media %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) slog.Info("Reject remove media",
"hyphaName", h.CanonicalName(),
"username", u.Name,
"errmsg", errmsg)
} }
func rejectEditLog(h hyphae.Hypha, u *user.User, errmsg string) { func rejectEditLog(h hyphae.Hypha, u *user.User, errmsg string) {
log.Printf("Reject edit %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) slog.Info("Reject edit",
"hyphaName", h.CanonicalName(),
"username", u.Name,
"errmsg", errmsg)
} }
func rejectUploadMediaLog(h hyphae.Hypha, u *user.User, errmsg string) { func rejectUploadMediaLog(h hyphae.Hypha, u *user.User, errmsg string) {
log.Printf("Reject upload media %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) slog.Info("Reject upload media",
"hyphaName", h.CanonicalName(),
"username", u.Name,
"errmsg", errmsg)
} }

View File

@ -3,36 +3,36 @@ package shroom
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
"github.com/bouncepaw/mycorrhiza/internal/categories"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/files"
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user"
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
"github.com/bouncepaw/mycorrhiza/internal/categories"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/files"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
) )
// Rename renames the old hypha to the new name and makes a history record about that. Call if and only if the user has the permission to rename. // Rename renames the old hypha to the new name and makes a history record about that. Call if and only if the user has the permission to rename.
func Rename(oldHypha hyphae2.ExistingHypha, newName string, recursive bool, leaveRedirections bool, u *user.User) error { func Rename(oldHypha hyphae.ExistingHypha, newName string, recursive bool, leaveRedirections bool, u *user.User) error {
// * bouncepaw hates this function and related renaming functions // * bouncepaw hates this function and related renaming functions
if newName == "" { if newName == "" {
rejectRenameLog(oldHypha, u, "no new name given") rejectRenameLog(oldHypha, u, "no new name given")
return errors.New("ui.rename_noname_tip") return errors.New("ui.rename_noname_tip")
} }
if !hyphae2.IsValidName(newName) { if !hyphae.IsValidName(newName) {
rejectRenameLog(oldHypha, u, fmt.Sprintf("new name %s invalid", newName)) rejectRenameLog(oldHypha, u, fmt.Sprintf("new name %s invalid", newName))
return errors.New("ui.rename_badname_tip") // FIXME: There is a bug related to this. return errors.New("ui.rename_badname_tip") // FIXME: There is a bug related to this.
} }
switch targetHypha := hyphae2.ByName(newName); targetHypha.(type) { switch targetHypha := hyphae.ByName(newName); targetHypha.(type) {
case hyphae2.ExistingHypha: case hyphae.ExistingHypha:
if targetHypha.CanonicalName() == oldHypha.CanonicalName() { if targetHypha.CanonicalName() == oldHypha.CanonicalName() {
return nil return nil
} }
@ -81,7 +81,7 @@ func Rename(oldHypha hyphae2.ExistingHypha, newName string, recursive bool, leav
oldName = h.CanonicalName() oldName = h.CanonicalName()
newName = re.ReplaceAllString(oldName, newName) newName = re.ReplaceAllString(oldName, newName)
) )
hyphae2.RenameHyphaTo(h, newName, replaceName) hyphae.RenameHyphaTo(h, newName, replaceName)
backlinks.UpdateBacklinksAfterRename(h, oldName) backlinks.UpdateBacklinksAfterRename(h, oldName)
categories.RenameHyphaInAllCategories(oldName, newName) categories.RenameHyphaInAllCategories(oldName, newName)
if leaveRedirections { if leaveRedirections {
@ -104,12 +104,12 @@ const redirectionTemplate = `=> %[1]s | 👁️➡️ %[2]s
func leaveRedirection(oldName, newName string, hop *history.Op) error { func leaveRedirection(oldName, newName string, hop *history.Op) error {
var ( var (
text = fmt.Sprintf(redirectionTemplate, newName, util.BeautifulName(newName)) text = fmt.Sprintf(redirectionTemplate, newName, util.BeautifulName(newName))
emptyHypha = hyphae2.ByName(oldName) emptyHypha = hyphae.ByName(oldName)
) )
switch emptyHypha := emptyHypha.(type) { switch emptyHypha := emptyHypha.(type) {
case *hyphae2.EmptyHypha: case *hyphae.EmptyHypha:
h := hyphae2.ExtendEmptyToTextual(emptyHypha, filepath.Join(files.HyphaeDir(), oldName+".myco")) h := hyphae.ExtendEmptyToTextual(emptyHypha, filepath.Join(files.HyphaeDir(), oldName+".myco"))
hyphae2.Insert(h) hyphae.Insert(h)
categories.AddHyphaToCategory(oldName, cfg.RedirectionCategory) categories.AddHyphaToCategory(oldName, cfg.RedirectionCategory)
defer backlinks.UpdateBacklinksAfterEdit(h, "") defer backlinks.UpdateBacklinksAfterEdit(h, "")
return writeTextToDisk(h, []byte(text), hop) return writeTextToDisk(h, []byte(text), hop)
@ -118,15 +118,15 @@ func leaveRedirection(oldName, newName string, hop *history.Op) error {
} }
} }
func findHyphaeToRename(superhypha hyphae2.ExistingHypha, recursive bool) []hyphae2.ExistingHypha { func findHyphaeToRename(superhypha hyphae.ExistingHypha, recursive bool) []hyphae.ExistingHypha {
hyphaList := []hyphae2.ExistingHypha{superhypha} hyphaList := []hyphae.ExistingHypha{superhypha}
if recursive { if recursive {
hyphaList = append(hyphaList, hyphae2.Subhyphae(superhypha)...) hyphaList = append(hyphaList, hyphae.Subhyphae(superhypha)...)
} }
return hyphaList return hyphaList
} }
func renamingPairs(hyphaeToRename []hyphae2.ExistingHypha, replaceName func(string) string) (map[string]string, error) { func renamingPairs(hyphaeToRename []hyphae.ExistingHypha, replaceName func(string) string) (map[string]string, error) {
var ( var (
renameMap = make(map[string]string) renameMap = make(map[string]string)
newNames = make([]string, len(hyphaeToRename)) newNames = make([]string, len(hyphaeToRename))
@ -138,12 +138,12 @@ func renamingPairs(hyphaeToRename []hyphae2.ExistingHypha, replaceName func(stri
renameMap[h.TextFilePath()] = replaceName(h.TextFilePath()) renameMap[h.TextFilePath()] = replaceName(h.TextFilePath())
} }
switch h := h.(type) { switch h := h.(type) {
case *hyphae2.MediaHypha: case *hyphae.MediaHypha:
renameMap[h.MediaFilePath()] = replaceName(h.MediaFilePath()) renameMap[h.MediaFilePath()] = replaceName(h.MediaFilePath())
} }
h.Unlock() h.Unlock()
} }
if firstFailure, ok := hyphae2.AreFreeNames(newNames...); !ok { if firstFailure, ok := hyphae.AreFreeNames(newNames...); !ok {
return nil, errors.New("Hypha " + firstFailure + " already exists") return nil, errors.New("Hypha " + firstFailure + " already exists")
} }
return renameMap, nil return renameMap, nil

View File

@ -1,9 +1,9 @@
package shroom package shroom
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
) )

View File

@ -2,14 +2,14 @@ package shroom
import ( import (
"fmt" "fmt"
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/user"
) )
// RemoveMedia removes media from the media hypha and makes a history record about that. If it only had media, the hypha will be deleted. If it also had text, the hypha will become textual. // RemoveMedia removes media from the media hypha and makes a history record about that. If it only had media, the hypha will be deleted. If it also had text, the hypha will become textual.
func RemoveMedia(u *user.User, h *hyphae2.MediaHypha) error { func RemoveMedia(u *user.User, h *hyphae.MediaHypha) error {
hop := history. hop := history.
Operation(history.TypeRemoveMedia). Operation(history.TypeRemoveMedia).
WithFilesRemoved(h.MediaFilePath()). WithFilesRemoved(h.MediaFilePath()).
@ -24,9 +24,9 @@ func RemoveMedia(u *user.User, h *hyphae2.MediaHypha) error {
} }
if h.HasTextFile() { if h.HasTextFile() {
hyphae2.Insert(hyphae2.ShrinkMediaToTextual(h)) hyphae.Insert(hyphae.ShrinkMediaToTextual(h))
} else { } else {
hyphae2.DeleteHypha(h) hyphae.DeleteHypha(h)
} }
return nil return nil
} }

View File

@ -5,7 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log" "log/slog"
"mime/multipart" "mime/multipart"
"os" "os"
"path/filepath" "path/filepath"
@ -201,7 +201,7 @@ func UploadBinary(h hyphae.Hypha, mime string, file multipart.File, u *user.User
if err := history.Rename(prevFilePath, uploadedFilePath); err != nil { if err := history.Rename(prevFilePath, uploadedFilePath); err != nil {
return err return err
} }
log.Printf("Move %s to %s\n", prevFilePath, uploadedFilePath) slog.Info("Move file", "from", prevFilePath, "to", uploadedFilePath)
h.SetMediaFilePath(uploadedFilePath) h.SetMediaFilePath(uploadedFilePath)
} }
} }

View File

@ -2,13 +2,14 @@ package tree
import ( import (
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/util"
"html/template" "html/template"
"io" "io"
"path" "path"
"sort" "sort"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/util"
) )
// Tree returns the subhypha matrix as HTML and names of the next and previous hyphae (or empty strings). // Tree returns the subhypha matrix as HTML and names of the next and previous hyphae (or empty strings).

View File

@ -3,10 +3,10 @@ package user
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/bouncepaw/mycorrhiza/internal/cfg" "log/slog"
"log"
"os" "os"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/files" "github.com/bouncepaw/mycorrhiza/internal/files"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
) )
@ -32,19 +32,23 @@ func usersFromFile() []*User {
return users return users
} }
if err != nil { if err != nil {
log.Fatal(err) slog.Error("Failed to read users.json", "err", err)
os.Exit(1)
} }
err = json.Unmarshal(contents, &users) err = json.Unmarshal(contents, &users)
if err != nil { if err != nil {
log.Fatal(err) slog.Error("Failed to unmarshal users.json contents", "err", err)
os.Exit(1)
} }
for _, u := range users { for _, u := range users {
u.Name = util.CanonicalName(u.Name) u.Name = util.CanonicalName(u.Name)
if u.Source == "" { if u.Source == "" {
u.Source = "local" u.Source = "local"
} }
} }
log.Println("Found", len(users), "users") slog.Info("Indexed users", "n", len(users))
return users return users
} }
@ -63,20 +67,22 @@ func readTokensToUsers() {
return return
} }
if err != nil { if err != nil {
log.Fatal(err) slog.Error("Failed to read tokens.json", "err", err)
os.Exit(1)
} }
var tmp map[string]string var tmp map[string]string
err = json.Unmarshal(contents, &tmp) err = json.Unmarshal(contents, &tmp)
if err != nil { if err != nil {
log.Fatal(err) slog.Error("Failed to unmarshal tokens.json contents", "err", err)
os.Exit(1)
} }
for token, username := range tmp { for token, username := range tmp {
tokens.Store(token, username) tokens.Store(token, username)
// commenceSession(username, token) // commenceSession(username, token)
} }
log.Println("Found", len(tmp), "active sessions") slog.Info("Indexed active sessions", "n", len(tmp))
} }
// SaveUserDatabase stores current user credentials into JSON file by configured path. // SaveUserDatabase stores current user credentials into JSON file by configured path.
@ -94,13 +100,13 @@ func dumpUserCredentials() error {
blob, err := json.MarshalIndent(userList, "", "\t") blob, err := json.MarshalIndent(userList, "", "\t")
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to marshal users.json", "err", err)
return err return err
} }
err = os.WriteFile(files.UserCredentialsJSON(), blob, 0666) err = os.WriteFile(files.UserCredentialsJSON(), blob, 0666)
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to write users.json", "err", err)
return err return err
} }
@ -119,11 +125,11 @@ func dumpTokens() {
blob, err := json.MarshalIndent(tmp, "", "\t") blob, err := json.MarshalIndent(tmp, "", "\t")
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to marshal tokens.json", "err", err)
return return
} }
err = os.WriteFile(files.TokensJSON(), blob, 0666) err = os.WriteFile(files.TokensJSON(), blob, 0666)
if err != nil { if err != nil {
log.Println("an error occurred in dumpTokens function:", err) slog.Error("Failed to write tokens.json", "err", err)
} }
} }

View File

@ -6,16 +6,16 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/cfg" "log/slog"
"log"
"net/http" "net/http"
"sort" "sort"
"strings" "strings"
"time" "time"
"golang.org/x/crypto/bcrypt" "github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
"golang.org/x/crypto/bcrypt"
) )
// CanProceed returns `true` if the user in `rq` has enough rights to access `route`. // CanProceed returns `true` if the user in `rq` has enough rights to access `route`.
@ -91,17 +91,17 @@ func LoginDataHTTP(w http.ResponseWriter, username, password string) error {
w.Header().Set("Content-Type", "text/html;charset=utf-8") w.Header().Set("Content-Type", "text/html;charset=utf-8")
if !HasUsername(username) { if !HasUsername(username) {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
log.Println("Unknown username", username, "was entered") slog.Info("Unknown username entered", "username", username)
return ErrUnknownUsername return ErrUnknownUsername
} }
if !CredentialsOK(username, password) { if !CredentialsOK(username, password) {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
log.Println("A wrong password was entered for username", username) slog.Info("Wrong password entered", "username", username)
return ErrWrongPassword return ErrWrongPassword
} }
token, err := AddSession(username) token, err := AddSession(username)
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to add session", "username", username, "err", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return err return err
} }
@ -114,7 +114,7 @@ func AddSession(username string) (string, error) {
token, err := util.RandomString(16) token, err := util.RandomString(16)
if err == nil { if err == nil {
commenceSession(username, token) commenceSession(username, token)
log.Println("New token for", username, "is", token) slog.Info("Added session", "username", username)
} }
return token, err return token, err
} }

View File

@ -2,12 +2,13 @@ package user
import ( import (
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"net/http" "net/http"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )

View File

@ -4,29 +4,36 @@ package interwiki
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"git.sr.ht/~bouncepaw/mycomarkup/v5/options" "log/slog"
"github.com/bouncepaw/mycorrhiza/internal/files"
"github.com/bouncepaw/mycorrhiza/util"
"log"
"os" "os"
"sync" "sync"
"github.com/bouncepaw/mycorrhiza/internal/files"
"github.com/bouncepaw/mycorrhiza/util"
"git.sr.ht/~bouncepaw/mycomarkup/v5/options"
) )
func Init() { func Init() error {
var ( record, err := readInterwiki()
record, err = readInterwiki()
)
if err != nil { if err != nil {
log.Fatalln(err) slog.Error("Failed to read interwiki", "err", err)
return err
} }
for _, wiki := range record { for _, wiki := range record {
wiki := wiki // This line is required wiki := wiki // This line is required
wiki.canonize() if err := wiki.canonize(); err != nil {
return err
}
if err := addEntry(&wiki); err != nil { if err := addEntry(&wiki); err != nil {
log.Fatalln(err.Error()) slog.Error("Failed to add interwiki entry", "err", err)
return err
} }
} }
log.Printf("Loaded %d interwiki entries\n", len(listOfEntries))
slog.Info("Indexed interwiki map", "n", len(listOfEntries))
return nil
} }
func dropEmptyStrings(ss []string) (clean []string) { func dropEmptyStrings(ss []string) (clean []string) {
@ -100,7 +107,6 @@ func deleteEntry(wiki *Wiki) {
for i, w := range listOfEntries { for i, w := range listOfEntries {
i, w := i, w i, w := i, w
if w.Name == wiki.Name { if w.Name == wiki.Name {
log.Println("It came to delete")
// Drop ith element. // Drop ith element.
listOfEntries[i] = listOfEntries[len(listOfEntries)-1] listOfEntries[i] = listOfEntries[len(listOfEntries)-1]
listOfEntries = listOfEntries[:len(listOfEntries)-1] listOfEntries = listOfEntries[:len(listOfEntries)-1]
@ -113,21 +119,22 @@ func deleteEntry(wiki *Wiki) {
wg.Wait() wg.Wait()
} }
// TODO: There is something clearly wrong with error-returning in this function.
func addEntry(wiki *Wiki) error { func addEntry(wiki *Wiki) error {
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
wiki.Aliases = dropEmptyStrings(wiki.Aliases) wiki.Aliases = dropEmptyStrings(wiki.Aliases)
var ( var (
names = append(wiki.Aliases, wiki.Name) names = append(wiki.Aliases, wiki.Name)
ok, name = areNamesFree(names) ok, name = areNamesFree(names)
) )
if !ok { switch {
log.Printf("There are multiple uses of the same name %s\n", name) case !ok:
slog.Error("There are multiple uses of the same name", "name", name)
return errors.New(name) return errors.New(name)
} case len(names) == 0:
if len(names) == 0 { slog.Error("No names passed for a new interwiki entry")
log.Println("No names passed for a new interwiki entry")
// There is something clearly wrong with error-returning in this function.
return errors.New("") return errors.New("")
} }
@ -176,10 +183,13 @@ func readInterwiki() ([]Wiki, error) {
func saveInterwikiJson() { func saveInterwikiJson() {
// Trust me, wiki crashing when an admin takes an administrative action totally makes sense. // Trust me, wiki crashing when an admin takes an administrative action totally makes sense.
if data, err := json.MarshalIndent(listOfEntries, "", "\t"); err != nil { if data, err := json.MarshalIndent(listOfEntries, "", "\t"); err != nil {
log.Fatalln(err) slog.Error("Failed to marshal interwiki entries", "err", err)
os.Exit(1)
} else if err = os.WriteFile(files.InterwikiJSON(), data, 0666); err != nil { } else if err = os.WriteFile(files.InterwikiJSON(), data, 0666); err != nil {
log.Fatalln(err) slog.Error("Failed to write interwiki.json", "err", err)
} else { os.Exit(1)
log.Println("Saved interwiki.json")
} }
slog.Info("Saved interwiki.json")
} }

View File

@ -2,11 +2,13 @@ package interwiki
import ( import (
"embed" "embed"
"github.com/bouncepaw/mycorrhiza/web/viewutil" "log/slog"
"github.com/gorilla/mux"
"log"
"net/http" "net/http"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"github.com/gorilla/mux"
) )
var ( var (
@ -63,19 +65,24 @@ func handlerModifyEntry(w http.ResponseWriter, rq *http.Request) {
) )
if oldData, ok = entriesByName[name]; !ok { if oldData, ok = entriesByName[name]; !ok {
log.Printf("Could not modify interwiki entry %s because it does not exist", name) slog.Info("Could not modify entry",
"name", name,
"reason", "does not exist")
viewutil.HandlerNotFound(w, rq) viewutil.HandlerNotFound(w, rq)
return return
} }
if err := replaceEntry(oldData, &newData); err != nil { if err := replaceEntry(oldData, &newData); err != nil {
log.Printf("Could not modify interwiki entry %s because one of the proposed aliases/name is taken\n", name) slog.Info("Could not modify entry",
"name", name,
"reason", "one of the proposed aliases or the name is taken",
"err", err)
viewNameTaken(viewutil.MetaFrom(w, rq), oldData, err.Error(), "modify-entry/"+name) viewNameTaken(viewutil.MetaFrom(w, rq), oldData, err.Error(), "modify-entry/"+name)
return return
} }
saveInterwikiJson() saveInterwikiJson()
log.Printf("Modified interwiki entry %s\n", name) slog.Info("Modified entry", "name", name)
http.Redirect(w, rq, "/interwiki", http.StatusSeeOther) http.Redirect(w, rq, "/interwiki", http.StatusSeeOther)
} }

View File

@ -1,9 +1,11 @@
package interwiki package interwiki
import ( import (
"errors"
"fmt" "fmt"
"log/slog"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
"log"
) )
// WikiEngine is an enumeration of supported interwiki targets. // WikiEngine is an enumeration of supported interwiki targets.
@ -47,14 +49,20 @@ type Wiki struct {
Engine WikiEngine `json:"engine"` Engine WikiEngine `json:"engine"`
} }
func (w *Wiki) canonize() { func (w *Wiki) canonize() error {
switch { switch {
case w.Name == "": case w.Name == "":
log.Fatalln("Cannot have a wiki in the interwiki map with no name") slog.Error("A site in the interwiki map has no name")
return errors.New("site with no name")
case w.URL == "": case w.URL == "":
log.Fatalf("Wiki %s has no URL\n", w.Name) slog.Error("Site in the interwiki map has no URL", "name", w.Name)
return errors.New("site with no URL")
case !w.Engine.Valid(): case !w.Engine.Valid():
log.Fatalf("Unknown engine %s for wiki %s\n", w.Engine, w.Name) slog.Error("Site in the interwiki map has an unknown engine",
"siteName", w.Name,
"engine", w.Engine,
)
return errors.New("unknown engine")
} }
w.Name = util.CanonicalName(w.Name) w.Name = util.CanonicalName(w.Name)
@ -83,4 +91,6 @@ func (w *Wiki) canonize() {
w.ImgSrcFormat = fmt.Sprintf("%s/{NAME}", w.URL) w.ImgSrcFormat = fmt.Sprintf("%s/{NAME}", w.URL)
} }
} }
return nil
} }

View File

@ -21,7 +21,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/fs" "io/fs"
"log" "log/slog"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strings" "strings"
@ -78,7 +78,7 @@ func init() {
var strings map[string]string var strings map[string]string
if err := json.Unmarshal(contents, &strings); err != nil { if err := json.Unmarshal(contents, &strings); err != nil {
log.Fatalf("error while parsing %s: %v", path, err) slog.Error("Failed to unmarshal localization file", "path", path, "err", err)
} }
for key, value := range strings { for key, value := range strings {

45
main.go
View File

@ -5,12 +5,9 @@
package main package main
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/categories"
"log"
"os"
"github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/internal/backlinks" "github.com/bouncepaw/mycorrhiza/internal/backlinks"
"github.com/bouncepaw/mycorrhiza/internal/categories"
"github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/files" "github.com/bouncepaw/mycorrhiza/internal/files"
"github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
@ -22,45 +19,63 @@ import (
"github.com/bouncepaw/mycorrhiza/web" "github.com/bouncepaw/mycorrhiza/web"
"github.com/bouncepaw/mycorrhiza/web/static" "github.com/bouncepaw/mycorrhiza/web/static"
"github.com/bouncepaw/mycorrhiza/web/viewutil" "github.com/bouncepaw/mycorrhiza/web/viewutil"
"log/slog"
"os"
) )
func main() { func main() {
parseCliArgs() if err := parseCliArgs(); err != nil {
os.Exit(1)
}
if err := files.PrepareWikiRoot(); err != nil { if err := files.PrepareWikiRoot(); err != nil {
log.Fatal(err) slog.Error("Failed to prepare wiki root", "err", err)
os.Exit(1)
} }
if err := cfg.ReadConfigFile(files.ConfigPath()); err != nil { if err := cfg.ReadConfigFile(files.ConfigPath()); err != nil {
log.Fatal(err) slog.Error("Failed to read config", "err", err)
os.Exit(1)
} }
log.Println("Running Mycorrhiza Wiki", version.Short)
if err := os.Chdir(files.HyphaeDir()); err != nil { if err := os.Chdir(files.HyphaeDir()); err != nil {
log.Fatal(err) slog.Error("Failed to chdir to hyphae dir",
"err", err, "hyphaeDir", files.HyphaeDir())
os.Exit(1)
} }
log.Println("Wiki directory is", cfg.WikiDir) slog.Info("Running Mycorrhiza Wiki",
"version", version.Short, "wikiDir", cfg.WikiDir)
// Init the subsystems: // Init the subsystems:
// TODO: keep all crashes in main rather than somewhere there
viewutil.Init() viewutil.Init()
hyphae.Index(files.HyphaeDir()) hyphae.Index(files.HyphaeDir())
backlinks.IndexBacklinks() backlinks.IndexBacklinks()
go backlinks.RunBacklinksConveyor() go backlinks.RunBacklinksConveyor()
user.InitUserDatabase() user.InitUserDatabase()
history.Start() if err := history.Start(); err != nil {
os.Exit(1)
}
history.InitGitRepo() history.InitGitRepo()
migration.MigrateRocketsMaybe() migration.MigrateRocketsMaybe()
migration.MigrateHeadingsMaybe() migration.MigrateHeadingsMaybe()
shroom.SetHeaderLinks() shroom.SetHeaderLinks()
categories.Init() if err := categories.Init(); err != nil {
interwiki.Init() os.Exit(1)
}
if err := interwiki.Init(); err != nil {
os.Exit(1)
}
// Static files: // Static files:
static.InitFS(files.StaticFiles()) static.InitFS(files.StaticFiles())
if !user.HasAnyAdmins() { if !user.HasAnyAdmins() {
log.Println("Your wiki has no admin yet. Run Mycorrhiza with -create-admin <username> option to create an admin.") slog.Error("Your wiki has no admin yet. Run Mycorrhiza with -create-admin <username> option to create an admin.")
} }
serveHTTP(web.Handler()) err := serveHTTP(web.Handler())
if err != nil {
os.Exit(1)
}
} }

View File

@ -1,13 +1,15 @@
package misc package misc
import ( import (
"log/slog"
"os"
"strings"
"text/template" // sic! TODO: make it html/template after the template library migration
"github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/internal/version" "github.com/bouncepaw/mycorrhiza/internal/version"
"github.com/bouncepaw/mycorrhiza/l18n" "github.com/bouncepaw/mycorrhiza/l18n"
"log"
"strings"
"text/template" // sic!
) )
type L10nEntry struct { type L10nEntry struct {
@ -95,7 +97,8 @@ func AboutHTML(lc *l18n.Localizer) string {
} }
temp, err := template.New("about wiki").Funcs(template.FuncMap{"get": get}).Parse(aboutTemplateString) temp, err := template.New("about wiki").Funcs(template.FuncMap{"get": get}).Parse(aboutTemplateString)
if err != nil { if err != nil {
log.Fatalln(err) slog.Error("Failed to parse About template", "err", err)
os.Exit(1)
} }
data := aboutData data := aboutData
data.Version = version.Short data.Version = version.Short
@ -112,7 +115,8 @@ func AboutHTML(lc *l18n.Localizer) string {
var out strings.Builder var out strings.Builder
err = temp.Execute(&out, data) err = temp.Execute(&out, data)
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to execute About template", "err", err)
os.Exit(1)
} }
return out.String() return out.String()
} }

View File

@ -3,7 +3,7 @@ package misc
import ( import (
"io" "io"
"log" "log/slog"
"math/rand" "math/rand"
"mime" "mime"
"net/http" "net/http"
@ -73,11 +73,11 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) {
if ok := user.CanProceed(rq, "reindex"); !ok { if ok := user.CanProceed(rq, "reindex"); !ok {
var lc = l18n.FromRequest(rq) var lc = l18n.FromRequest(rq)
viewutil.HttpErr(viewutil.MetaFrom(w, rq), http.StatusForbidden, cfg.HomeHypha, lc.Get("ui.reindex_no_rights")) viewutil.HttpErr(viewutil.MetaFrom(w, rq), http.StatusForbidden, cfg.HomeHypha, lc.Get("ui.reindex_no_rights"))
log.Println("Rejected", rq.URL) slog.Info("No rights to reindex")
return return
} }
hyphae.ResetCount() hyphae.ResetCount()
log.Println("Reindexing hyphae in", files.HyphaeDir()) slog.Info("Reindexing hyphae", "hyphaeDir", files.HyphaeDir())
hyphae.Index(files.HyphaeDir()) hyphae.Index(files.HyphaeDir())
backlinks.IndexBacklinks() backlinks.IndexBacklinks()
http.Redirect(w, rq, "/", http.StatusSeeOther) http.Redirect(w, rq, "/", http.StatusSeeOther)
@ -89,9 +89,10 @@ func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
if ok := user.CanProceed(rq, "update-header-links"); !ok { if ok := user.CanProceed(rq, "update-header-links"); !ok {
var lc = l18n.FromRequest(rq) var lc = l18n.FromRequest(rq)
viewutil.HttpErr(viewutil.MetaFrom(w, rq), http.StatusForbidden, cfg.HomeHypha, lc.Get("ui.header_no_rights")) viewutil.HttpErr(viewutil.MetaFrom(w, rq), http.StatusForbidden, cfg.HomeHypha, lc.Get("ui.header_no_rights"))
log.Println("Rejected", rq.URL) slog.Info("No rights to update header links")
return return
} }
slog.Info("Updated header links")
shroom.SetHeaderLinks() shroom.SetHeaderLinks()
http.Redirect(w, rq, "/", http.StatusSeeOther) http.Redirect(w, rq, "/", http.StatusSeeOther)
} }
@ -133,7 +134,7 @@ func handlerAbout(w http.ResponseWriter, rq *http.Request) {
map[string]string{}, map[string]string{},
)) ))
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to write About template", "err", err)
} }
} }
@ -148,7 +149,7 @@ func handlerStyle(w http.ResponseWriter, rq *http.Request) {
} }
_, err = io.Copy(w, file) _, err = io.Copy(w, file)
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to write stylesheet; proceeding anyway", "err", err)
} }
_ = file.Close() _ = file.Close()
} }
@ -163,7 +164,7 @@ func handlerRobotsTxt(w http.ResponseWriter, rq *http.Request) {
} }
_, err = io.Copy(w, file) _, err = io.Copy(w, file)
if err != nil { if err != nil {
log.Println() slog.Error("Failed to write robots.txt; proceeding anyway", "err", err)
} }
_ = file.Close() _ = file.Close()
} }

View File

@ -2,6 +2,7 @@ package misc
import ( import (
"embed" "embed"
"github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/web/viewutil" "github.com/bouncepaw/mycorrhiza/web/viewutil"
) )

View File

@ -2,11 +2,13 @@ package mycoopts
import ( import (
"errors" "errors"
"git.sr.ht/~bouncepaw/mycomarkup/v5/options"
"github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/interwiki" "github.com/bouncepaw/mycorrhiza/interwiki"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
"git.sr.ht/~bouncepaw/mycomarkup/v5/options"
) )
func MarkupOptions(hyphaName string) options.Options { func MarkupOptions(hyphaName string) options.Options {

View File

@ -3,7 +3,7 @@ package util
import ( import (
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"log" "log/slog"
"net/http" "net/http"
"strings" "strings"
@ -82,7 +82,7 @@ func HyphaNameFromRq(rq *http.Request, actions ...string) string {
return CanonicalName(strings.TrimPrefix(p, "/"+action+"/")) return CanonicalName(strings.TrimPrefix(p, "/"+action+"/"))
} }
} }
log.Println("HyphaNameFromRq: this request is invalid, fall back to home hypha") slog.Info("HyphaNameFromRq: this request is invalid, fall back to home hypha")
return cfg.HomeHypha return cfg.HomeHypha
} }

View File

@ -2,7 +2,7 @@ package web
import ( import (
"fmt" "fmt"
"log" "log/slog"
"mime" "mime"
"net/http" "net/http"
"os" "os"
@ -115,7 +115,7 @@ func handlerAdmin(w http.ResponseWriter, rq *http.Request) {
// handlerAdminShutdown kills the wiki. // handlerAdminShutdown kills the wiki.
func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) {
if user.CanProceed(rq, "admin/shutdown") { if user.CanProceed(rq, "admin/shutdown") {
log.Println("An admin commanded the wiki to shutdown") slog.Info("An admin commanded the wiki to shutdown")
os.Exit(0) os.Exit(0)
} }
} }
@ -162,7 +162,7 @@ func handlerAdminUserEdit(w http.ResponseWriter, rq *http.Request) {
u.Group = newGroup u.Group = newGroup
if err := user.SaveUserDatabase(); err != nil { if err := user.SaveUserDatabase(); err != nil {
u.Group = oldGroup u.Group = oldGroup
log.Println(err) slog.Info("Failed to save user database", "err", err)
f = f.WithError(err) f = f.WithError(err)
} else { } else {
http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther)
@ -241,7 +241,7 @@ func handlerAdminUserDelete(w http.ResponseWriter, rq *http.Request) {
if !f.HasError() { if !f.HasError() {
http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther)
} else { } else {
log.Println(f.Error()) slog.Info("Failed to delete user", "err", f.Error())
} }
} }

View File

@ -1,14 +1,13 @@
package web package web
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/categories"
"io" "io"
"log"
"log/slog" "log/slog"
"net/http" "net/http"
"sort" "sort"
"strings" "strings"
"github.com/bouncepaw/mycorrhiza/internal/categories"
"github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil" "github.com/bouncepaw/mycorrhiza/web/viewutil"
@ -66,7 +65,7 @@ func handlerCategory(w http.ResponseWriter, rq *http.Request) {
// There is one hypha from the hypha field. Then there are n hyphae in fields prefixed by _. It seems like I have to do it myself. Compare with PHP which handles it for you. I hope I am doing this wrong. // There is one hypha from the hypha field. Then there are n hyphae in fields prefixed by _. It seems like I have to do it myself. Compare with PHP which handles it for you. I hope I am doing this wrong.
func hyphaeFromRequest(rq *http.Request) (canonicalNames []string) { func hyphaeFromRequest(rq *http.Request) (canonicalNames []string) {
if err := rq.ParseForm(); err != nil { if err := rq.ParseForm(); err != nil {
log.Println(err) slog.Info("Failed to parse form", "err", err)
} }
if hyphaName := util.CanonicalName(rq.PostFormValue("hypha")); hyphaName != "" { if hyphaName := util.CanonicalName(rq.PostFormValue("hypha")); hyphaName != "" {
canonicalNames = append(canonicalNames, hyphaName) canonicalNames = append(canonicalNames, hyphaName)
@ -100,7 +99,8 @@ func handlerRemoveFromCategory(w http.ResponseWriter, rq *http.Request) {
return return
} }
if len(hyphaNames) == 0 || catName == "" { if len(hyphaNames) == 0 || catName == "" {
log.Printf("%s passed no data for removal of hyphae from a category\n", u.Name) slog.Info("No data for removal of hyphae from category passed",
"username", u.Name, "catName", catName)
http.Redirect(w, rq, redirectTo, http.StatusSeeOther) http.Redirect(w, rq, redirectTo, http.StatusSeeOther)
return return
} }
@ -108,7 +108,8 @@ func handlerRemoveFromCategory(w http.ResponseWriter, rq *http.Request) {
// TODO: Make it more effective. // TODO: Make it more effective.
categories.RemoveHyphaFromCategory(hyphaName, catName) categories.RemoveHyphaFromCategory(hyphaName, catName)
} }
log.Printf("%s removed %q from category %s\n", u.Name, hyphaNames, catName) slog.Info("Remove hyphae from category",
"username", u.Name, "catName", catName, "hyphaNames", hyphaNames)
http.Redirect(w, rq, redirectTo, http.StatusSeeOther) http.Redirect(w, rq, redirectTo, http.StatusSeeOther)
} }

View File

@ -1,23 +1,22 @@
package web package web
import ( import (
"git.sr.ht/~bouncepaw/mycomarkup/v5" "html/template"
"log/slog"
"net/http"
"github.com/bouncepaw/mycorrhiza/hypview"
"github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/hyphae"
"github.com/bouncepaw/mycorrhiza/internal/shroom" "github.com/bouncepaw/mycorrhiza/internal/shroom"
"github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"html/template"
"log"
"net/http"
"git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext"
"github.com/bouncepaw/mycorrhiza/hypview"
"github.com/bouncepaw/mycorrhiza/mycoopts"
"github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/l18n" "github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/mycoopts"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"git.sr.ht/~bouncepaw/mycomarkup/v5"
"git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext"
"github.com/gorilla/mux"
) )
func initMutators(r *mux.Router) { func initMutators(r *mux.Router) {
@ -64,14 +63,16 @@ func handlerDelete(w http.ResponseWriter, rq *http.Request) {
) )
if !u.CanProceed("delete") { if !u.CanProceed("delete") {
log.Printf("%s has no rights to delete %s\n", u.Name, h.CanonicalName()) slog.Info("No rights to delete hypha",
"username", u.Name, "hyphaName", h.CanonicalName())
viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights")
return return
} }
switch h.(type) { switch h.(type) {
case *hyphae.EmptyHypha: case *hyphae.EmptyHypha:
log.Printf("%s tries to delete empty hypha %s\n", u.Name, h.CanonicalName()) slog.Info("Trying to delete empty hyphae",
"username", u.Name, "hyphaName", h.CanonicalName())
// TODO: localize // TODO: localize
viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot delete an empty hypha") viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot delete an empty hypha")
return return
@ -87,7 +88,7 @@ func handlerDelete(w http.ResponseWriter, rq *http.Request) {
} }
if err := shroom.Delete(u, h.(hyphae.ExistingHypha)); err != nil { if err := shroom.Delete(u, h.(hyphae.ExistingHypha)); err != nil {
log.Println(err) slog.Error("Failed to delete hypha", "err", err)
viewutil.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error()) viewutil.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error())
return return
} }
@ -105,13 +106,15 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) {
switch h.(type) { switch h.(type) {
case *hyphae.EmptyHypha: case *hyphae.EmptyHypha:
log.Printf("%s tries to rename empty hypha %s", u.Name, h.CanonicalName()) slog.Info("Trying to rename empty hypha",
"username", u.Name, "hyphaName", h.CanonicalName())
viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot rename an empty hypha") // TODO: localize viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot rename an empty hypha") // TODO: localize
return return
} }
if !u.CanProceed("rename") { if !u.CanProceed("rename") {
log.Printf("%s has no rights to rename %s\n", u.Name, h.CanonicalName()) slog.Info("No rights to rename hypha",
"username", u.Name, "hyphaName", h.CanonicalName())
viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights")
return return
} }
@ -129,7 +132,8 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) {
} }
if err := shroom.Rename(oldHypha, newName, recursive, leaveRedirections, u); err != nil { if err := shroom.Rename(oldHypha, newName, recursive, leaveRedirections, u); err != nil {
log.Printf("%s tries to rename %s: %s", u.Name, oldHypha.CanonicalName(), err.Error()) slog.Error("Failed to rename hypha",
"err", err, "username", u.Name, "hyphaName", oldHypha.CanonicalName())
viewutil.HttpErr(meta, http.StatusForbidden, oldHypha.CanonicalName(), lc.Get(err.Error())) // TODO: localize viewutil.HttpErr(meta, http.StatusForbidden, oldHypha.CanonicalName(), lc.Get(err.Error())) // TODO: localize
return return
} }
@ -163,7 +167,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
default: default:
content, err = hyphae.FetchMycomarkupFile(h) content, err = hyphae.FetchMycomarkupFile(h)
if err != nil { if err != nil {
log.Println(err) slog.Error("Failed to fetch Mycomarkup file", "err", err)
viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, lc.Get("ui.error_text_fetch")) viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, lc.Get("ui.error_text_fetch"))
return return
} }

View File

@ -3,11 +3,12 @@ package newtmpl
import ( import (
"embed" "embed"
"fmt" "fmt"
"html/template"
"strings"
"github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil" "github.com/bouncepaw/mycorrhiza/web/viewutil"
"html/template"
"strings"
) )
//go:embed *.html //go:embed *.html

View File

@ -2,6 +2,7 @@ package web
import ( import (
"embed" "embed"
"github.com/bouncepaw/mycorrhiza/web/newtmpl" "github.com/bouncepaw/mycorrhiza/web/newtmpl"
"github.com/bouncepaw/mycorrhiza/web/viewutil" "github.com/bouncepaw/mycorrhiza/web/viewutil"
) )

View File

@ -2,12 +2,13 @@ package web
import ( import (
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"mime" "mime"
"net/http" "net/http"
"reflect" "reflect"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
) )
func handlerUserChangePassword(w http.ResponseWriter, rq *http.Request) { func handlerUserChangePassword(w http.ResponseWriter, rq *http.Request) {

View File

@ -2,7 +2,17 @@ package web
import ( import (
"fmt" "fmt"
"git.sr.ht/~bouncepaw/mycomarkup/v5" "html/template"
"io"
"log/slog"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/hypview" "github.com/bouncepaw/mycorrhiza/hypview"
"github.com/bouncepaw/mycorrhiza/internal/backlinks" "github.com/bouncepaw/mycorrhiza/internal/backlinks"
"github.com/bouncepaw/mycorrhiza/internal/categories" "github.com/bouncepaw/mycorrhiza/internal/categories"
@ -12,26 +22,15 @@ import (
"github.com/bouncepaw/mycorrhiza/internal/mimetype" "github.com/bouncepaw/mycorrhiza/internal/mimetype"
"github.com/bouncepaw/mycorrhiza/internal/tree" "github.com/bouncepaw/mycorrhiza/internal/tree"
"github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/mycoopts" "github.com/bouncepaw/mycorrhiza/mycoopts"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil" "github.com/bouncepaw/mycorrhiza/web/viewutil"
"html/template"
"io"
"log"
"log/slog"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/gorilla/mux"
"git.sr.ht/~bouncepaw/mycomarkup/v5"
"git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext" "git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext"
"git.sr.ht/~bouncepaw/mycomarkup/v5/tools" "git.sr.ht/~bouncepaw/mycomarkup/v5/tools"
"github.com/bouncepaw/mycorrhiza/history" "github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/util"
) )
func initReaders(r *mux.Router) { func initReaders(r *mux.Router) {
@ -109,6 +108,7 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) {
h = hyphae.ByName(hyphaName) h = hyphae.ByName(hyphaName)
) )
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
switch h := h.(type) { switch h := h.(type) {
case *hyphae.EmptyHypha: case *hyphae.EmptyHypha:
var mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco") var mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")
@ -116,27 +116,32 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) {
if err != nil { if err != nil {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
log.Printf("While serving text of %s at revision %s: %s\n", hyphaName, revHash, err.Error()) slog.Error("Failed to serve text part",
"err", err, "hyphaName", hyphaName, "revHash", revHash)
_, _ = io.WriteString(w, "Error: "+err.Error()) _, _ = io.WriteString(w, "Error: "+err.Error())
return return
} }
log.Printf("Serving text of %s from %s at revision %s\n", hyphaName, mycoFilePath, revHash) slog.Info("Serving text part",
"hyphaName", hyphaName, "revHash", revHash, "mycoFilePath", mycoFilePath)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
_, _ = io.WriteString(w, textContents) _, _ = io.WriteString(w, textContents)
case hyphae.ExistingHypha: case hyphae.ExistingHypha:
if !h.HasTextFile() { if !h.HasTextFile() {
log.Printf(`Media hypha %s has no text`) slog.Info("Media hypha has no text part; cannot serve it",
"hyphaName", h.CanonicalName())
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
} }
var textContents, err = history.FileAtRevision(h.TextFilePath(), revHash) var textContents, err = history.FileAtRevision(h.TextFilePath(), revHash)
if err != nil { if err != nil {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
log.Printf("While serving text of %s at revision %s: %s\n", hyphaName, revHash, err.Error()) slog.Error("Failed to serve text part",
"err", err, "hyphaName", h.CanonicalName(), "revHash", revHash)
_, _ = io.WriteString(w, "Error: "+err.Error()) _, _ = io.WriteString(w, "Error: "+err.Error())
return return
} }
log.Printf("Serving text of %s from %s at revision %s\n", hyphaName, h.TextFilePath(), revHash) slog.Info("Serving text part", "hyphaName", h.CanonicalName(), "revHash", revHash)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
_, _ = io.WriteString(w, textContents) _, _ = io.WriteString(w, textContents)
} }
@ -188,7 +193,7 @@ func handlerText(w http.ResponseWriter, rq *http.Request) {
hyphaName := util.HyphaNameFromRq(rq, "text") hyphaName := util.HyphaNameFromRq(rq, "text")
switch h := hyphae.ByName(hyphaName).(type) { switch h := hyphae.ByName(hyphaName).(type) {
case hyphae.ExistingHypha: case hyphae.ExistingHypha:
log.Println("Serving", h.TextFilePath()) slog.Info("Serving text part", "path", h.TextFilePath())
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
http.ServeFile(w, rq, h.TextFilePath()) http.ServeFile(w, rq, h.TextFilePath())
} }
@ -201,9 +206,10 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) {
switch h := hyphae.ByName(hyphaName).(type) { switch h := hyphae.ByName(hyphaName).(type) {
case *hyphae.EmptyHypha, *hyphae.TextualHypha: case *hyphae.EmptyHypha, *hyphae.TextualHypha:
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
log.Printf("Textual hypha %s has no media, cannot serve\n", h.CanonicalName()) slog.Info("Textual hypha has no media file; cannot serve it",
"hyphaName", h.CanonicalName())
case *hyphae.MediaHypha: case *hyphae.MediaHypha:
log.Println("Serving", h.MediaFilePath()) slog.Info("Serving media file", "path", h.MediaFilePath())
w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.MediaFilePath()))) w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.MediaFilePath())))
http.ServeFile(w, rq, h.MediaFilePath()) http.ServeFile(w, rq, h.MediaFilePath())
} }

View File

@ -1,11 +1,12 @@
package viewutil package viewutil
import ( import (
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/l18n"
"html/template" "html/template"
"io" "io"
"net/http" "net/http"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/l18n"
) )
// Meta is a bundle of common stuffs used by views, templates. // Meta is a bundle of common stuffs used by views, templates.

View File

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/cfg"
"io/fs" "io/fs"
"log" "log/slog"
"strings" "strings"
"text/template" // TODO: save the world "text/template" // TODO: save the world
@ -125,7 +125,7 @@ func Base(meta Meta, title, body string, bodyAttributes map[string]string, headE
BodyAttributes: bodyAttributes, BodyAttributes: bodyAttributes,
}) })
if err != nil { if err != nil {
log.Println(err) slog.Info("Failed to execute the legacy Base template; proceeding anyway", "err", err)
} }
return w.String() return w.String()
} }
@ -149,7 +149,7 @@ func ExecutePage(meta Meta, chain Chain, data interface {
}) { }) {
data.withBaseValues(meta, HeaderLinks, cfg.CommonScripts) data.withBaseValues(meta, HeaderLinks, cfg.CommonScripts)
if err := chain.Get(meta).ExecuteTemplate(meta.W, "page", data); err != nil { if err := chain.Get(meta).ExecuteTemplate(meta.W, "page", data); err != nil {
log.Println(err) slog.Info("Failed to execute page; proceeding anyway", "err", err)
} }
} }

View File

@ -4,12 +4,7 @@ package web
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"io" "io"
"log"
"log/slog" "log/slog"
"mime" "mime"
"net/http" "net/http"
@ -19,11 +14,15 @@ import (
"github.com/bouncepaw/mycorrhiza/help" "github.com/bouncepaw/mycorrhiza/help"
"github.com/bouncepaw/mycorrhiza/history/histweb" "github.com/bouncepaw/mycorrhiza/history/histweb"
"github.com/bouncepaw/mycorrhiza/hypview" "github.com/bouncepaw/mycorrhiza/hypview"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/interwiki" "github.com/bouncepaw/mycorrhiza/interwiki"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/misc" "github.com/bouncepaw/mycorrhiza/misc"
"github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"github.com/gorilla/mux"
) )
// Handler initializes and returns the HTTP router based on the configuration. // Handler initializes and returns the HTTP router based on the configuration.
@ -308,7 +307,7 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
errmsg := user.LoginDataHTTP(w, username, "") errmsg := user.LoginDataHTTP(w, username, "")
if errmsg != nil { if errmsg != nil {
log.Printf("Failed to login %s using Telegram: %s", username, err.Error()) slog.Error("Failed to login using Telegram", "err", err, "username", username)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
_, _ = io.WriteString( _, _ = io.WriteString(
w, w,