diff --git a/flag.go b/flag.go index 70646bf..82a2627 100644 --- a/flag.go +++ b/flag.go @@ -3,19 +3,20 @@ package main import ( "bufio" _ "embed" + "errors" "flag" "fmt" "io" - "log" + "log/slog" "os" "path/filepath" - "golang.org/x/term" - "github.com/bouncepaw/mycorrhiza/internal/cfg" "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" + + "golang.org/x/term" ) // 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. -func parseCliArgs() { +func parseCliArgs() error { var createAdminName string var versionFlag bool @@ -42,43 +43,53 @@ func parseCliArgs() { flag.Parse() if versionFlag { - fmt.Println("Mycorrhiza Wiki", version.Long) + slog.Info("Running Mycorrhiza Wiki", "version", version.Long) os.Exit(0) } args := flag.Args() 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]) 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 if createAdminName != "" { - createAdminCommand(createAdminName) + if err := createAdminCommand(createAdminName); err != nil { + os.Exit(1) + } os.Exit(0) } + return nil } -func createAdminCommand(name string) { +func createAdminCommand(name string) error { if err := files.PrepareWikiRoot(); err != nil { - log.Fatal(err) + slog.Error("Failed to prepare wiki root", "err", err) + return err } cfg.UseAuth = true cfg.AllowRegistration = true - user2.InitUserDatabase() + user.InitUserDatabase() password, err := askPass("Password") 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 { - log.Fatal(err) + if err := user.Register(name, password, "admin", "local", true); err != nil { + slog.Error("Failed to register admin", "err", err) + return err } + return nil } func askPass(prompt string) (string, error) { diff --git a/history/feed.go b/history/feed.go index 4906816..edd0dda 100644 --- a/history/feed.go +++ b/history/feed.go @@ -3,11 +3,12 @@ package history import ( "errors" "fmt" - "github.com/bouncepaw/mycorrhiza/internal/cfg" "net/url" "strings" "time" + "github.com/bouncepaw/mycorrhiza/internal/cfg" + "github.com/gorilla/feeds" ) diff --git a/history/history.go b/history/history.go index b889e80..0e77786 100644 --- a/history/history.go +++ b/history/history.go @@ -4,7 +4,7 @@ package history import ( "bytes" "fmt" - "log" + "log/slog" "os/exec" "path/filepath" "regexp" @@ -21,12 +21,14 @@ var renameMsgPattern = regexp.MustCompile(`^Rename ‘(.*)’ to ‘.*’`) var gitEnv = []string{"GIT_COMMITTER_NAME=wikimind", "GIT_COMMITTER_EMAIL=wikimind@mycorrhiza"} // Start finds git and initializes git credentials. -func Start() { +func Start() error { path, err := exec.LookPath("git") 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 + return nil } // InitGitRepo checks a Git repository and initializes it if necessary. @@ -44,7 +46,7 @@ func InitGitRepo() { } } if !isGitRepo { - log.Println("Initializing Git repo at", files.HyphaeDir()) + slog.Info("Initializing Git repo", "path", files.HyphaeDir()) gitsh("init") gitsh("config", "core.quotePath", "false") } @@ -60,7 +62,7 @@ func gitsh(args ...string) (out bytes.Buffer, err error) { b, err := cmd.CombinedOutput() if err != nil { - log.Println("gitsh:", err) + slog.Info("Git command failed", "err", err, "output", string(b)) } 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`. 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) return err } diff --git a/history/histweb/histview.go b/history/histweb/histview.go index 196b998..7c7b3a4 100644 --- a/history/histweb/histview.go +++ b/history/histweb/histview.go @@ -4,19 +4,21 @@ package histweb import ( "embed" "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" - "log" + "log/slog" "net/http" "path/filepath" "strconv" "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) { @@ -30,9 +32,9 @@ func InitHandlers(rtr *mux.Router) { rtr.HandleFunc("/recent-changes-atom", handlerRecentChangesAtom) rtr.HandleFunc("/recent-changes-json", handlerRecentChangesJSON) - chainPrimitiveDiff = viewutil2.CopyEnRuWith(fs, "view_primitive_diff.html", ruTranslation) - chainRecentChanges = viewutil2.CopyEnRuWith(fs, "view_recent_changes.html", ruTranslation) - chainHistory = viewutil2.CopyEnRuWith(fs, "view_history.html", ruTranslation) + chainPrimitiveDiff = viewutil.CopyEnRuWith(fs, "view_primitive_diff.html", ruTranslation) + chainRecentChanges = viewutil.CopyEnRuWith(fs, "view_recent_changes.html", ruTranslation) + chainHistory = viewutil.CopyEnRuWith(fs, "view_history.html", ruTranslation) } func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { @@ -45,12 +47,12 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { } var ( mycoFilePath string - h = hyphae2.ByName(util.CanonicalName(slug)) + h = hyphae.ByName(util.CanonicalName(slug)) ) switch h := h.(type) { - case hyphae2.ExistingHypha: + case hyphae.ExistingHypha: mycoFilePath = h.TextFilePath() - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco") } 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) return } - primitiveDiff(viewutil2.MetaFrom(w, rq), h, revHash, text) + primitiveDiff(viewutil.MetaFrom(w, rq), h, revHash, text) } // handlerRecentChanges displays the /recent-changes/ page. @@ -68,7 +70,7 @@ func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { if editCount > 100 { 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. @@ -81,9 +83,11 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) { if err == nil { 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. @@ -135,20 +139,20 @@ var ( {{define "n recent changes"}}{{.}} свеж{{if eq . 1}}ая правка{{else if le . 4}}их правок{{else}}их правок{{end}}{{end}} {{define "recent empty"}}Правки не найдены.{{end}} ` - chainPrimitiveDiff, chainRecentChanges, chainHistory viewutil2.Chain + chainPrimitiveDiff, chainRecentChanges, chainHistory viewutil.Chain ) type recentChangesData struct { - *viewutil2.BaseData + *viewutil.BaseData EditCount int Changes []history.Revision UserHypha string Stops []int } -func recentChanges(meta viewutil2.Meta, editCount int, changes []history.Revision) { - viewutil2.ExecutePage(meta, chainRecentChanges, recentChangesData{ - BaseData: &viewutil2.BaseData{}, +func recentChanges(meta viewutil.Meta, editCount int, changes []history.Revision) { + viewutil.ExecutePage(meta, chainRecentChanges, recentChangesData{ + BaseData: &viewutil.BaseData{}, EditCount: editCount, Changes: changes, UserHypha: cfg.UserHypha, @@ -157,13 +161,13 @@ func recentChanges(meta viewutil2.Meta, editCount int, changes []history.Revisio } type primitiveDiffData struct { - *viewutil2.BaseData + *viewutil.BaseData HyphaName string Hash string 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) if len(hunks) > 0 { var buf strings.Builder @@ -198,8 +202,8 @@ func primitiveDiff(meta viewutil2.Meta, h hyphae2.Hypha, hash, text string) { text = fmt.Sprintf( `
%s
`, text) } - viewutil2.ExecutePage(meta, chainPrimitiveDiff, primitiveDiffData{ - BaseData: &viewutil2.BaseData{}, + viewutil.ExecutePage(meta, chainPrimitiveDiff, primitiveDiffData{ + BaseData: &viewutil.BaseData{}, HyphaName: h.CanonicalName(), Hash: hash, Text: template.HTML(text), @@ -207,14 +211,14 @@ func primitiveDiff(meta viewutil2.Meta, h hyphae2.Hypha, hash, text string) { } type historyData struct { - *viewutil2.BaseData + *viewutil.BaseData HyphaName string Contents string } -func historyView(meta viewutil2.Meta, hyphaName, contents string) { - viewutil2.ExecutePage(meta, chainHistory, historyData{ - BaseData: &viewutil2.BaseData{ +func historyView(meta viewutil.Meta, hyphaName, contents string) { + viewutil.ExecutePage(meta, chainHistory, historyData{ + BaseData: &viewutil.BaseData{ Addr: "/history/" + util.CanonicalName(hyphaName), }, HyphaName: hyphaName, diff --git a/history/operations.go b/history/operations.go index 0f9eb80..71cfbd5 100644 --- a/history/operations.go +++ b/history/operations.go @@ -4,11 +4,11 @@ package history // Things related to writing history. import ( "fmt" - "github.com/bouncepaw/mycorrhiza/internal/user" "os" "path/filepath" "sync" + "github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/util" ) diff --git a/history/revision.go b/history/revision.go index 7f04309..9f5becb 100644 --- a/history/revision.go +++ b/history/revision.go @@ -2,7 +2,8 @@ package history import ( "fmt" - "log" + "log/slog" + "os" "regexp" "strconv" "strings" @@ -11,9 +12,11 @@ import ( "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 { - Hash string + // Hash is usually short. + Hash string + // Username is extracted from email. Username string Time time.Time Message string @@ -71,7 +74,9 @@ func (stream *recentChangesStream) next(n int) []Revision { res, err := gitLog(args...) if err != nil { - log.Fatal(err) + // TODO: return error + slog.Error("Failed to git log", "err", err) + os.Exit(1) } if len(res) != 0 { stream.currHash = res[len(res)-1].Hash @@ -103,14 +108,14 @@ func (stream recentChangesStream) iterator() func() (Revision, bool) { func RecentChanges(n int) []Revision { stream := newRecentChangesStream() revs := stream.next(n) - log.Printf("Found %d recent changes", len(revs)) + slog.Info("Found recent changes", "n", len(revs)) return revs } // Revisions returns slice of revisions for the given hypha name, ordered most recent first. func Revisions(hyphaName string) ([]Revision, error) { 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 } diff --git a/httpd.go b/httpd.go index ee2af1e..71bf815 100644 --- a/httpd.go +++ b/httpd.go @@ -1,16 +1,18 @@ package main import ( - "github.com/bouncepaw/mycorrhiza/internal/cfg" - "log" + "errors" + "log/slog" "net" "net/http" "os" "strings" "time" + + "github.com/bouncepaw/mycorrhiza/internal/cfg" ) -func serveHTTP(handler http.Handler) { +func serveHTTP(handler http.Handler) (err error) { server := &http.Server{ ReadTimeout: 300 * time.Second, WriteTimeout: 300 * time.Second, @@ -19,35 +21,51 @@ func serveHTTP(handler http.Handler) { } if strings.HasPrefix(cfg.ListenAddr, "/") { - startUnixSocketServer(server, cfg.ListenAddr) + err = startUnixSocketServer(server, cfg.ListenAddr) } else { server.Addr = cfg.ListenAddr - startHTTPServer(server) + err = startHTTPServer(server) } + return err } -func startUnixSocketServer(server *http.Server, socketFile string) { - os.Remove(socketFile) - - listener, err := net.Listen("unix", socketFile) +func startUnixSocketServer(server *http.Server, socketPath string) error { + err := os.Remove(socketPath) if err != nil { - log.Fatalf("Failed to start a server: %v", err) - } - defer listener.Close() - - if err := os.Chmod(socketFile, 0666); err != nil { - log.Fatalf("Failed to set socket permissions: %v", err) + return err } - log.Printf("Listening on Unix socket %s", cfg.ListenAddr) - if err := server.Serve(listener); err != http.ErrServerClosed { - log.Fatalf("Failed to start a server: %v", err) + listener, err := net.Listen("unix", socketPath) + if err != nil { + 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) { - log.Printf("Listening on %s", server.Addr) - if err := server.ListenAndServe(); err != http.ErrServerClosed { - log.Fatalf("Failed to start a server: %v", err) +func startHTTPServer(server *http.Server) error { + slog.Info("Listening over HTTP", "addr", server.Addr) + + if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { + slog.Error("Failed to start the server", "err", err) + return err } + + return nil } diff --git a/hypview/hypview.go b/hypview/hypview.go index 6881768..0843534 100644 --- a/hypview/hypview.go +++ b/hypview/hypview.go @@ -3,7 +3,7 @@ package hypview import ( "embed" "html/template" - "log" + "log/slog" "strings" "github.com/bouncepaw/mycorrhiza/internal/backlinks" @@ -66,7 +66,7 @@ func NaviTitle(meta viewutil.Meta, hyphaName string) template.HTML { HomeHypha: cfg.HomeHypha, }) if err != nil { - log.Println(err) + slog.Error("Failed to render NaviTitle properly; using nevertheless", "err", err) } return template.HTML(buf.String()) } diff --git a/internal/backlinks/backlinks.go b/internal/backlinks/backlinks.go index f2e235a..ec9fe9d 100644 --- a/internal/backlinks/backlinks.go +++ b/internal/backlinks/backlinks.go @@ -2,8 +2,8 @@ package backlinks import ( - hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae" - "log" + "github.com/bouncepaw/mycorrhiza/internal/hyphae" + "log/slog" "os" "sort" @@ -14,7 +14,7 @@ import ( func yieldHyphaBacklinks(hyphaName string) <-chan string { hyphaName = util.CanonicalName(hyphaName) out := make(chan string) - sorted := hyphae2.PathographicSort(out) + sorted := hyphae.PathographicSort(out) go func() { backlinks, exists := backlinkIndex[hyphaName] 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. func IndexBacklinks() { // 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)) for _, link := range foundLinks { if _, exists := backlinkIndex[link]; !exists { @@ -72,7 +72,7 @@ func BacklinksFor(hyphaName string) []string { func Orphans() []string { var orphans []string - for h := range hyphae2.YieldExistingHyphae() { + for h := range hyphae.YieldExistingHyphae() { if BacklinksCount(h.CanonicalName()) == 0 { orphans = append(orphans, h.CanonicalName()) } @@ -92,14 +92,14 @@ func toLinkSet(xs []string) linkSet { return result } -func fetchText(h hyphae2.Hypha) string { +func fetchText(h hyphae.Hypha) string { var path string switch h := h.(type) { - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: return "" - case *hyphae2.TextualHypha: + case *hyphae.TextualHypha: path = h.TextFilePath() - case *hyphae2.MediaHypha: + case *hyphae.MediaHypha: if !h.HasTextFile() { return "" } @@ -108,7 +108,7 @@ func fetchText(h hyphae2.Hypha) string { text, err := os.ReadFile(path) if err != nil { - log.Println(err) + slog.Error("Failed to read file", "path", path, "err", err, "hyphaName", h.CanonicalName()) return "" } return string(text) diff --git a/internal/backlinks/hooks.go b/internal/backlinks/hooks.go index ef65952..60a3c50 100644 --- a/internal/backlinks/hooks.go +++ b/internal/backlinks/hooks.go @@ -1,12 +1,13 @@ package backlinks import ( + "github.com/bouncepaw/mycorrhiza/internal/hyphae" + "github.com/bouncepaw/mycorrhiza/mycoopts" + "git.sr.ht/~bouncepaw/mycomarkup/v5" "git.sr.ht/~bouncepaw/mycomarkup/v5/links" "git.sr.ht/~bouncepaw/mycomarkup/v5/mycocontext" "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 diff --git a/internal/categories/files.go b/internal/categories/files.go index f4e4fb3..7c80546 100644 --- a/internal/categories/files.go +++ b/internal/categories/files.go @@ -2,7 +2,7 @@ package categories import ( "encoding/json" - "log" + "log/slog" "os" "slices" "sort" @@ -16,12 +16,11 @@ var categoryToHyphae = map[string]*categoryNode{} 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. -func Init() { - var ( - record, err = readCategoriesFromDisk() - ) +func Init() error { + record, err := readCategoriesFromDisk() if err != nil { - log.Fatalln(err) + slog.Error("Failed to read categories from disk", "err", err) + return err } 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 { @@ -123,9 +123,7 @@ func readCategoriesFromDisk() (catFileRecord, error) { var fileMutex sync.Mutex func saveToDisk() { - var ( - record catFileRecord - ) + var record catFileRecord for name, node := range categoryToHyphae { record.Categories = append(record.Categories, catRecord{ Name: name, @@ -134,13 +132,16 @@ func saveToDisk() { } data, err := json.MarshalIndent(record, "", "\t") 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? fileMutex.Lock() err = os.WriteFile(files.CategoriesJSON(), data, 0666) if err != nil { - log.Fatalln(err) + slog.Error("Failed to write categories.json", "err", err) + os.Exit(1) } fileMutex.Unlock() } diff --git a/internal/files/files.go b/internal/files/files.go index bb82cff..e6fa383 100644 --- a/internal/files/files.go +++ b/internal/files/files.go @@ -2,11 +2,12 @@ package files import ( - "github.com/bouncepaw/mycorrhiza/internal/cfg" - "github.com/bouncepaw/mycorrhiza/web/static" "io" "os" "path/filepath" + + "github.com/bouncepaw/mycorrhiza/internal/cfg" + "github.com/bouncepaw/mycorrhiza/web/static" ) var paths struct { diff --git a/internal/hyphae/existing_hypha.go b/internal/hyphae/existing_hypha.go index 8b6cf7f..0301137 100644 --- a/internal/hyphae/existing_hypha.go +++ b/internal/hyphae/existing_hypha.go @@ -1,9 +1,10 @@ package hyphae import ( - "github.com/bouncepaw/mycorrhiza/util" "os" "path/filepath" + + "github.com/bouncepaw/mycorrhiza/util" ) // ExistingHypha is not EmptyHypha. *MediaHypha and *TextualHypha implement this interface. diff --git a/internal/hyphae/files.go b/internal/hyphae/files.go index 9be35a2..3c499bf 100644 --- a/internal/hyphae/files.go +++ b/internal/hyphae/files.go @@ -1,11 +1,11 @@ package hyphae import ( - "github.com/bouncepaw/mycorrhiza/internal/mimetype" - "log" "log/slog" "os" "path/filepath" + + "github.com/bouncepaw/mycorrhiza/internal/mimetype" ) // 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 @@ -60,7 +60,8 @@ func Index(path string) { func indexHelper(path string, nestLevel uint, ch chan ExistingHypha) { nodes, err := os.ReadDir(path) if err != nil { - log.Fatal(err) + slog.Error("Failed to read directory", "path", path, "err", err) + os.Exit(1) } for _, node := range nodes { diff --git a/internal/migration/headings.go b/internal/migration/headings.go index fb8f3cd..1de4a35 100644 --- a/internal/migration/headings.go +++ b/internal/migration/headings.go @@ -1,11 +1,13 @@ package migration import ( - "git.sr.ht/~bouncepaw/mycomarkup/v5/tools" - "github.com/bouncepaw/mycorrhiza/internal/files" "io/ioutil" - "log" + "log/slog" "os" + + "github.com/bouncepaw/mycorrhiza/internal/files" + + "git.sr.ht/~bouncepaw/mycomarkup/v5/tools" ) var headingMarkerPath string @@ -29,7 +31,8 @@ func shouldMigrateHeadings() bool { return true } 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() return false @@ -42,6 +45,7 @@ func createHeadingMarker() { 0766, ) if err != nil { - log.Fatalln(err) + slog.Error("Failed to create heading migration marker", "err", err) + os.Exit(1) } } diff --git a/internal/migration/migration.go b/internal/migration/migration.go index d3f945f..0bcad88 100644 --- a/internal/migration/migration.go +++ b/internal/migration/migration.go @@ -8,14 +8,14 @@ package migration import ( - "github.com/bouncepaw/mycorrhiza/internal/user" "io" - "log" + "log/slog" "os" "strings" "github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/internal/hyphae" + "github.com/bouncepaw/mycorrhiza/internal/user" ) func genericLineMigrator( @@ -37,7 +37,8 @@ func genericLineMigrator( file, err := os.OpenFile(hypha.TextFilePath(), os.O_RDWR, 0766) if err != nil { 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 @@ -45,7 +46,7 @@ func genericLineMigrator( if err != nil { hop.WithErrAbort(err) _ = 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 ( @@ -59,21 +60,24 @@ func genericLineMigrator( if err != nil { hop.WithErrAbort(err) _ = 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) if err != nil { hop.WithErrAbort(err) _ = 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) if err != nil { hop.WithErrAbort(err) _ = 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() @@ -85,8 +89,8 @@ func genericLineMigrator( } 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)) } diff --git a/internal/migration/rockets.go b/internal/migration/rockets.go index 5dc050b..dc99fce 100644 --- a/internal/migration/rockets.go +++ b/internal/migration/rockets.go @@ -1,11 +1,13 @@ package migration import ( - "git.sr.ht/~bouncepaw/mycomarkup/v5/tools" - "github.com/bouncepaw/mycorrhiza/internal/files" "io/ioutil" - "log" + "log/slog" "os" + + "github.com/bouncepaw/mycorrhiza/internal/files" + + "git.sr.ht/~bouncepaw/mycomarkup/v5/tools" ) var rocketMarkerPath string @@ -33,7 +35,8 @@ func shouldMigrateRockets() bool { return true } 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() return false @@ -46,6 +49,7 @@ func createRocketLinkMarker() { 0766, ) if err != nil { - log.Fatalln(err) + slog.Error("Failed to create rocket link migration marker") + os.Exit(1) } } diff --git a/internal/shroom/can.go b/internal/shroom/can.go index c9d1f3d..8a4ccc3 100644 --- a/internal/shroom/can.go +++ b/internal/shroom/can.go @@ -2,23 +2,23 @@ package shroom import ( "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" ) // TODO: get rid of this abomination func canFactory( - rejectLogger func(hyphae2.Hypha, *user.User, string), + rejectLogger func(hyphae.Hypha, *user.User, 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, notExistsMsg string, mustExist bool, -) func(*user.User, hyphae2.Hypha, *l18n.Localizer) error { - return func(u *user.User, h hyphae2.Hypha, lc *l18n.Localizer) error { +) func(*user.User, hyphae.Hypha, *l18n.Localizer) error { + return func(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) error { if !u.CanProceed(action) { rejectLogger(h, u, "no rights") return errors.New(noRightsMsg) @@ -26,7 +26,7 @@ func canFactory( if mustExist { switch h.(type) { - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: rejectLogger(h, u, "does not exist") return errors.New(notExistsMsg) } diff --git a/internal/shroom/delete.go b/internal/shroom/delete.go index 701fd0c..f07df9d 100644 --- a/internal/shroom/delete.go +++ b/internal/shroom/delete.go @@ -2,29 +2,30 @@ package shroom import ( "fmt" + "github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/internal/backlinks" "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" ) // 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. Operation(history.TypeDeleteHypha). WithMsg(fmt.Sprintf("Delete ‘%s’", h.CanonicalName())). WithUser(u) - originalText, _ := hyphae2.FetchMycomarkupFile(h) + originalText, _ := hyphae.FetchMycomarkupFile(h) switch h := h.(type) { - case *hyphae2.MediaHypha: + case *hyphae.MediaHypha: if h.HasTextFile() { hop.WithFilesRemoved(h.MediaFilePath(), h.TextFilePath()) } else { hop.WithFilesRemoved(h.MediaFilePath()) } - case *hyphae2.TextualHypha: + case *hyphae.TextualHypha: hop.WithFilesRemoved(h.TextFilePath()) } if hop.Apply().HasErrors() { @@ -32,6 +33,6 @@ func Delete(u *user.User, h hyphae2.ExistingHypha) error { } backlinks.UpdateBacklinksAfterDelete(h, originalText) categories.RemoveHyphaFromAllCategories(h.CanonicalName()) - hyphae2.DeleteHypha(h) + hyphae.DeleteHypha(h) return nil } diff --git a/internal/shroom/header_links.go b/internal/shroom/header_links.go index dd3ff1b..af28f75 100644 --- a/internal/shroom/header_links.go +++ b/internal/shroom/header_links.go @@ -1,22 +1,24 @@ package shroom 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/blocks" "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. func SetHeaderLinks() { - switch userLinksHypha := hyphae2.ByName(cfg.HeaderLinksHypha).(type) { - case *hyphae2.EmptyHypha: + switch userLinksHypha := hyphae.ByName(cfg.HeaderLinksHypha).(type) { + case *hyphae.EmptyHypha: setDefaultHeaderLinks() - case hyphae2.ExistingHypha: + case hyphae.ExistingHypha: contents, err := os.ReadFile(userLinksHypha.TextFilePath()) if err != nil || len(contents) == 0 { setDefaultHeaderLinks() diff --git a/internal/shroom/log.go b/internal/shroom/log.go index 2aef825..535dcaf 100644 --- a/internal/shroom/log.go +++ b/internal/shroom/log.go @@ -1,20 +1,36 @@ package shroom import ( + "log/slog" + "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/user" - "log" ) 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) { - 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) { - 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) { - 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) } diff --git a/internal/shroom/rename.go b/internal/shroom/rename.go index 3aeeeb7..6150c92 100644 --- a/internal/shroom/rename.go +++ b/internal/shroom/rename.go @@ -3,36 +3,36 @@ package shroom import ( "errors" "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/filepath" "regexp" "strings" "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" ) // 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 if newName == "" { rejectRenameLog(oldHypha, u, "no new name given") 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)) return errors.New("ui.rename_badname_tip") // FIXME: There is a bug related to this. } - switch targetHypha := hyphae2.ByName(newName); targetHypha.(type) { - case hyphae2.ExistingHypha: + switch targetHypha := hyphae.ByName(newName); targetHypha.(type) { + case hyphae.ExistingHypha: if targetHypha.CanonicalName() == oldHypha.CanonicalName() { return nil } @@ -81,7 +81,7 @@ func Rename(oldHypha hyphae2.ExistingHypha, newName string, recursive bool, leav oldName = h.CanonicalName() newName = re.ReplaceAllString(oldName, newName) ) - hyphae2.RenameHyphaTo(h, newName, replaceName) + hyphae.RenameHyphaTo(h, newName, replaceName) backlinks.UpdateBacklinksAfterRename(h, oldName) categories.RenameHyphaInAllCategories(oldName, newName) if leaveRedirections { @@ -104,12 +104,12 @@ const redirectionTemplate = `=> %[1]s | 👁️➡️ %[2]s func leaveRedirection(oldName, newName string, hop *history.Op) error { var ( text = fmt.Sprintf(redirectionTemplate, newName, util.BeautifulName(newName)) - emptyHypha = hyphae2.ByName(oldName) + emptyHypha = hyphae.ByName(oldName) ) switch emptyHypha := emptyHypha.(type) { - case *hyphae2.EmptyHypha: - h := hyphae2.ExtendEmptyToTextual(emptyHypha, filepath.Join(files.HyphaeDir(), oldName+".myco")) - hyphae2.Insert(h) + case *hyphae.EmptyHypha: + h := hyphae.ExtendEmptyToTextual(emptyHypha, filepath.Join(files.HyphaeDir(), oldName+".myco")) + hyphae.Insert(h) categories.AddHyphaToCategory(oldName, cfg.RedirectionCategory) defer backlinks.UpdateBacklinksAfterEdit(h, "") 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 { - hyphaList := []hyphae2.ExistingHypha{superhypha} +func findHyphaeToRename(superhypha hyphae.ExistingHypha, recursive bool) []hyphae.ExistingHypha { + hyphaList := []hyphae.ExistingHypha{superhypha} if recursive { - hyphaList = append(hyphaList, hyphae2.Subhyphae(superhypha)...) + hyphaList = append(hyphaList, hyphae.Subhyphae(superhypha)...) } 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 ( renameMap = make(map[string]string) newNames = make([]string, len(hyphaeToRename)) @@ -138,12 +138,12 @@ func renamingPairs(hyphaeToRename []hyphae2.ExistingHypha, replaceName func(stri renameMap[h.TextFilePath()] = replaceName(h.TextFilePath()) } switch h := h.(type) { - case *hyphae2.MediaHypha: + case *hyphae.MediaHypha: renameMap[h.MediaFilePath()] = replaceName(h.MediaFilePath()) } 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 renameMap, nil diff --git a/internal/shroom/search.go b/internal/shroom/search.go index 57efad0..666752d 100644 --- a/internal/shroom/search.go +++ b/internal/shroom/search.go @@ -1,9 +1,9 @@ package shroom import ( - "github.com/bouncepaw/mycorrhiza/internal/hyphae" "strings" + "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/util" ) diff --git a/internal/shroom/unattach.go b/internal/shroom/unattach.go index 74b76b4..613cae3 100644 --- a/internal/shroom/unattach.go +++ b/internal/shroom/unattach.go @@ -2,14 +2,14 @@ package shroom import ( "fmt" - hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae" - "github.com/bouncepaw/mycorrhiza/internal/user" "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. -func RemoveMedia(u *user.User, h *hyphae2.MediaHypha) error { +func RemoveMedia(u *user.User, h *hyphae.MediaHypha) error { hop := history. Operation(history.TypeRemoveMedia). WithFilesRemoved(h.MediaFilePath()). @@ -24,9 +24,9 @@ func RemoveMedia(u *user.User, h *hyphae2.MediaHypha) error { } if h.HasTextFile() { - hyphae2.Insert(hyphae2.ShrinkMediaToTextual(h)) + hyphae.Insert(hyphae.ShrinkMediaToTextual(h)) } else { - hyphae2.DeleteHypha(h) + hyphae.DeleteHypha(h) } return nil } diff --git a/internal/shroom/upload.go b/internal/shroom/upload.go index a63c1ec..ff438a6 100644 --- a/internal/shroom/upload.go +++ b/internal/shroom/upload.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" "io" - "log" + "log/slog" "mime/multipart" "os" "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 { return err } - log.Printf("Move ‘%s’ to ‘%s’\n", prevFilePath, uploadedFilePath) + slog.Info("Move file", "from", prevFilePath, "to", uploadedFilePath) h.SetMediaFilePath(uploadedFilePath) } } diff --git a/internal/tree/tree.go b/internal/tree/tree.go index 6dc171e..44f4dac 100644 --- a/internal/tree/tree.go +++ b/internal/tree/tree.go @@ -2,13 +2,14 @@ package tree import ( "fmt" - "github.com/bouncepaw/mycorrhiza/internal/hyphae" - "github.com/bouncepaw/mycorrhiza/util" "html/template" "io" "path" "sort" "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). diff --git a/internal/user/files.go b/internal/user/files.go index d48d8a9..7d836a6 100644 --- a/internal/user/files.go +++ b/internal/user/files.go @@ -3,10 +3,10 @@ package user import ( "encoding/json" "errors" - "github.com/bouncepaw/mycorrhiza/internal/cfg" - "log" + "log/slog" "os" + "github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/files" "github.com/bouncepaw/mycorrhiza/util" ) @@ -32,19 +32,23 @@ func usersFromFile() []*User { return users } if err != nil { - log.Fatal(err) + slog.Error("Failed to read users.json", "err", err) + os.Exit(1) } + err = json.Unmarshal(contents, &users) if err != nil { - log.Fatal(err) + slog.Error("Failed to unmarshal users.json contents", "err", err) + os.Exit(1) } + for _, u := range users { u.Name = util.CanonicalName(u.Name) if u.Source == "" { u.Source = "local" } } - log.Println("Found", len(users), "users") + slog.Info("Indexed users", "n", len(users)) return users } @@ -63,20 +67,22 @@ func readTokensToUsers() { return } if err != nil { - log.Fatal(err) + slog.Error("Failed to read tokens.json", "err", err) + os.Exit(1) } var tmp map[string]string err = json.Unmarshal(contents, &tmp) if err != nil { - log.Fatal(err) + slog.Error("Failed to unmarshal tokens.json contents", "err", err) + os.Exit(1) } for token, username := range tmp { tokens.Store(token, username) // 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. @@ -94,13 +100,13 @@ func dumpUserCredentials() error { blob, err := json.MarshalIndent(userList, "", "\t") if err != nil { - log.Println(err) + slog.Error("Failed to marshal users.json", "err", err) return err } err = os.WriteFile(files.UserCredentialsJSON(), blob, 0666) if err != nil { - log.Println(err) + slog.Error("Failed to write users.json", "err", err) return err } @@ -119,11 +125,11 @@ func dumpTokens() { blob, err := json.MarshalIndent(tmp, "", "\t") if err != nil { - log.Println(err) + slog.Error("Failed to marshal tokens.json", "err", err) return } err = os.WriteFile(files.TokensJSON(), blob, 0666) if err != nil { - log.Println("an error occurred in dumpTokens function:", err) + slog.Error("Failed to write tokens.json", "err", err) } } diff --git a/internal/user/net.go b/internal/user/net.go index 00f60c2..7066d28 100644 --- a/internal/user/net.go +++ b/internal/user/net.go @@ -6,16 +6,16 @@ import ( "encoding/hex" "errors" "fmt" - "github.com/bouncepaw/mycorrhiza/internal/cfg" - "log" + "log/slog" "net/http" "sort" "strings" "time" - "golang.org/x/crypto/bcrypt" - + "github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/util" + + "golang.org/x/crypto/bcrypt" ) // 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") if !HasUsername(username) { w.WriteHeader(http.StatusBadRequest) - log.Println("Unknown username", username, "was entered") + slog.Info("Unknown username entered", "username", username) return ErrUnknownUsername } if !CredentialsOK(username, password) { w.WriteHeader(http.StatusBadRequest) - log.Println("A wrong password was entered for username", username) + slog.Info("Wrong password entered", "username", username) return ErrWrongPassword } token, err := AddSession(username) if err != nil { - log.Println(err) + slog.Error("Failed to add session", "username", username, "err", err) w.WriteHeader(http.StatusBadRequest) return err } @@ -114,7 +114,7 @@ func AddSession(username string) (string, error) { token, err := util.RandomString(16) if err == nil { commenceSession(username, token) - log.Println("New token for", username, "is", token) + slog.Info("Added session", "username", username) } return token, err } diff --git a/internal/user/user.go b/internal/user/user.go index 6aa500a..eec2ff7 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -2,12 +2,13 @@ package user import ( "fmt" - "github.com/bouncepaw/mycorrhiza/internal/cfg" "net/http" "strings" "sync" "time" + "github.com/bouncepaw/mycorrhiza/internal/cfg" + "golang.org/x/crypto/bcrypt" ) diff --git a/interwiki/interwiki.go b/interwiki/interwiki.go index de4a532..5020afc 100644 --- a/interwiki/interwiki.go +++ b/interwiki/interwiki.go @@ -4,29 +4,36 @@ package interwiki import ( "encoding/json" "errors" - "git.sr.ht/~bouncepaw/mycomarkup/v5/options" - "github.com/bouncepaw/mycorrhiza/internal/files" - "github.com/bouncepaw/mycorrhiza/util" - "log" + "log/slog" "os" "sync" + + "github.com/bouncepaw/mycorrhiza/internal/files" + "github.com/bouncepaw/mycorrhiza/util" + + "git.sr.ht/~bouncepaw/mycomarkup/v5/options" ) -func Init() { - var ( - record, err = readInterwiki() - ) +func Init() error { + record, err := readInterwiki() if err != nil { - log.Fatalln(err) + slog.Error("Failed to read interwiki", "err", err) + return err } + for _, wiki := range record { wiki := wiki // This line is required - wiki.canonize() + if err := wiki.canonize(); err != nil { + return err + } 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) { @@ -100,7 +107,6 @@ func deleteEntry(wiki *Wiki) { for i, w := range listOfEntries { i, w := i, w if w.Name == wiki.Name { - log.Println("It came to delete") // Drop ith element. listOfEntries[i] = listOfEntries[len(listOfEntries)-1] listOfEntries = listOfEntries[:len(listOfEntries)-1] @@ -113,21 +119,22 @@ func deleteEntry(wiki *Wiki) { wg.Wait() } +// TODO: There is something clearly wrong with error-returning in this function. func addEntry(wiki *Wiki) error { mutex.Lock() defer mutex.Unlock() wiki.Aliases = dropEmptyStrings(wiki.Aliases) + var ( names = append(wiki.Aliases, wiki.Name) ok, name = areNamesFree(names) ) - if !ok { - log.Printf("There are multiple uses of the same name ‘%s’\n", name) + switch { + case !ok: + slog.Error("There are multiple uses of the same name", "name", name) return errors.New(name) - } - if len(names) == 0 { - log.Println("No names passed for a new interwiki entry") - // There is something clearly wrong with error-returning in this function. + case len(names) == 0: + slog.Error("No names passed for a new interwiki entry") return errors.New("") } @@ -176,10 +183,13 @@ func readInterwiki() ([]Wiki, error) { func saveInterwikiJson() { // Trust me, wiki crashing when an admin takes an administrative action totally makes sense. 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 { - log.Fatalln(err) - } else { - log.Println("Saved interwiki.json") + slog.Error("Failed to write interwiki.json", "err", err) + os.Exit(1) } + + slog.Info("Saved interwiki.json") + } diff --git a/interwiki/web.go b/interwiki/web.go index 58ba51d..b8c62f8 100644 --- a/interwiki/web.go +++ b/interwiki/web.go @@ -2,11 +2,13 @@ package interwiki import ( "embed" - "github.com/bouncepaw/mycorrhiza/web/viewutil" - "github.com/gorilla/mux" - "log" + "log/slog" "net/http" "strings" + + "github.com/bouncepaw/mycorrhiza/web/viewutil" + + "github.com/gorilla/mux" ) var ( @@ -63,19 +65,24 @@ func handlerModifyEntry(w http.ResponseWriter, rq *http.Request) { ) 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) return } 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) return } saveInterwikiJson() - log.Printf("Modified interwiki entry ‘%s’\n", name) + slog.Info("Modified entry", "name", name) http.Redirect(w, rq, "/interwiki", http.StatusSeeOther) } diff --git a/interwiki/wiki.go b/interwiki/wiki.go index 4d0ef51..05df378 100644 --- a/interwiki/wiki.go +++ b/interwiki/wiki.go @@ -1,9 +1,11 @@ package interwiki import ( + "errors" "fmt" + "log/slog" + "github.com/bouncepaw/mycorrhiza/util" - "log" ) // WikiEngine is an enumeration of supported interwiki targets. @@ -47,14 +49,20 @@ type Wiki struct { Engine WikiEngine `json:"engine"` } -func (w *Wiki) canonize() { +func (w *Wiki) canonize() error { switch { 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 == "": - 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(): - 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) @@ -83,4 +91,6 @@ func (w *Wiki) canonize() { w.ImgSrcFormat = fmt.Sprintf("%s/{NAME}", w.URL) } } + + return nil } diff --git a/l18n/l18n.go b/l18n/l18n.go index d352d61..ea5ae44 100644 --- a/l18n/l18n.go +++ b/l18n/l18n.go @@ -21,7 +21,7 @@ import ( "encoding/json" "fmt" "io/fs" - "log" + "log/slog" "net/http" "path/filepath" "strings" @@ -78,7 +78,7 @@ func init() { var strings map[string]string 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 { diff --git a/main.go b/main.go index 4028464..21dd33f 100644 --- a/main.go +++ b/main.go @@ -5,12 +5,9 @@ package main import ( - "github.com/bouncepaw/mycorrhiza/internal/categories" - "log" - "os" - "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" @@ -22,45 +19,63 @@ import ( "github.com/bouncepaw/mycorrhiza/web" "github.com/bouncepaw/mycorrhiza/web/static" "github.com/bouncepaw/mycorrhiza/web/viewutil" + "log/slog" + "os" ) func main() { - parseCliArgs() + if err := parseCliArgs(); err != nil { + os.Exit(1) + } 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 { - 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 { - 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: + // TODO: keep all crashes in main rather than somewhere there viewutil.Init() hyphae.Index(files.HyphaeDir()) backlinks.IndexBacklinks() go backlinks.RunBacklinksConveyor() user.InitUserDatabase() - history.Start() + if err := history.Start(); err != nil { + os.Exit(1) + } history.InitGitRepo() migration.MigrateRocketsMaybe() migration.MigrateHeadingsMaybe() shroom.SetHeaderLinks() - categories.Init() - interwiki.Init() + if err := categories.Init(); err != nil { + os.Exit(1) + } + if err := interwiki.Init(); err != nil { + os.Exit(1) + } // Static files: static.InitFS(files.StaticFiles()) if !user.HasAnyAdmins() { - log.Println("Your wiki has no admin yet. Run Mycorrhiza with -create-admin option to create an admin.") + slog.Error("Your wiki has no admin yet. Run Mycorrhiza with -create-admin option to create an admin.") } - serveHTTP(web.Handler()) + err := serveHTTP(web.Handler()) + if err != nil { + os.Exit(1) + } } diff --git a/misc/about.go b/misc/about.go index 36c392a..16d1164 100644 --- a/misc/about.go +++ b/misc/about.go @@ -1,13 +1,15 @@ package misc 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/user" "github.com/bouncepaw/mycorrhiza/internal/version" "github.com/bouncepaw/mycorrhiza/l18n" - "log" - "strings" - "text/template" // sic! ) 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) if err != nil { - log.Fatalln(err) + slog.Error("Failed to parse About template", "err", err) + os.Exit(1) } data := aboutData data.Version = version.Short @@ -112,7 +115,8 @@ func AboutHTML(lc *l18n.Localizer) string { var out strings.Builder err = temp.Execute(&out, data) if err != nil { - log.Println(err) + slog.Error("Failed to execute About template", "err", err) + os.Exit(1) } return out.String() } diff --git a/misc/handlers.go b/misc/handlers.go index e282ee4..fc16802 100644 --- a/misc/handlers.go +++ b/misc/handlers.go @@ -3,7 +3,7 @@ package misc import ( "io" - "log" + "log/slog" "math/rand" "mime" "net/http" @@ -73,11 +73,11 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) { if ok := user.CanProceed(rq, "reindex"); !ok { var lc = l18n.FromRequest(rq) 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 } hyphae.ResetCount() - log.Println("Reindexing hyphae in", files.HyphaeDir()) + slog.Info("Reindexing hyphae", "hyphaeDir", files.HyphaeDir()) hyphae.Index(files.HyphaeDir()) backlinks.IndexBacklinks() 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 { var lc = l18n.FromRequest(rq) 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 } + slog.Info("Updated header links") shroom.SetHeaderLinks() http.Redirect(w, rq, "/", http.StatusSeeOther) } @@ -133,7 +134,7 @@ func handlerAbout(w http.ResponseWriter, rq *http.Request) { map[string]string{}, )) 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) if err != nil { - log.Println(err) + slog.Error("Failed to write stylesheet; proceeding anyway", "err", err) } _ = file.Close() } @@ -163,7 +164,7 @@ func handlerRobotsTxt(w http.ResponseWriter, rq *http.Request) { } _, err = io.Copy(w, file) if err != nil { - log.Println() + slog.Error("Failed to write robots.txt; proceeding anyway", "err", err) } _ = file.Close() } diff --git a/misc/views.go b/misc/views.go index 99f83ff..2cbd389 100644 --- a/misc/views.go +++ b/misc/views.go @@ -2,6 +2,7 @@ package misc import ( "embed" + "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/web/viewutil" ) diff --git a/mycoopts/mycoopts.go b/mycoopts/mycoopts.go index bd1d9f2..7fe78a8 100644 --- a/mycoopts/mycoopts.go +++ b/mycoopts/mycoopts.go @@ -2,11 +2,13 @@ package mycoopts import ( "errors" - "git.sr.ht/~bouncepaw/mycomarkup/v5/options" + "github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/interwiki" "github.com/bouncepaw/mycorrhiza/util" + + "git.sr.ht/~bouncepaw/mycomarkup/v5/options" ) func MarkupOptions(hyphaName string) options.Options { diff --git a/util/util.go b/util/util.go index 499697b..7cdd404 100644 --- a/util/util.go +++ b/util/util.go @@ -3,7 +3,7 @@ package util import ( "crypto/rand" "encoding/hex" - "log" + "log/slog" "net/http" "strings" @@ -82,7 +82,7 @@ func HyphaNameFromRq(rq *http.Request, actions ...string) string { 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 } diff --git a/web/admin.go b/web/admin.go index c01abce..d3c4b41 100644 --- a/web/admin.go +++ b/web/admin.go @@ -2,7 +2,7 @@ package web import ( "fmt" - "log" + "log/slog" "mime" "net/http" "os" @@ -115,7 +115,7 @@ func handlerAdmin(w http.ResponseWriter, rq *http.Request) { // handlerAdminShutdown kills the wiki. func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { 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) } } @@ -162,7 +162,7 @@ func handlerAdminUserEdit(w http.ResponseWriter, rq *http.Request) { u.Group = newGroup if err := user.SaveUserDatabase(); err != nil { u.Group = oldGroup - log.Println(err) + slog.Info("Failed to save user database", "err", err) f = f.WithError(err) } else { http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) @@ -241,7 +241,7 @@ func handlerAdminUserDelete(w http.ResponseWriter, rq *http.Request) { if !f.HasError() { http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) } else { - log.Println(f.Error()) + slog.Info("Failed to delete user", "err", f.Error()) } } diff --git a/web/cats.go b/web/cats.go index 47b1d7f..251b905 100644 --- a/web/cats.go +++ b/web/cats.go @@ -1,14 +1,13 @@ package web import ( - "github.com/bouncepaw/mycorrhiza/internal/categories" "io" - "log" "log/slog" "net/http" "sort" "strings" + "github.com/bouncepaw/mycorrhiza/internal/categories" "github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/util" "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. func hyphaeFromRequest(rq *http.Request) (canonicalNames []string) { 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 != "" { canonicalNames = append(canonicalNames, hyphaName) @@ -100,7 +99,8 @@ func handlerRemoveFromCategory(w http.ResponseWriter, rq *http.Request) { return } 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) return } @@ -108,7 +108,8 @@ func handlerRemoveFromCategory(w http.ResponseWriter, rq *http.Request) { // TODO: Make it more effective. 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) } diff --git a/web/mutators.go b/web/mutators.go index 75e13ae..1561514 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -1,23 +1,22 @@ package web 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/shroom" "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/mycoopts" "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) { @@ -64,14 +63,16 @@ func handlerDelete(w http.ResponseWriter, rq *http.Request) { ) 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") return } switch h.(type) { 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 viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot delete an empty hypha") return @@ -87,7 +88,7 @@ func handlerDelete(w http.ResponseWriter, rq *http.Request) { } 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()) return } @@ -105,13 +106,15 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) { switch h.(type) { 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 return } 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") return } @@ -129,7 +132,8 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) { } 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 return } @@ -163,7 +167,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { default: content, err = hyphae.FetchMycomarkupFile(h) 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")) return } diff --git a/web/newtmpl/newtmpl.go b/web/newtmpl/newtmpl.go index b0184c5..d2bf77f 100644 --- a/web/newtmpl/newtmpl.go +++ b/web/newtmpl/newtmpl.go @@ -3,11 +3,12 @@ package newtmpl import ( "embed" "fmt" + "html/template" + "strings" + "github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/web/viewutil" - "html/template" - "strings" ) //go:embed *.html diff --git a/web/pages.go b/web/pages.go index 38cf691..4f8f077 100644 --- a/web/pages.go +++ b/web/pages.go @@ -2,6 +2,7 @@ package web import ( "embed" + "github.com/bouncepaw/mycorrhiza/web/newtmpl" "github.com/bouncepaw/mycorrhiza/web/viewutil" ) diff --git a/web/password.go b/web/password.go index 4a74a7b..37e885d 100644 --- a/web/password.go +++ b/web/password.go @@ -2,12 +2,13 @@ package web import ( "fmt" - "github.com/bouncepaw/mycorrhiza/internal/user" - "github.com/bouncepaw/mycorrhiza/util" - "github.com/bouncepaw/mycorrhiza/web/viewutil" "mime" "net/http" "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) { diff --git a/web/readers.go b/web/readers.go index 0f8363c..480c874 100644 --- a/web/readers.go +++ b/web/readers.go @@ -2,7 +2,17 @@ package web import ( "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/internal/backlinks" "github.com/bouncepaw/mycorrhiza/internal/categories" @@ -12,26 +22,15 @@ import ( "github.com/bouncepaw/mycorrhiza/internal/mimetype" "github.com/bouncepaw/mycorrhiza/internal/tree" "github.com/bouncepaw/mycorrhiza/internal/user" + "github.com/bouncepaw/mycorrhiza/l18n" "github.com/bouncepaw/mycorrhiza/mycoopts" + "github.com/bouncepaw/mycorrhiza/util" "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/tools" - "github.com/bouncepaw/mycorrhiza/history" - "github.com/bouncepaw/mycorrhiza/l18n" - "github.com/bouncepaw/mycorrhiza/util" + "github.com/gorilla/mux" ) func initReaders(r *mux.Router) { @@ -109,6 +108,7 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) { h = hyphae.ByName(hyphaName) ) w.Header().Set("Content-Type", "text/plain; charset=utf-8") + switch h := h.(type) { case *hyphae.EmptyHypha: var mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco") @@ -116,27 +116,32 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) { if err != nil { 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()) 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) _, _ = io.WriteString(w, textContents) + case hyphae.ExistingHypha: 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) } var textContents, err = history.FileAtRevision(h.TextFilePath(), revHash) if err != nil { 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()) 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) _, _ = io.WriteString(w, textContents) } @@ -188,7 +193,7 @@ func handlerText(w http.ResponseWriter, rq *http.Request) { hyphaName := util.HyphaNameFromRq(rq, "text") switch h := hyphae.ByName(hyphaName).(type) { 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") http.ServeFile(w, rq, h.TextFilePath()) } @@ -201,9 +206,10 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) { switch h := hyphae.ByName(hyphaName).(type) { case *hyphae.EmptyHypha, *hyphae.TextualHypha: 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: - log.Println("Serving", h.MediaFilePath()) + slog.Info("Serving media file", "path", h.MediaFilePath()) w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.MediaFilePath()))) http.ServeFile(w, rq, h.MediaFilePath()) } diff --git a/web/viewutil/meta.go b/web/viewutil/meta.go index d47dc02..4b8ab2d 100644 --- a/web/viewutil/meta.go +++ b/web/viewutil/meta.go @@ -1,11 +1,12 @@ package viewutil import ( - "github.com/bouncepaw/mycorrhiza/internal/user" - "github.com/bouncepaw/mycorrhiza/l18n" "html/template" "io" "net/http" + + "github.com/bouncepaw/mycorrhiza/internal/user" + "github.com/bouncepaw/mycorrhiza/l18n" ) // Meta is a bundle of common stuffs used by views, templates. diff --git a/web/viewutil/viewutil.go b/web/viewutil/viewutil.go index f49de2d..80fb2f8 100644 --- a/web/viewutil/viewutil.go +++ b/web/viewutil/viewutil.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/bouncepaw/mycorrhiza/internal/cfg" "io/fs" - "log" + "log/slog" "strings" "text/template" // TODO: save the world @@ -125,7 +125,7 @@ func Base(meta Meta, title, body string, bodyAttributes map[string]string, headE BodyAttributes: bodyAttributes, }) if err != nil { - log.Println(err) + slog.Info("Failed to execute the legacy Base template; proceeding anyway", "err", err) } return w.String() } @@ -149,7 +149,7 @@ func ExecutePage(meta Meta, chain Chain, data interface { }) { data.withBaseValues(meta, HeaderLinks, cfg.CommonScripts) 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) } } diff --git a/web/web.go b/web/web.go index 01ba4e6..fad97d6 100644 --- a/web/web.go +++ b/web/web.go @@ -4,12 +4,7 @@ package web import ( "errors" "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" - "log" "log/slog" "mime" "net/http" @@ -19,11 +14,15 @@ import ( "github.com/bouncepaw/mycorrhiza/help" "github.com/bouncepaw/mycorrhiza/history/histweb" "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/l18n" "github.com/bouncepaw/mycorrhiza/misc" - "github.com/gorilla/mux" - "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. @@ -308,7 +307,7 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) { errmsg := user.LoginDataHTTP(w, username, "") 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) _, _ = io.WriteString( w,