From 5f79930539ade556f9e1f18235d1a2604ec98148 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sat, 27 Jun 2020 22:47:53 +0500 Subject: [PATCH] Final touches. Refactoring is done? --- fs/data.go | 81 +++++++++++++++++++++++++++++++ fs/hypha.go | 113 +++++++++++-------------------------------- handlers.go | 49 ++++++------------- w/m/Fruit/3.markdown | 4 ++ w/m/Fruit/meta.json | 67 +++++++++++++++++-------- 5 files changed, 174 insertions(+), 140 deletions(-) create mode 100644 fs/data.go create mode 100644 w/m/Fruit/3.markdown diff --git a/fs/data.go b/fs/data.go new file mode 100644 index 0000000..0eb142d --- /dev/null +++ b/fs/data.go @@ -0,0 +1,81 @@ +// This file contains methods for Hypha that calculate data about the hypha based on known information. +package fs + +import ( + "fmt" + "io/ioutil" + "log" + "path/filepath" + "strconv" + "strings" + + "github.com/bouncepaw/mycorrhiza/cfg" +) + +func (h *Hypha) MetaJsonPath() string { + return filepath.Join(h.Path(), "meta.json") +} + +func (h *Hypha) Path() string { + return filepath.Join(cfg.WikiDir, h.FullName) +} + +func (h *Hypha) TextPath() string { + return h.actual.TextPath +} + +func (h *Hypha) parentName() string { + return filepath.Dir(h.FullName) +} + +// hasBinaryData returns true if the revision has any binary data associated. +// During initialisation, it is guaranteed that r.BinaryMime is set to "" if the revision has no binary data. (is it?) +func (h *Hypha) hasBinaryData() bool { + return h.actual.BinaryMime != "" +} + +func (h *Hypha) TagsJoined() string { + if h.Exists { + return strings.Join(h.actual.Tags, ", ") + } + return "" +} + +func (h *Hypha) TextMime() string { + if h.Exists { + return h.actual.TextMime + } + return "text/markdown" +} + +func (h *Hypha) mimeTypeForActionRaw() string { + // If text mime type is text/html, it is not good as it will be rendered. + if h.actual.TextMime == "text/html" { + return "text/plain" + } + return h.actual.TextMime +} + +// NewestId finds the largest id among all revisions. +func (h *Hypha) NewestId() string { + var largest int + for k, _ := range h.Revisions { + id, _ := strconv.Atoi(k) + if id > largest { + largest = id + } + } + return strconv.Itoa(largest) +} + +func (h *Hypha) TextContent() string { + if h.Exists { + contents, err := ioutil.ReadFile(h.TextPath()) + if err != nil { + log.Println("Could not read", h.FullName) + return "Error: could not hypha text content file. It is recommended to cancel editing. Please contact the wiki admin. If you are the admin, see the logs." + } + return string(contents) + } + return fmt.Sprintf(cfg.DescribeHyphaHerePattern, h.FullName) +} diff --git a/fs/hypha.go b/fs/hypha.go index 7b0abb2..3ac7ed0 100644 --- a/fs/hypha.go +++ b/fs/hypha.go @@ -3,7 +3,6 @@ package fs import ( "encoding/json" "errors" - "fmt" "io/ioutil" "log" "net/http" @@ -33,44 +32,6 @@ func (h *Hypha) Invalidate(err error) *Hypha { return h } -func (h *Hypha) MetaJsonPath() string { - return filepath.Join(h.Path(), "meta.json") -} - -func (h *Hypha) Path() string { - return filepath.Join(cfg.WikiDir, h.FullName) -} - -func (h *Hypha) TextPath() string { - return h.actual.TextPath -} - -func (h *Hypha) TagsJoined() string { - if h.Exists { - return strings.Join(h.actual.Tags, ", ") - } - return "" -} - -func (h *Hypha) TextMime() string { - if h.Exists { - return h.actual.TextMime - } - return "text/markdown" -} - -func (h *Hypha) TextContent() string { - if h.Exists { - contents, err := ioutil.ReadFile(h.TextPath()) - if err != nil { - log.Println("Could not read", h.FullName) - return "Error: could not hypha text content file. It is recommended to cancel editing. Please contact the wiki admin. If you are the admin, see the logs." - } - return string(contents) - } - return fmt.Sprintf(cfg.DescribeHyphaHerePattern, h.FullName) -} - func (s *Storage) Open(name string) *Hypha { h := &Hypha{ Exists: true, @@ -107,14 +68,6 @@ func (s *Storage) Open(name string) *Hypha { return h } -func (h *Hypha) parentName() string { - return filepath.Dir(h.FullName) -} - -func (h *Hypha) metaJsonPath() string { - return filepath.Join(cfg.WikiDir, h.FullName, "meta.json") -} - // OnRevision tries to change to a revision specified by `id`. func (h *Hypha) OnRevision(id string) *Hypha { if h.Invalid || !h.Exists { @@ -133,18 +86,6 @@ func (h *Hypha) OnRevision(id string) *Hypha { return h } -// NewestId finds the largest id among all revisions. -func (h *Hypha) NewestId() string { - var largest int - for k, _ := range h.Revisions { - id, _ := strconv.Atoi(k) - if id > largest { - largest = id - } - } - return strconv.Itoa(largest) -} - func (h *Hypha) PlainLog(s string) { if h.Exists { log.Println(h.FullName, h.actual.Id, s) @@ -153,74 +94,74 @@ func (h *Hypha) PlainLog(s string) { } } -func (h *Hypha) mimeTypeForActionRaw() string { - // If text mime type is text/html, it is not good as it will be rendered. - if h.actual.TextMime == "text/html" { - return "text/plain" +func (h *Hypha) LogSuccMaybe(succMsg string) *Hypha { + if h.Invalid { + h.PlainLog(h.Err.Error()) + } else { + h.PlainLog(succMsg) } - return h.actual.TextMime -} - -// hasBinaryData returns true if the revision has any binary data associated. -// During initialisation, it is guaranteed that r.BinaryMime is set to "" if the revision has no binary data. (is it?) -func (h *Hypha) hasBinaryData() bool { - return h.actual.BinaryMime != "" + return h } // ActionRaw is used with `?action=raw`. // It writes text content of the revision without any parsing or rendering. -func (h *Hypha) ActionRaw(w http.ResponseWriter) { +func (h *Hypha) ActionRaw(w http.ResponseWriter) *Hypha { + if h.Invalid { + return h + } fileContents, err := ioutil.ReadFile(h.actual.TextPath) if err != nil { - log.Fatal(err) - return + return h.Invalidate(err) } w.Header().Set("Content-Type", h.mimeTypeForActionRaw()) w.WriteHeader(http.StatusOK) w.Write(fileContents) - h.PlainLog("Serving raw text") + return h } // ActionBinary is used with `?action=binary`. // It writes contents of binary content file. -func (h *Hypha) ActionBinary(w http.ResponseWriter) { +func (h *Hypha) ActionBinary(w http.ResponseWriter) *Hypha { + if h.Invalid { + return h + } fileContents, err := ioutil.ReadFile(h.actual.BinaryPath) if err != nil { - log.Fatal(err) - return + return h.Invalidate(err) } w.Header().Set("Content-Type", h.actual.BinaryMime) w.WriteHeader(http.StatusOK) w.Write(fileContents) - h.PlainLog("Serving raw text") + return h } // ActionZen is used with `?action=zen`. // It renders the hypha but without any layout or styles. Pure. Zen. -func (h *Hypha) ActionZen(w http.ResponseWriter) { +func (h *Hypha) ActionZen(w http.ResponseWriter) *Hypha { + if h.Invalid { + return h + } html, err := h.asHtml() if err != nil { - log.Println(err) w.WriteHeader(http.StatusInternalServerError) - return + return h.Invalidate(err) } w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) w.Write([]byte(html)) - h.PlainLog("Rendering zen") + return h } // ActionView is used with `?action=view` or no action at all. // It renders the page, the layout and everything else. -func (h *Hypha) ActionView(w http.ResponseWriter, renderExists, renderNotExists func(string, string) string) { +func (h *Hypha) ActionView(w http.ResponseWriter, renderExists, renderNotExists func(string, string) string) *Hypha { var html string var err error if h.Exists { html, err = h.asHtml() if err != nil { - log.Println(err) w.WriteHeader(http.StatusInternalServerError) - return + return h.Invalidate(err) } } w.Header().Set("Content-Type", "text/html;charset=utf-8") @@ -230,7 +171,7 @@ func (h *Hypha) ActionView(w http.ResponseWriter, renderExists, renderNotExists } else { w.Write([]byte(renderNotExists(h.FullName, ""))) } - h.PlainLog("Rendering hypha view") + return h } // CreateDirIfNeeded creates directory where the hypha must reside if needed. diff --git a/handlers.go b/handlers.go index 1dbe3f0..0f52411 100644 --- a/handlers.go +++ b/handlers.go @@ -2,13 +2,7 @@ package main import ( "log" - // "io/ioutil" - // "log" "net/http" - // "path/filepath" - // "strconv" - // "strings" - // "time" "github.com/bouncepaw/mycorrhiza/fs" "github.com/bouncepaw/mycorrhiza/render" @@ -18,40 +12,31 @@ import ( // There are handlers below. See main() for their usage. // Boilerplate code present in many handlers. Good to have it. -func HandlerBase(w http.ResponseWriter, rq *http.Request) (*fs.Hypha, bool) { +func HandlerBase(w http.ResponseWriter, rq *http.Request) *fs.Hypha { vars := mux.Vars(rq) - h := fs.Hs.Open(vars["hypha"]).OnRevision(RevInMap(vars)) - if h.Invalid { - log.Println(h.Err) - return h, false - } - return h, true + return fs.Hs.Open(vars["hypha"]).OnRevision(RevInMap(vars)) } func HandlerRaw(w http.ResponseWriter, rq *http.Request) { log.Println("?action=raw") - if h, ok := HandlerBase(w, rq); ok { - h.ActionRaw(w) - } + HandlerBase(w, rq).ActionRaw(w).LogSuccMaybe("Serving raw text") } func HandlerBinary(w http.ResponseWriter, rq *http.Request) { log.Println("?action=binary") - if h, ok := HandlerBase(w, rq); ok { - h.ActionBinary(w) - } + HandlerBase(w, rq).ActionBinary(w).LogSuccMaybe("Serving binary data") } func HandlerZen(w http.ResponseWriter, rq *http.Request) { - if h, ok := HandlerBase(w, rq); ok { - h.ActionZen(w) - } + log.Println("?action=zen") + HandlerBase(w, rq).ActionZen(w).LogSuccMaybe("Rendering zen") } func HandlerView(w http.ResponseWriter, rq *http.Request) { - if h, ok := HandlerBase(w, rq); ok { - h.ActionView(w, render.HyphaPage, render.Hypha404) - } + log.Println("?action=view") + HandlerBase(w, rq). + ActionView(w, render.HyphaPage, render.Hypha404). + LogSuccMaybe("Rendering hypha view") } func HandlerEdit(w http.ResponseWriter, rq *http.Request) { @@ -72,14 +57,12 @@ func HandlerUpdate(w http.ResponseWriter, rq *http.Request) { WriteTextFileFromHttpData(rq). WriteBinaryFileFromHttpData(rq). SaveJson(). - Store() + Store(). + LogSuccMaybe("Saved changes") - if h.Invalid { - log.Println(h.Err) - return + if !h.Invalid { + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write([]byte(render.HyphaUpdateOk(h))) } - - w.WriteHeader(http.StatusOK) - w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.Write([]byte(render.HyphaUpdateOk(h))) } diff --git a/w/m/Fruit/3.markdown b/w/m/Fruit/3.markdown new file mode 100644 index 0000000..e99cd53 --- /dev/null +++ b/w/m/Fruit/3.markdown @@ -0,0 +1,4 @@ +According to real *scientists*, fruit is a type of fetus. Most of them are tasty and cool, though some of them are really sour and depressing. Be careful when choosing fruit. Best ones are: + +* [Apple](Apple) +* [Pear](Pear) \ No newline at end of file diff --git a/w/m/Fruit/meta.json b/w/m/Fruit/meta.json index cb14bcf..b4d4797 100644 --- a/w/m/Fruit/meta.json +++ b/w/m/Fruit/meta.json @@ -1,22 +1,47 @@ { -"revisions":{ - "1":{ - "name": "Fruit", - "time": 1591635559, - "author": "bouncepaw", - "comment": "create Fruit", - "tags": ["fetus", "tasty"], - "text_mime": "text/markdown", - "text_name": "1.md" - }, - "2":{ - "name": "Fruit", - "time": 1591636222, - "author": "fungimaster", - "comment": "update Fruit", - "tags": ["fetus", "tasty"], - "text_mime": "text/markdown", - "text_name": "2.md" - } -} -} + "views": 0, + "deleted": false, + "revisions": { + "1": { + "tags": [ + "fetus", + "tasty" + ], + "name": "Fruit", + "comment": "create Fruit", + "author": "bouncepaw", + "time": 1591635559, + "text_mime": "text/markdown", + "binary_mime": "", + "text_name": "1.md", + "binary_name": "" + }, + "2": { + "tags": [ + "fetus", + "tasty" + ], + "name": "Fruit", + "comment": "update Fruit", + "author": "fungimaster", + "time": 1591636222, + "text_mime": "text/markdown", + "binary_mime": "", + "text_name": "2.md", + "binary_name": "" + }, + "3": { + "tags": null, + "name": "Fruit", + "comment": "Update Fruit", + "author": "", + "time": 1593279957, + "text_mime": "text/markdown", + "binary_mime": "", + "text_name": "3.markdown", + "binary_name": "" + } + }, + "Invalid": false, + "Err": null +} \ No newline at end of file