1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-01-31 11:29:09 +00:00

Final touches. Refactoring is done?

This commit is contained in:
Timur Ismagilov 2020-06-27 22:47:53 +05:00
parent d36f86f715
commit 5f79930539
5 changed files with 174 additions and 140 deletions

81
fs/data.go Normal file
View File

@ -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)
}

View File

@ -3,7 +3,6 @@ package fs
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
@ -33,44 +32,6 @@ func (h *Hypha) Invalidate(err error) *Hypha {
return h 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 { func (s *Storage) Open(name string) *Hypha {
h := &Hypha{ h := &Hypha{
Exists: true, Exists: true,
@ -107,14 +68,6 @@ func (s *Storage) Open(name string) *Hypha {
return h 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`. // OnRevision tries to change to a revision specified by `id`.
func (h *Hypha) OnRevision(id string) *Hypha { func (h *Hypha) OnRevision(id string) *Hypha {
if h.Invalid || !h.Exists { if h.Invalid || !h.Exists {
@ -133,18 +86,6 @@ func (h *Hypha) OnRevision(id string) *Hypha {
return h 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) { func (h *Hypha) PlainLog(s string) {
if h.Exists { if h.Exists {
log.Println(h.FullName, h.actual.Id, s) log.Println(h.FullName, h.actual.Id, s)
@ -153,74 +94,74 @@ func (h *Hypha) PlainLog(s string) {
} }
} }
func (h *Hypha) mimeTypeForActionRaw() string { func (h *Hypha) LogSuccMaybe(succMsg string) *Hypha {
// If text mime type is text/html, it is not good as it will be rendered. if h.Invalid {
if h.actual.TextMime == "text/html" { h.PlainLog(h.Err.Error())
return "text/plain" } else {
h.PlainLog(succMsg)
} }
return h.actual.TextMime return h
}
// 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 != ""
} }
// ActionRaw is used with `?action=raw`. // ActionRaw is used with `?action=raw`.
// It writes text content of the revision without any parsing or rendering. // 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) fileContents, err := ioutil.ReadFile(h.actual.TextPath)
if err != nil { if err != nil {
log.Fatal(err) return h.Invalidate(err)
return
} }
w.Header().Set("Content-Type", h.mimeTypeForActionRaw()) w.Header().Set("Content-Type", h.mimeTypeForActionRaw())
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(fileContents) w.Write(fileContents)
h.PlainLog("Serving raw text") return h
} }
// ActionBinary is used with `?action=binary`. // ActionBinary is used with `?action=binary`.
// It writes contents of binary content file. // 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) fileContents, err := ioutil.ReadFile(h.actual.BinaryPath)
if err != nil { if err != nil {
log.Fatal(err) return h.Invalidate(err)
return
} }
w.Header().Set("Content-Type", h.actual.BinaryMime) w.Header().Set("Content-Type", h.actual.BinaryMime)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(fileContents) w.Write(fileContents)
h.PlainLog("Serving raw text") return h
} }
// ActionZen is used with `?action=zen`. // ActionZen is used with `?action=zen`.
// It renders the hypha but without any layout or styles. Pure. 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() html, err := h.asHtml()
if err != nil { if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return h.Invalidate(err)
} }
w.Header().Set("Content-Type", "text/html;charset=utf-8") w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte(html)) w.Write([]byte(html))
h.PlainLog("Rendering zen") return h
} }
// ActionView is used with `?action=view` or no action at all. // ActionView is used with `?action=view` or no action at all.
// It renders the page, the layout and everything else. // 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 html string
var err error var err error
if h.Exists { if h.Exists {
html, err = h.asHtml() html, err = h.asHtml()
if err != nil { if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return h.Invalidate(err)
} }
} }
w.Header().Set("Content-Type", "text/html;charset=utf-8") w.Header().Set("Content-Type", "text/html;charset=utf-8")
@ -230,7 +171,7 @@ func (h *Hypha) ActionView(w http.ResponseWriter, renderExists, renderNotExists
} else { } else {
w.Write([]byte(renderNotExists(h.FullName, ""))) w.Write([]byte(renderNotExists(h.FullName, "")))
} }
h.PlainLog("Rendering hypha view") return h
} }
// CreateDirIfNeeded creates directory where the hypha must reside if needed. // CreateDirIfNeeded creates directory where the hypha must reside if needed.

View File

@ -2,13 +2,7 @@ package main
import ( import (
"log" "log"
// "io/ioutil"
// "log"
"net/http" "net/http"
// "path/filepath"
// "strconv"
// "strings"
// "time"
"github.com/bouncepaw/mycorrhiza/fs" "github.com/bouncepaw/mycorrhiza/fs"
"github.com/bouncepaw/mycorrhiza/render" "github.com/bouncepaw/mycorrhiza/render"
@ -18,40 +12,31 @@ import (
// There are handlers below. See main() for their usage. // There are handlers below. See main() for their usage.
// Boilerplate code present in many handlers. Good to have it. // 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) vars := mux.Vars(rq)
h := fs.Hs.Open(vars["hypha"]).OnRevision(RevInMap(vars)) return fs.Hs.Open(vars["hypha"]).OnRevision(RevInMap(vars))
if h.Invalid {
log.Println(h.Err)
return h, false
}
return h, true
} }
func HandlerRaw(w http.ResponseWriter, rq *http.Request) { func HandlerRaw(w http.ResponseWriter, rq *http.Request) {
log.Println("?action=raw") log.Println("?action=raw")
if h, ok := HandlerBase(w, rq); ok { HandlerBase(w, rq).ActionRaw(w).LogSuccMaybe("Serving raw text")
h.ActionRaw(w)
}
} }
func HandlerBinary(w http.ResponseWriter, rq *http.Request) { func HandlerBinary(w http.ResponseWriter, rq *http.Request) {
log.Println("?action=binary") log.Println("?action=binary")
if h, ok := HandlerBase(w, rq); ok { HandlerBase(w, rq).ActionBinary(w).LogSuccMaybe("Serving binary data")
h.ActionBinary(w)
}
} }
func HandlerZen(w http.ResponseWriter, rq *http.Request) { func HandlerZen(w http.ResponseWriter, rq *http.Request) {
if h, ok := HandlerBase(w, rq); ok { log.Println("?action=zen")
h.ActionZen(w) HandlerBase(w, rq).ActionZen(w).LogSuccMaybe("Rendering zen")
}
} }
func HandlerView(w http.ResponseWriter, rq *http.Request) { func HandlerView(w http.ResponseWriter, rq *http.Request) {
if h, ok := HandlerBase(w, rq); ok { log.Println("?action=view")
h.ActionView(w, render.HyphaPage, render.Hypha404) HandlerBase(w, rq).
} ActionView(w, render.HyphaPage, render.Hypha404).
LogSuccMaybe("Rendering hypha view")
} }
func HandlerEdit(w http.ResponseWriter, rq *http.Request) { func HandlerEdit(w http.ResponseWriter, rq *http.Request) {
@ -72,14 +57,12 @@ func HandlerUpdate(w http.ResponseWriter, rq *http.Request) {
WriteTextFileFromHttpData(rq). WriteTextFileFromHttpData(rq).
WriteBinaryFileFromHttpData(rq). WriteBinaryFileFromHttpData(rq).
SaveJson(). SaveJson().
Store() Store().
LogSuccMaybe("Saved changes")
if h.Invalid {
log.Println(h.Err)
return
}
if !h.Invalid {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write([]byte(render.HyphaUpdateOk(h))) w.Write([]byte(render.HyphaUpdateOk(h)))
}
} }

4
w/m/Fruit/3.markdown Normal file
View File

@ -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)

View File

@ -1,22 +1,47 @@
{ {
"revisions":{ "views": 0,
"1":{ "deleted": false,
"revisions": {
"1": {
"tags": [
"fetus",
"tasty"
],
"name": "Fruit", "name": "Fruit",
"time": 1591635559,
"author": "bouncepaw",
"comment": "create Fruit", "comment": "create Fruit",
"tags": ["fetus", "tasty"], "author": "bouncepaw",
"time": 1591635559,
"text_mime": "text/markdown", "text_mime": "text/markdown",
"text_name": "1.md" "binary_mime": "",
"text_name": "1.md",
"binary_name": ""
}, },
"2":{ "2": {
"tags": [
"fetus",
"tasty"
],
"name": "Fruit", "name": "Fruit",
"time": 1591636222,
"author": "fungimaster",
"comment": "update Fruit", "comment": "update Fruit",
"tags": ["fetus", "tasty"], "author": "fungimaster",
"time": 1591636222,
"text_mime": "text/markdown", "text_mime": "text/markdown",
"text_name": "2.md" "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
} }