From a22b70023f85c69b77e0f089e120c18f8b5607f7 Mon Sep 17 00:00:00 2001 From: hugmouse Date: Fri, 5 Mar 2021 18:40:28 +0800 Subject: [PATCH 01/18] Fix invalid css rules --- assets/default.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/default.css b/assets/default.css index d785cfc..d36fe6f 100644 --- a/assets/default.css +++ b/assets/default.css @@ -36,7 +36,7 @@ header { width: 100%; margin-bottom: 1rem; } @media screen and (max-width: 800px) { .amnt-grid { grid-template-columns: 1fr; } - .layout { grid-template-column: auto; grid-template-row: auto auto auto; } + .layout { grid-template-columns: auto; grid-template-rows: auto auto auto; } .main-width { width: 100%; } main { padding: 1rem; margin: 0; } } @@ -150,7 +150,7 @@ figcaption { padding-bottom: .5rem; } .rc-entry__links, .rc-entry__msg { grid-column: 1 / span 2; } .rc-entry__author { font-style: italic; } -.prevnext__el { display: block-inline; min-width: 40%; padding: .5rem; margin-bottom: .25rem; text-decoration: none; border-radius: .25rem; } +.prevnext__el { display: inline-block; min-width: 40%; padding: .5rem; margin-bottom: .25rem; text-decoration: none; border-radius: .25rem; } .prevnext__prev { float: left; } .prevnext__next { float: right; text-align: right; } From 416c606e6da7b67338e109f81840809b49bc1161 Mon Sep 17 00:00:00 2001 From: hugmouse Date: Fri, 5 Mar 2021 20:20:51 +0800 Subject: [PATCH 02/18] Sending a 404 status if there is no content on the page Probably a hack. I'm not sure how it should be done normally, but I have no other idea how to do it. --- http_readers.go | 21 +++++++++++++++------ util/util.go | 7 +++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/http_readers.go b/http_readers.go index a75b682..807d478 100644 --- a/http_readers.go +++ b/http_readers.go @@ -112,10 +112,19 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { contents = views.AttachmentHTML(h) + contents } } - util.HTTP200Page(w, - views.BaseHTML( - util.BeautifulName(hyphaName), - views.HyphaHTML(rq, h, contents), - u, - openGraph)) + if contents == "" { + util.HTTP404Page(w, + views.BaseHTML( + util.BeautifulName(hyphaName), + views.HyphaHTML(rq, h, contents), + u, + openGraph)) + } else { + util.HTTP200Page(w, + views.BaseHTML( + util.BeautifulName(hyphaName), + views.HyphaHTML(rq, h, contents), + u, + openGraph)) + } } diff --git a/util/util.go b/util/util.go index 6b7590f..4dbae26 100644 --- a/util/util.go +++ b/util/util.go @@ -53,6 +53,13 @@ func ShorterPath(path string) string { return path } +// HTTP404Page writes a 404 error in the status, needed when no content is found on the page. +func HTTP404Page(w http.ResponseWriter, page string) { + w.Header().Set("Content-Type", "text/html;charset=utf-8") + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(page)) +} + // HTTP200Page wraps some frequently used things for successful 200 responses. func HTTP200Page(w http.ResponseWriter, page string) { w.Header().Set("Content-Type", "text/html;charset=utf-8") From c7ab41a3b0bb21575dd5e896116f3b193b57165a Mon Sep 17 00:00:00 2001 From: Alexey Gusev Date: Fri, 5 Mar 2021 23:40:41 +0300 Subject: [PATCH 03/18] Fix token storage path --- user/files.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/user/files.go b/user/files.go index 3235497..a4fa7a0 100644 --- a/user/files.go +++ b/user/files.go @@ -4,6 +4,7 @@ import ( "encoding/json" "io/ioutil" "log" + "strings" "os" "github.com/adrg/xdg" @@ -62,10 +63,10 @@ func readTokensToUsers() { func tokenStoragePath() string { dir, err := xdg.DataFile("mycorrhiza/tokens.json") if err != nil { - // Yes, it is unix-only, but function above rarely fails, so this block is probably never reached. - path := "/home/" + os.Getenv("HOME") + "/.local/share/mycorrhiza/tokens.json" - os.MkdirAll(path, 0777) - return path + log.Fatal(err) + } + if strings.HasPrefix(dir, util.WikiDir) { + log.Fatal("Error: Wiki storage directory includes private config files") } return dir } From 964bd4168ae37bea8ed5f48b122d2c9d2debc3da Mon Sep 17 00:00:00 2001 From: DanInSpace Date: Sat, 6 Mar 2021 02:34:54 +0500 Subject: [PATCH 04/18] gitignore editors and IDEA folders --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 9632b28..f6d437f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ mycorrhiza hyphae/*.gog + +# go editors and IDEA folders +.idea/ +.vscode/ From dd5d78322f2fe4366336626000b0fd28e01784c3 Mon Sep 17 00:00:00 2001 From: DanInSpace Date: Sat, 6 Mar 2021 12:38:08 +0500 Subject: [PATCH 05/18] Typo fix --- views/stuff.qtpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 4359734..99354ca 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -118,7 +118,7 @@ for u := range user.YieldUsers() { {% func AdminPanelHTML() %}
-

Admininstrative functions

+

Administrative functions

Safe things

    From 0426c372de5aa7d0e125351f592a116944ada359 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sat, 6 Mar 2021 14:40:47 +0500 Subject: [PATCH 06/18] Support configuration files See https://mycorrhiza.lesarbr.es/hypha/configuration for an example. A copy of this example is stored at assets/config.ini. Use option -config-path to pass the config file. Note that all other CLI options have been removed. Some of them may be returned later. Also note that no real testing has been done. --- Makefile | 3 ++ README.md | 4 +-- assets/assets.qtpl.go | 4 +-- assets/config.ini | 16 ++++++++++ flag.go | 37 +++++++++++------------ go.mod | 2 +- go.sum | 4 +-- util/config.go | 70 +++++++++++++++++++++++++++++++++++++++++++ util/util.go | 26 +++++++++------- views/stuff.qtpl.go | 4 +-- 10 files changed, 131 insertions(+), 39 deletions(-) create mode 100644 assets/config.ini create mode 100644 util/config.go diff --git a/Makefile b/Makefile index 0b9db7e..51525fe 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ auth_run: build gemini_run: build ./mycorrhiza -gemini-cert-path "." metarrhiza +config_run: build + ./mycorrhiza -config-path "assets/config.ini" metarrhiza + build: go generate go build . diff --git a/README.md b/README.md index d7269e6..ac4de92 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# 🍄 MycorrhizaWiki 0.13 +# 🍄 MycorrhizaWiki 0.14 A wiki engine. [Main wiki](https://mycorrhiza.lesarbr.es) ## Building -Also see [detailed instructions](https://mycorrhiza.lesarbr.es/page/deploy) on wiki. +Also see [detailed instructions](https://mycorrhiza.lesarbr.es/hypha/deploy) on wiki. ```sh git clone --recurse-submodules https://github.com/bouncepaw/mycorrhiza cd mycorrhiza diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 160549b..94343bd 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -61,7 +61,7 @@ header { width: 100%; margin-bottom: 1rem; } @media screen and (max-width: 800px) { .amnt-grid { grid-template-columns: 1fr; } - .layout { grid-template-column: auto; grid-template-row: auto auto auto; } + .layout { grid-template-columns: auto; grid-template-rows: auto auto auto; } .main-width { width: 100%; } main { padding: 1rem; margin: 0; } } @@ -178,7 +178,7 @@ figcaption { padding-bottom: .5rem; } .rc-entry__links, .rc-entry__msg { grid-column: 1 / span 2; } .rc-entry__author { font-style: italic; } -.prevnext__el { display: block-inline; min-width: 40%; padding: .5rem; margin-bottom: .25rem; text-decoration: none; border-radius: .25rem; } +.prevnext__el { display: inline-block; min-width: 40%; padding: .5rem; margin-bottom: .25rem; text-decoration: none; border-radius: .25rem; } .prevnext__prev { float: left; } .prevnext__next { float: right; text-align: right; } diff --git a/assets/config.ini b/assets/config.ini new file mode 100644 index 0000000..0ad67b9 --- /dev/null +++ b/assets/config.ini @@ -0,0 +1,16 @@ +WikiName = My wiki +NaviTitleIcon = 🐑 + +[Hyphae] +HomeHypha = home +UserHypha = u +HeaderLinksHypha = header-links + +[Network] +HTTPPort = 8080 +URL = https://wiki +GeminiCertificatePath = /home/wiki/gemcerts + +[Authorization] +UseFixedAuth = true +FixedAuthCredentialsPath = /home/wiki/mycocredentials.json diff --git a/flag.go b/flag.go index 77a7d05..a26fee1 100644 --- a/flag.go +++ b/flag.go @@ -10,16 +10,17 @@ import ( ) func init() { - flag.StringVar(&util.URL, "url", "http://0.0.0.0:$port", "URL at which your wiki can be found. Used to generate feeds and social media previews") - flag.StringVar(&util.ServerPort, "port", "1737", "Port to serve the wiki at using HTTP") - flag.StringVar(&util.HomePage, "home", "home", "The home page name") - flag.StringVar(&util.SiteNavIcon, "icon", "🍄", "What to show in the navititle in the beginning, before the colon") - flag.StringVar(&util.SiteName, "name", "wiki", "What is the name of your wiki") - flag.StringVar(&util.UserHypha, "user-hypha", "u", "Hypha which is a superhypha of all user pages") - flag.StringVar(&util.AuthMethod, "auth-method", "none", "What auth method to use. Variants: \"none\", \"fixed\"") - flag.StringVar(&util.FixedCredentialsPath, "fixed-credentials-path", "mycocredentials.json", "Used when -auth-method=fixed. Path to file with user credentials.") - flag.StringVar(&util.HeaderLinksHypha, "header-links-hypha", "", "Optional hypha that overrides the header links") - flag.StringVar(&util.GeminiCertPath, "gemini-cert-path", "", "Directory where you store Gemini certificates. Leave empty if you don't want to use Gemini.") + // flag.StringVar(&util.URL, "url", "http://0.0.0.0:$port", "URL at which your wiki can be found. Used to generate feeds and social media previews") + // flag.StringVar(&util.ServerPort, "port", "1737", "Port to serve the wiki at using HTTP") + // flag.StringVar(&util.HomePage, "home", "home", "The home page name") + // flag.StringVar(&util.SiteNavIcon, "icon", "🍄", "What to show in the navititle in the beginning, before the colon") + // flag.StringVar(&util.SiteName, "name", "wiki", "What is the name of your wiki") + // flag.StringVar(&util.UserHypha, "user-hypha", "u", "Hypha which is a superhypha of all user pages") + // flag.StringVar(&util.AuthMethod, "auth-method", "none", "What auth method to use. Variants: \"none\", \"fixed\"") + // flag.StringVar(&util.FixedCredentialsPath, "fixed-credentials-path", "mycocredentials.json", "Used when -auth-method=fixed. Path to file with user credentials.") + // flag.StringVar(&util.HeaderLinksHypha, "header-links-hypha", "", "Optional hypha that overrides the header links") + // flag.StringVar(&util.GeminiCertPath, "gemini-cert-path", "", "Directory where you store Gemini certificates. Leave empty if you don't want to use Gemini.") + flag.StringVar(&util.ConfigFilePath, "config-path", "", "Path to a configuration file. Leave empty if you don't want to use it.") } // Do the things related to cli args and die maybe @@ -31,6 +32,10 @@ func parseCliArgs() { log.Fatal("Error: pass a wiki directory") } + if util.ConfigFilePath != "" { + util.ReadConfigFile(util.ConfigFilePath) + } + var err error WikiDir, err = filepath.Abs(args[0]) util.WikiDir = WikiDir @@ -38,20 +43,12 @@ func parseCliArgs() { log.Fatal(err) } - if util.URL == "http://0.0.0.0:$port" { + if util.URL == "" { util.URL = "http://0.0.0.0:" + util.ServerPort } util.HomePage = util.CanonicalName(util.HomePage) util.UserHypha = util.CanonicalName(util.UserHypha) util.HeaderLinksHypha = util.CanonicalName(util.HeaderLinksHypha) - - switch util.AuthMethod { - case "none": - case "fixed": - user.AuthUsed = true - user.ReadUsersFromFilesystem() - default: - log.Fatal("Error: unknown auth method:", util.AuthMethod) - } + user.AuthUsed = util.UseFixedAuth } diff --git a/go.mod b/go.mod index 26dbe9f..060d073 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 + github.com/go-ini/ini v1.62.0 // indirect github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect github.com/valyala/quicktemplate v1.6.3 - tildegit.org/solderpunk/gemcert v0.0.0-20200801165357-fc14deb27512 // indirect ) diff --git a/go.sum b/go.sum index 0aa3df2..544a723 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/adrg/xdg v0.2.2/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU= +github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY= github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= @@ -35,5 +37,3 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -tildegit.org/solderpunk/gemcert v0.0.0-20200801165357-fc14deb27512 h1:reGEt1vmGompn/6FitHdBatILTsK9CYnQOCw3weoW/s= -tildegit.org/solderpunk/gemcert v0.0.0-20200801165357-fc14deb27512/go.mod h1:gqBK7AJ5wPR1bpFOuPmlQObYxwXrFdZmNb2vdzquqoA= diff --git a/util/config.go b/util/config.go new file mode 100644 index 0000000..be9e4f3 --- /dev/null +++ b/util/config.go @@ -0,0 +1,70 @@ +package util + +import ( + "log" + "strconv" + + "github.com/go-ini/ini" +) + +type Config struct { + WikiName string + NaviTitleIcon string + Hyphae + Network + Authorization +} + +type Hyphae struct { + HomeHypha string + UserHypha string + HeaderLinksHypha string +} + +type Network struct { + HTTPPort uint64 + URL string + GeminiCertificatePath string +} + +type Authorization struct { + UseFixedAuth bool + FixedAuthCredentialsPath string +} + +func ReadConfigFile(path string) { + log.Println("Loading config at", path) + cfg := &Config{ + WikiName: "MycorrhizaWiki", + NaviTitleIcon: "🍄", + Hyphae: Hyphae{ + HomeHypha: "home", + UserHypha: "u", + HeaderLinksHypha: "", + }, + Network: Network{ + HTTPPort: 1737, + URL: "", + GeminiCertificatePath: "", + }, + Authorization: Authorization{ + UseFixedAuth: false, + FixedAuthCredentialsPath: "", + }, + } + err := ini.MapTo(cfg, path) + if err != nil { + log.Fatal(err) + } + + SiteName = cfg.WikiName + SiteNavIcon = cfg.NaviTitleIcon + HomePage = cfg.HomeHypha + UserHypha = cfg.UserHypha + HeaderLinksHypha = cfg.HeaderLinksHypha + ServerPort = strconv.FormatUint(cfg.HTTPPort, 10) + URL = cfg.URL + GeminiCertPath = cfg.GeminiCertificatePath + UseFixedAuth = cfg.UseFixedAuth + FixedCredentialsPath = cfg.FixedAuthCredentialsPath +} diff --git a/util/util.go b/util/util.go index 4dbae26..1c42d40 100644 --- a/util/util.go +++ b/util/util.go @@ -9,18 +9,24 @@ import ( "unicode" ) +// TODO: make names match to fields of config file var ( - URL string - ServerPort string - HomePage string - SiteNavIcon string - SiteName string - WikiDir string - UserHypha string - HeaderLinksHypha string - AuthMethod string + SiteName string + SiteNavIcon string + + HomePage string + UserHypha string + HeaderLinksHypha string + + ServerPort string + URL string + GeminiCertPath string + + UseFixedAuth bool FixedCredentialsPath string - GeminiCertPath string + + WikiDir string + ConfigFilePath string ) // LettersNumbersOnly keeps letters and numbers only in the given string. diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 7780726..e5c2dda 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -352,7 +352,7 @@ func StreamAboutHTML(qw422016 *qt422016.Writer) { //line views/stuff.qtpl:98 qw422016.N().S(`
      -
    • MycorrhizaWiki version: β 0.13 indev
    • +
    • MycorrhizaWiki version: β 0.13
    • `) //line views/stuff.qtpl:101 if user.AuthUsed { @@ -445,7 +445,7 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { qw422016.N().S(`
      -

      Admininstrative functions

      +

      Administrative functions

      Safe things

        From b5838c946ff21e30bdc0e297641acb620c614127 Mon Sep 17 00:00:00 2001 From: DanInSpace Date: Sat, 6 Mar 2021 14:44:20 +0500 Subject: [PATCH 07/18] Fix more typos --- assets/assets.qtpl.go | 4 ++-- hyphae/files.go | 2 +- link/link.go | 2 +- shroom/can.go | 4 ++-- views/history.qtpl | 2 +- views/stuff.qtpl.go | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 160549b..94343bd 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -61,7 +61,7 @@ header { width: 100%; margin-bottom: 1rem; } @media screen and (max-width: 800px) { .amnt-grid { grid-template-columns: 1fr; } - .layout { grid-template-column: auto; grid-template-row: auto auto auto; } + .layout { grid-template-columns: auto; grid-template-rows: auto auto auto; } .main-width { width: 100%; } main { padding: 1rem; margin: 0; } } @@ -178,7 +178,7 @@ figcaption { padding-bottom: .5rem; } .rc-entry__links, .rc-entry__msg { grid-column: 1 / span 2; } .rc-entry__author { font-style: italic; } -.prevnext__el { display: block-inline; min-width: 40%; padding: .5rem; margin-bottom: .25rem; text-decoration: none; border-radius: .25rem; } +.prevnext__el { display: inline-block; min-width: 40%; padding: .5rem; margin-bottom: .25rem; text-decoration: none; border-radius: .25rem; } .prevnext__prev { float: left; } .prevnext__next { float: right; text-align: right; } diff --git a/hyphae/files.go b/hyphae/files.go index 56ccda5..05b856d 100644 --- a/hyphae/files.go +++ b/hyphae/files.go @@ -40,7 +40,7 @@ func indexHelper(path string, nestLevel uint, ch chan *Hypha) { } for _, node := range nodes { - // If this hypha looks like it can be a hypha path, go deeper. Do not touch the .git and static folders for they have an admnistrative importance! + // If this hypha looks like it can be a hypha path, go deeper. Do not touch the .git and static folders for they have an administrative importance! if node.IsDir() && util.IsCanonicalName(node.Name()) && node.Name() != ".git" && diff --git a/link/link.go b/link/link.go index 6fe3323..cde5c4b 100644 --- a/link/link.go +++ b/link/link.go @@ -12,7 +12,7 @@ import ( type LinkType int const ( - LinkInavild LinkType = iota + LinkInvalid LinkType = iota // LinkLocalRoot is a link like "/list", "/user-list", etc. LinkLocalRoot // LinkLocalHypha is a link like "test", "../test", etc. diff --git a/shroom/can.go b/shroom/can.go index 152d896..3e0c67f 100644 --- a/shroom/can.go +++ b/shroom/can.go @@ -13,7 +13,7 @@ func canFactory( dispatcher func(*hyphae.Hypha, *user.User) (string, string), noRightsMsg string, notExistsMsg string, - careAboutExistince bool, + careAboutExistence bool, ) func(*user.User, *hyphae.Hypha) (error, string) { return func(u *user.User, h *hyphae.Hypha) (error, string) { if !u.CanProceed(action) { @@ -21,7 +21,7 @@ func canFactory( return errors.New(noRightsMsg), "Not enough rights" } - if careAboutExistince && !h.Exists { + if careAboutExistence && !h.Exists { rejectLogger(h, u, "does not exist") return errors.New(notExistsMsg), "Does not exist" } diff --git a/views/history.qtpl b/views/history.qtpl index 7b5b0ef..e76565f 100644 --- a/views/history.qtpl +++ b/views/history.qtpl @@ -27,7 +27,7 @@

        Subscribe via RSS, Atom or JSON feed.

        {% comment %} - Here I am, willing to add some accesibility using ARIA. Turns out, + Here I am, willing to add some accessibility using ARIA. Turns out, role="feed" is not supported in any screen reader as of September 2020. At least web search says so. Even JAWS doesn't support it! How come? I'll add the role anyway. -- bouncepaw diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 7780726..e5c2dda 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -352,7 +352,7 @@ func StreamAboutHTML(qw422016 *qt422016.Writer) { //line views/stuff.qtpl:98 qw422016.N().S(`
          -
        • MycorrhizaWiki version: β 0.13 indev
        • +
        • MycorrhizaWiki version: β 0.13
        • `) //line views/stuff.qtpl:101 if user.AuthUsed { @@ -445,7 +445,7 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { qw422016.N().S(`
          -

          Admininstrative functions

          +

          Administrative functions

          Safe things

            From be19d19a5e7deba7edeebb6286800b1637da1d4f Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 7 Mar 2021 19:58:37 +0500 Subject: [PATCH 08/18] Fix user credentials not being read --- flag.go | 3 +++ user/users.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/flag.go b/flag.go index a26fee1..fcc8c22 100644 --- a/flag.go +++ b/flag.go @@ -51,4 +51,7 @@ func parseCliArgs() { util.UserHypha = util.CanonicalName(util.UserHypha) util.HeaderLinksHypha = util.CanonicalName(util.HeaderLinksHypha) user.AuthUsed = util.UseFixedAuth + if user.AuthUsed && util.FixedCredentialsPath != "" { + user.ReadUsersFromFilesystem() + } } diff --git a/user/users.go b/user/users.go index 847d130..9a56212 100644 --- a/user/users.go +++ b/user/users.go @@ -66,10 +66,10 @@ func userByName(username string) *User { func commenceSession(username, token string) { tokens.Store(token, username) - go dumpTokens() + dumpTokens() } func terminateSession(token string) { tokens.Delete(token) - go dumpTokens() + dumpTokens() } From b4143ed5895e276a045ac601327acd3223997544 Mon Sep 17 00:00:00 2001 From: Mysh! Date: Tue, 9 Mar 2021 09:55:22 +0800 Subject: [PATCH 09/18] Panic fix (#44) This fixes the bug when there are no hypha in the wiki and the user clicks the "random" button. Since there are zero amount of pages, a number 0 is given to random, which causes a panic and resets the connection. See: https://github.com/bouncepaw/mycorrhiza/issues/44 --- main.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index f8780b1..203c59d 100644 --- a/main.go +++ b/main.go @@ -85,8 +85,16 @@ func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { // Redirect to a random hypha. func handlerRandom(w http.ResponseWriter, rq *http.Request) { log.Println(rq.URL) - var randomHyphaName string - i := rand.Intn(hyphae.Count()) + var ( + randomHyphaName string + amountOfHyphae int = hyphae.Count() + ) + if amountOfHyphae == 0 { + HttpErr(w, http.StatusNotFound, util.HomePage, "There are no hyphae", + "It is not possible to display a random hypha because the wiki does not contain any hyphae") + return + } + i := rand.Intn(amountOfHyphae) for h := range hyphae.YieldExistingHyphae() { if i == 0 { randomHyphaName = h.Name From e35643bb9d9bb33530f34605cccb77ba8cac4039 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Tue, 9 Mar 2021 19:27:14 +0500 Subject: [PATCH 10/18] Add -print-example-config --- Makefile | 6 - assets/assets.qtpl | 8 + assets/assets.qtpl.go | 338 ++++++++++++++++++++++++++---------------- flag.go | 24 ++- history/history.go | 29 ++-- main.go | 2 +- util/config.go | 11 +- 7 files changed, 262 insertions(+), 156 deletions(-) diff --git a/Makefile b/Makefile index 51525fe..c48dc4f 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,6 @@ run: build ./mycorrhiza metarrhiza -auth_run: build - ./mycorrhiza -auth-method fixed metarrhiza - -gemini_run: build - ./mycorrhiza -gemini-cert-path "." metarrhiza - config_run: build ./mycorrhiza -config-path "assets/config.ini" metarrhiza diff --git a/assets/assets.qtpl b/assets/assets.qtpl index 2e6b4f2..a3a56f6 100644 --- a/assets/assets.qtpl +++ b/assets/assets.qtpl @@ -1,3 +1,11 @@ +{%- func HelpMessage() -%} +Usage of %s: +{%- endfunc -%} + +{%- func ExampleConfig() -%} +{% cat "config.ini" %} +{%- endfunc -%} + {% func DefaultCSS() %} {% cat "default.css" %} {% endfunc %} diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 94343bd..00ad405 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -18,11 +18,97 @@ var ( ) //line assets/assets.qtpl:1 -func StreamDefaultCSS(qw422016 *qt422016.Writer) { +func StreamHelpMessage(qw422016 *qt422016.Writer) { //line assets/assets.qtpl:1 + qw422016.N().S(`Usage of %s: +`) +//line assets/assets.qtpl:3 +} + +//line assets/assets.qtpl:3 +func WriteHelpMessage(qq422016 qtio422016.Writer) { +//line assets/assets.qtpl:3 + qw422016 := qt422016.AcquireWriter(qq422016) +//line assets/assets.qtpl:3 + StreamHelpMessage(qw422016) +//line assets/assets.qtpl:3 + qt422016.ReleaseWriter(qw422016) +//line assets/assets.qtpl:3 +} + +//line assets/assets.qtpl:3 +func HelpMessage() string { +//line assets/assets.qtpl:3 + qb422016 := qt422016.AcquireByteBuffer() +//line assets/assets.qtpl:3 + WriteHelpMessage(qb422016) +//line assets/assets.qtpl:3 + qs422016 := string(qb422016.B) +//line assets/assets.qtpl:3 + qt422016.ReleaseByteBuffer(qb422016) +//line assets/assets.qtpl:3 + return qs422016 +//line assets/assets.qtpl:3 +} + +//line assets/assets.qtpl:5 +func StreamExampleConfig(qw422016 *qt422016.Writer) { +//line assets/assets.qtpl:6 + qw422016.N().S(`WikiName = My wiki +NaviTitleIcon = 🐑 + +[Hyphae] +HomeHypha = home +UserHypha = u +HeaderLinksHypha = header-links + +[Network] +HTTPPort = 8080 +URL = https://wiki +GeminiCertificatePath = /home/wiki/gemcerts + +[Authorization] +UseFixedAuth = true +FixedAuthCredentialsPath = /home/wiki/mycocredentials.json +`) +//line assets/assets.qtpl:6 qw422016.N().S(` `) -//line assets/assets.qtpl:2 +//line assets/assets.qtpl:7 +} + +//line assets/assets.qtpl:7 +func WriteExampleConfig(qq422016 qtio422016.Writer) { +//line assets/assets.qtpl:7 + qw422016 := qt422016.AcquireWriter(qq422016) +//line assets/assets.qtpl:7 + StreamExampleConfig(qw422016) +//line assets/assets.qtpl:7 + qt422016.ReleaseWriter(qw422016) +//line assets/assets.qtpl:7 +} + +//line assets/assets.qtpl:7 +func ExampleConfig() string { +//line assets/assets.qtpl:7 + qb422016 := qt422016.AcquireByteBuffer() +//line assets/assets.qtpl:7 + WriteExampleConfig(qb422016) +//line assets/assets.qtpl:7 + qs422016 := string(qb422016.B) +//line assets/assets.qtpl:7 + qt422016.ReleaseByteBuffer(qb422016) +//line assets/assets.qtpl:7 + return qs422016 +//line assets/assets.qtpl:7 +} + +//line assets/assets.qtpl:9 +func StreamDefaultCSS(qw422016 *qt422016.Writer) { +//line assets/assets.qtpl:9 + qw422016.N().S(` +`) +//line assets/assets.qtpl:10 qw422016.N().S(`.amnt-grid { display: grid; grid-template-columns: 1fr 1fr; } .upload-binary__input { display: block; margin: .25rem 0; } @@ -298,168 +384,168 @@ mark { background: rgba(130, 80, 30, 5); color: inherit; } .backlinks { display: none; } `) -//line assets/assets.qtpl:2 +//line assets/assets.qtpl:10 qw422016.N().S(` `) -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 } -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 func WriteDefaultCSS(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 StreamDefaultCSS(qw422016) -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 } -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 func DefaultCSS() string { -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 WriteDefaultCSS(qb422016) -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 qs422016 := string(qb422016.B) -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 return qs422016 -//line assets/assets.qtpl:3 +//line assets/assets.qtpl:11 } // Next three are from https://remixicon.com/ -//line assets/assets.qtpl:6 +//line assets/assets.qtpl:14 func StreamIconHTTP(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:6 +//line assets/assets.qtpl:14 qw422016.N().S(` `) -//line assets/assets.qtpl:7 +//line assets/assets.qtpl:15 qw422016.N().S(` `) -//line assets/assets.qtpl:7 +//line assets/assets.qtpl:15 qw422016.N().S(` `) -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 } -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 func WriteIconHTTP(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 StreamIconHTTP(qw422016) -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 } -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 func IconHTTP() string { -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 WriteIconHTTP(qb422016) -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 qs422016 := string(qb422016.B) -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 return qs422016 -//line assets/assets.qtpl:8 +//line assets/assets.qtpl:16 } -//line assets/assets.qtpl:10 +//line assets/assets.qtpl:18 func StreamIconGemini(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:10 +//line assets/assets.qtpl:18 qw422016.N().S(` `) -//line assets/assets.qtpl:11 +//line assets/assets.qtpl:19 qw422016.N().S(` `) -//line assets/assets.qtpl:11 - qw422016.N().S(` -`) -//line assets/assets.qtpl:12 -} - -//line assets/assets.qtpl:12 -func WriteIconGemini(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:12 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:12 - StreamIconGemini(qw422016) -//line assets/assets.qtpl:12 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:12 -} - -//line assets/assets.qtpl:12 -func IconGemini() string { -//line assets/assets.qtpl:12 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:12 - WriteIconGemini(qb422016) -//line assets/assets.qtpl:12 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:12 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:12 - return qs422016 -//line assets/assets.qtpl:12 -} - -//line assets/assets.qtpl:14 -func StreamIconMailto(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:14 - qw422016.N().S(` -`) -//line assets/assets.qtpl:15 - qw422016.N().S(` -`) -//line assets/assets.qtpl:15 - qw422016.N().S(` -`) -//line assets/assets.qtpl:16 -} - -//line assets/assets.qtpl:16 -func WriteIconMailto(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:16 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:16 - StreamIconMailto(qw422016) -//line assets/assets.qtpl:16 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:16 -} - -//line assets/assets.qtpl:16 -func IconMailto() string { -//line assets/assets.qtpl:16 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:16 - WriteIconMailto(qb422016) -//line assets/assets.qtpl:16 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:16 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:16 - return qs422016 -//line assets/assets.qtpl:16 -} - -// This is a modified version of https://www.svgrepo.com/svg/232085/rat - -//line assets/assets.qtpl:19 -func StreamIconGopher(qw422016 *qt422016.Writer) { //line assets/assets.qtpl:19 qw422016.N().S(` `) //line assets/assets.qtpl:20 +} + +//line assets/assets.qtpl:20 +func WriteIconGemini(qq422016 qtio422016.Writer) { +//line assets/assets.qtpl:20 + qw422016 := qt422016.AcquireWriter(qq422016) +//line assets/assets.qtpl:20 + StreamIconGemini(qw422016) +//line assets/assets.qtpl:20 + qt422016.ReleaseWriter(qw422016) +//line assets/assets.qtpl:20 +} + +//line assets/assets.qtpl:20 +func IconGemini() string { +//line assets/assets.qtpl:20 + qb422016 := qt422016.AcquireByteBuffer() +//line assets/assets.qtpl:20 + WriteIconGemini(qb422016) +//line assets/assets.qtpl:20 + qs422016 := string(qb422016.B) +//line assets/assets.qtpl:20 + qt422016.ReleaseByteBuffer(qb422016) +//line assets/assets.qtpl:20 + return qs422016 +//line assets/assets.qtpl:20 +} + +//line assets/assets.qtpl:22 +func StreamIconMailto(qw422016 *qt422016.Writer) { +//line assets/assets.qtpl:22 + qw422016.N().S(` +`) +//line assets/assets.qtpl:23 + qw422016.N().S(` +`) +//line assets/assets.qtpl:23 + qw422016.N().S(` +`) +//line assets/assets.qtpl:24 +} + +//line assets/assets.qtpl:24 +func WriteIconMailto(qq422016 qtio422016.Writer) { +//line assets/assets.qtpl:24 + qw422016 := qt422016.AcquireWriter(qq422016) +//line assets/assets.qtpl:24 + StreamIconMailto(qw422016) +//line assets/assets.qtpl:24 + qt422016.ReleaseWriter(qw422016) +//line assets/assets.qtpl:24 +} + +//line assets/assets.qtpl:24 +func IconMailto() string { +//line assets/assets.qtpl:24 + qb422016 := qt422016.AcquireByteBuffer() +//line assets/assets.qtpl:24 + WriteIconMailto(qb422016) +//line assets/assets.qtpl:24 + qs422016 := string(qb422016.B) +//line assets/assets.qtpl:24 + qt422016.ReleaseByteBuffer(qb422016) +//line assets/assets.qtpl:24 + return qs422016 +//line assets/assets.qtpl:24 +} + +// This is a modified version of https://www.svgrepo.com/svg/232085/rat + +//line assets/assets.qtpl:27 +func StreamIconGopher(qw422016 *qt422016.Writer) { +//line assets/assets.qtpl:27 + qw422016.N().S(` +`) +//line assets/assets.qtpl:28 qw422016.N().S(` `) -//line assets/assets.qtpl:20 +//line assets/assets.qtpl:28 qw422016.N().S(` `) -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 } -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 func WriteIconGopher(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 StreamIconGopher(qw422016) -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 } -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 func IconGopher() string { -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 WriteIconGopher(qb422016) -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 qs422016 := string(qb422016.B) -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 return qs422016 -//line assets/assets.qtpl:21 +//line assets/assets.qtpl:29 } diff --git a/flag.go b/flag.go index fcc8c22..b3be793 100644 --- a/flag.go +++ b/flag.go @@ -2,13 +2,18 @@ package main import ( "flag" + "fmt" "log" + "os" "path/filepath" + "github.com/bouncepaw/mycorrhiza/assets" "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/util" ) +var printExampleConfig bool + func init() { // flag.StringVar(&util.URL, "url", "http://0.0.0.0:$port", "URL at which your wiki can be found. Used to generate feeds and social media previews") // flag.StringVar(&util.ServerPort, "port", "1737", "Port to serve the wiki at using HTTP") @@ -21,6 +26,15 @@ func init() { // flag.StringVar(&util.HeaderLinksHypha, "header-links-hypha", "", "Optional hypha that overrides the header links") // flag.StringVar(&util.GeminiCertPath, "gemini-cert-path", "", "Directory where you store Gemini certificates. Leave empty if you don't want to use Gemini.") flag.StringVar(&util.ConfigFilePath, "config-path", "", "Path to a configuration file. Leave empty if you don't want to use it.") + flag.BoolVar(&printExampleConfig, "print-example-config", false, "If true, print an example configuration file contents and exit. You can save the output to a file and base your own configuration on it.") + flag.Usage = func() { + fmt.Fprintf( + flag.CommandLine.Output(), + assets.HelpMessage(), + os.Args[0], + ) + flag.PrintDefaults() + } } // Do the things related to cli args and die maybe @@ -28,13 +42,17 @@ func parseCliArgs() { flag.Parse() args := flag.Args() + if printExampleConfig { + fmt.Printf(assets.ExampleConfig()) + os.Exit(0) + } + if len(args) == 0 { log.Fatal("Error: pass a wiki directory") } - if util.ConfigFilePath != "" { - util.ReadConfigFile(util.ConfigFilePath) - } + // It is ok if the path is "" + util.ReadConfigFile(util.ConfigFilePath) var err error WikiDir, err = filepath.Abs(args[0]) diff --git a/history/history.go b/history/history.go index d02e156..a1e897b 100644 --- a/history/history.go +++ b/history/history.go @@ -13,11 +13,22 @@ import ( "github.com/bouncepaw/mycorrhiza/util" ) +// Path to git executable. Set at init() +var gitpath string + var renameMsgPattern = regexp.MustCompile(`^Rename ‘(.*)’ to ‘.*’`) -// Start initializes git credentials. +// Start finds git and initializes git credentials. func Start(wikiDir string) { - _, err := gitsh("config", "user.name", "wikimind") + path, err := exec.LookPath("git") + if err != nil { + log.Fatal("Cound not find the git executable. Check your $PATH.") + } else { + log.Println("Git path is", path) + } + gitpath = path + + _, err = gitsh("config", "user.name", "wikimind") if err != nil { log.Fatal(err) } @@ -110,20 +121,6 @@ func (rev *Revision) bestLink() string { } } -// Path to git executable. Set at init() -var gitpath string - -func init() { - path, err := exec.LookPath("git") - if err != nil { - log.Fatal("Cound not find the git executable. Check your $PATH.") - } else { - log.Println("Git path is", path) - } - gitpath = path - -} - // I pronounce it as [gɪt͡ʃ]. // gitsh is async-safe, therefore all other git-related functions in this module are too. func gitsh(args ...string) (out bytes.Buffer, err error) { diff --git a/main.go b/main.go index 203c59d..2b0987d 100644 --- a/main.go +++ b/main.go @@ -168,8 +168,8 @@ Crawl-delay: 5`)) } func main() { - log.Println("Running MycorrhizaWiki β") parseCliArgs() + log.Println("Running MycorrhizaWiki β") if err := os.Chdir(WikiDir); err != nil { log.Fatal(err) } diff --git a/util/config.go b/util/config.go index be9e4f3..0cf2687 100644 --- a/util/config.go +++ b/util/config.go @@ -33,7 +33,6 @@ type Authorization struct { } func ReadConfigFile(path string) { - log.Println("Loading config at", path) cfg := &Config{ WikiName: "MycorrhizaWiki", NaviTitleIcon: "🍄", @@ -52,9 +51,13 @@ func ReadConfigFile(path string) { FixedAuthCredentialsPath: "", }, } - err := ini.MapTo(cfg, path) - if err != nil { - log.Fatal(err) + + if path != "" { + log.Println("Loading config at", path) + err := ini.MapTo(cfg, path) + if err != nil { + log.Fatal(err) + } } SiteName = cfg.WikiName From 8e94048f159b270a6926c3749a0dd61d8c09d5a2 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Tue, 9 Mar 2021 20:51:37 +0500 Subject: [PATCH 11/18] Make preview look more like view --- views/mutators.qtpl | 2 +- views/mutators.qtpl.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/views/mutators.qtpl b/views/mutators.qtpl index 233c3d5..ff7cbf0 100644 --- a/views/mutators.qtpl +++ b/views/mutators.qtpl @@ -34,7 +34,7 @@ Cancel

            Note that the hypha is not saved yet. You can preview the changes ↓

            -
            {%s= renderedPage %}
            +
            {%s= renderedPage %}
          {% endfunc %} diff --git a/views/mutators.qtpl.go b/views/mutators.qtpl.go index 5510ceb..23ac4ea 100644 --- a/views/mutators.qtpl.go +++ b/views/mutators.qtpl.go @@ -138,11 +138,11 @@ func StreamPreviewHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, t qw422016.N().S(`" class="edit-form__cancel">Cancel

          Note that the hypha is not saved yet. You can preview the changes ↓

          -
          `) +
          `) //line views/mutators.qtpl:37 qw422016.N().S(renderedPage) //line views/mutators.qtpl:37 - qw422016.N().S(`
          + qw422016.N().S(`
      `) From 8fc036ba1c281adf347b280350f614bf911a7d38 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 14 Mar 2021 18:16:30 +0500 Subject: [PATCH 12/18] Throw away all backlink-related stuff --- assets/assets.qtpl.go | 2 - assets/default.css | 2 - hyphae/files.go | 9 +-- hyphae/hyphae.go | 119 ++++++++--------------------------- main.go | 2 - markup/outlink.go | 1 + shroom/backlink.go | 36 ----------- views/hypha.qtpl | 17 ----- views/hypha.qtpl.go | 142 ++++++++++++------------------------------ views/readers.qtpl | 1 - views/readers.qtpl.go | 85 ++++++++++++------------- 11 files changed, 108 insertions(+), 308 deletions(-) delete mode 100644 shroom/backlink.go diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 00ad405..fb79b57 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -381,8 +381,6 @@ mark { background: rgba(130, 80, 30, 5); color: inherit; } .hypha-tabs { background-color: #232323; } } } - -.backlinks { display: none; } `) //line assets/assets.qtpl:10 qw422016.N().S(` diff --git a/assets/default.css b/assets/default.css index 90d3b5a..8700c5a 100644 --- a/assets/default.css +++ b/assets/default.css @@ -270,5 +270,3 @@ mark { background: rgba(130, 80, 30, 5); color: inherit; } .hypha-tabs { background-color: #232323; } } } - -.backlinks { display: none; } diff --git a/hyphae/files.go b/hyphae/files.go index 05b856d..ad98fd8 100644 --- a/hyphae/files.go +++ b/hyphae/files.go @@ -11,8 +11,6 @@ import ( // Index finds all hypha files in the full `path` and saves them to the hypha storage. func Index(path string) { - byNamesMutex.Lock() - defer byNamesMutex.Unlock() byNames = make(map[string]*Hypha) ch := make(chan *Hypha, 5) @@ -23,11 +21,10 @@ func Index(path string) { for h := range ch { // At this time it is safe to ignore the mutex, because there is only one worker. - if oldHypha, ok := byNames[h.Name]; ok { - oldHypha.MergeIn(h) + if oh := ByName(h.Name); oh.Exists { + oh.MergeIn(h) } else { - byNames[h.Name] = h - IncrementCount() + h.Insert() } } } diff --git a/hyphae/hyphae.go b/hyphae/hyphae.go index 59e2763..996b65f 100644 --- a/hyphae/hyphae.go +++ b/hyphae/hyphae.go @@ -13,12 +13,10 @@ var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"\'&%{}]+`) type Hypha struct { sync.RWMutex - Name string + Name string // Canonical name Exists bool - TextPath string - BinaryPath string - OutLinks []*Hypha - BackLinks []*Hypha + TextPath string // == "" => no text part + BinaryPath string // == "" => no attachment } var byNames = make(map[string]*Hypha) @@ -31,56 +29,44 @@ func EmptyHypha(hyphaName string) *Hypha { Exists: false, TextPath: "", BinaryPath: "", - OutLinks: make([]*Hypha, 0), - BackLinks: make([]*Hypha, 0), } } -// ByName returns a hypha by name. If h.Exists, the returned hypha pointer is known to be part of the hypha index (byNames map). +// ByName returns a hypha by name. It may have been recorded to the storage. func ByName(hyphaName string) (h *Hypha) { - h, exists := byNames[hyphaName] - if exists { + h, recorded := byNames[hyphaName] + if recorded { return h } return EmptyHypha(hyphaName) } -// Insert inserts the hypha into the storage. It overwrites the previous record, if there was any, and returns false. If the was no previous record, return true. -func (h *Hypha) Insert() (justCreated bool) { - hp := ByName(h.Name) - +func storeHypha(h *Hypha) { byNamesMutex.Lock() - defer byNamesMutex.Unlock() - if hp.Exists { - hp = h + byNames[h.Name] = h + byNamesMutex.Unlock() +} + +// Insert inserts the hypha into the storage. A previous record is used if possible. Count incrementation is done if needed. +func (h *Hypha) Insert() (justRecorded bool) { + hp, recorded := byNames[h.Name] + if recorded { + hp.MergeIn(h) } else { - h.Exists = true - byNames[h.Name] = h + storeHypha(h) IncrementCount() } - return !hp.Exists + return !recorded } -func (h *Hypha) InsertIfNew() (justCreated bool) { +func (h *Hypha) InsertIfNew() (justRecorded bool) { if !h.Exists { return h.Insert() } return false } -func (h *Hypha) InsertIfNewKeepExistence() { - hp := ByName(h.Name) - - byNamesMutex.Lock() - defer byNamesMutex.Unlock() - if hp.Exists { - hp = h - } else { - byNames[h.Name] = h - } -} - func (h *Hypha) Delete() { byNamesMutex.Lock() h.Lock() @@ -88,10 +74,6 @@ func (h *Hypha) Delete() { DecrementCount() byNamesMutex.Unlock() h.Unlock() - - for _, outlinkHypha := range h.OutLinks { - outlinkHypha.DropBackLink(h) - } } func (h *Hypha) RenameTo(newName string) { @@ -106,6 +88,10 @@ func (h *Hypha) RenameTo(newName string) { // MergeIn merges in content file paths from a different hypha object. Prints warnings sometimes. func (h *Hypha) MergeIn(oh *Hypha) { + if h == oh { + return + } + h.Lock() if h.TextPath == "" && oh.TextPath != "" { h.TextPath = oh.TextPath } @@ -115,61 +101,6 @@ func (h *Hypha) MergeIn(oh *Hypha) { } h.BinaryPath = oh.BinaryPath } -} - -// ## Link related stuff -// Notes in pseudocode and whatnot: -// * (Reader h) does not mutate h => safe -// * (Rename h) reuses the same hypha object => safe -// * (Unattach h) and (Attach h) do not change (Backlinks h) => safe - -// * (Delete h) does not change (Backlinks h), but changes (Outlinks h), removing h from them => make it safe -// * (Unattach h) and (Attach h) => h may start or stop existing => may change (Outlinks h) => make it safe -// * (Edit h) => h may start existing => may change (Backlinks h) => make it safe -// * (Edit h) may add or remove h to or from (Outlinks h) => make it safe - -func (h *Hypha) AddOutLink(oh *Hypha) (added bool) { - h.Lock() - defer h.Unlock() - - for _, outlink := range h.OutLinks { - if outlink == oh { - return false - } - } - h.OutLinks = append(h.OutLinks, oh) - return true -} - -func (h *Hypha) AddBackLink(bh *Hypha) (added bool) { - h.Lock() - defer h.Unlock() - - for _, backlink := range h.BackLinks { - if backlink == h { - return false - } - } - h.BackLinks = append(h.BackLinks, bh) - return true -} - -func (h *Hypha) DropBackLink(bh *Hypha) { - h.Lock() - defer h.Unlock() - - if len(h.BackLinks) <= 1 { - h.BackLinks = make([]*Hypha, 0) - return - } - lastBackLinkIndex := len(h.BackLinks) - for i, backlink := range h.BackLinks { - if backlink == bh { - if i != lastBackLinkIndex { - h.BackLinks[i] = h.BackLinks[lastBackLinkIndex] - } - h.BackLinks = h.BackLinks[:lastBackLinkIndex] - return - } - } + h.Exists = oh.Exists + h.Unlock() } diff --git a/main.go b/main.go index 2b0987d..b9ff7d1 100644 --- a/main.go +++ b/main.go @@ -176,8 +176,6 @@ func main() { log.Println("Wiki storage directory is", WikiDir) hyphae.Index(WikiDir) log.Println("Indexed", hyphae.Count(), "hyphae") - shroom.FindAllBacklinks() - log.Println("Found all backlinks") history.Start(WikiDir) shroom.SetHeaderLinks() diff --git a/markup/outlink.go b/markup/outlink.go index 0580371..0f4203a 100644 --- a/markup/outlink.go +++ b/markup/outlink.go @@ -13,6 +13,7 @@ import ( // * Rocketlinks // * Transclusion // * Image galleries +// Not needed anymore, I guess. func (md *MycoDoc) OutLinks() chan string { ch := make(chan string) if !md.parsedAlready { diff --git a/shroom/backlink.go b/shroom/backlink.go deleted file mode 100644 index 860ba56..0000000 --- a/shroom/backlink.go +++ /dev/null @@ -1,36 +0,0 @@ -package shroom - -import ( - "io/ioutil" - "log" - - "github.com/bouncepaw/mycorrhiza/hyphae" - "github.com/bouncepaw/mycorrhiza/markup" -) - -// FindAllBacklinks iterates over all hyphae that have text parts, sets their outlinks and then sets backlinks. -func FindAllBacklinks() { - for h := range hyphae.FilterTextHyphae(hyphae.YieldExistingHyphae()) { - findBacklinkWorker(h) - } -} - -func findBacklinkWorker(h *hyphae.Hypha) { - var ( - textContents, err = ioutil.ReadFile(h.TextPath) - ) - if err == nil { - for outlink := range markup.Doc(h.Name, string(textContents)).OutLinks() { - outlinkHypha := hyphae.ByName(outlink) - if outlinkHypha == h { - break - } - - outlinkHypha.AddBackLink(h) - outlinkHypha.InsertIfNewKeepExistence() - h.AddOutLink(outlinkHypha) - } - } else { - log.Println("Error when reading text contents of ‘%s’: %s", h.Name, err.Error()) - } -} diff --git a/views/hypha.qtpl b/views/hypha.qtpl index a2d74ba..74d6ae6 100644 --- a/views/hypha.qtpl +++ b/views/hypha.qtpl @@ -32,23 +32,6 @@ {% endfunc %} -{% func BackLinksHTML(h *hyphae.Hypha) %} - -{% endfunc %} - {% func AttachmentHTML(h *hyphae.Hypha) %} {% switch filepath.Ext(h.BinaryPath) %} diff --git a/views/hypha.qtpl.go b/views/hypha.qtpl.go index 499b9aa..13bcc52 100644 --- a/views/hypha.qtpl.go +++ b/views/hypha.qtpl.go @@ -123,175 +123,111 @@ func NaviTitleHTML(h *hyphae.Hypha) string { } //line views/hypha.qtpl:35 -func StreamBackLinksHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) { +func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) { //line views/hypha.qtpl:35 qw422016.N().S(` - -`) -//line views/hypha.qtpl:50 -} - -//line views/hypha.qtpl:50 -func WriteBackLinksHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:50 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/hypha.qtpl:50 - StreamBackLinksHTML(qw422016, h) -//line views/hypha.qtpl:50 - qt422016.ReleaseWriter(qw422016) -//line views/hypha.qtpl:50 -} - -//line views/hypha.qtpl:50 -func BackLinksHTML(h *hyphae.Hypha) string { -//line views/hypha.qtpl:50 - qb422016 := qt422016.AcquireByteBuffer() -//line views/hypha.qtpl:50 - WriteBackLinksHTML(qb422016, h) -//line views/hypha.qtpl:50 - qs422016 := string(qb422016.B) -//line views/hypha.qtpl:50 - qt422016.ReleaseByteBuffer(qb422016) -//line views/hypha.qtpl:50 - return qs422016 -//line views/hypha.qtpl:50 -} - -//line views/hypha.qtpl:52 -func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:52 - qw422016.N().S(` `) -//line views/hypha.qtpl:53 +//line views/hypha.qtpl:36 switch filepath.Ext(h.BinaryPath) { -//line views/hypha.qtpl:55 +//line views/hypha.qtpl:38 case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico": -//line views/hypha.qtpl:55 +//line views/hypha.qtpl:38 qw422016.N().S(`
      `) -//line views/hypha.qtpl:60 +//line views/hypha.qtpl:43 case ".ogg", ".webm", ".mp4": -//line views/hypha.qtpl:60 +//line views/hypha.qtpl:43 qw422016.N().S(`
      `) -//line views/hypha.qtpl:68 +//line views/hypha.qtpl:51 case ".mp3": -//line views/hypha.qtpl:68 +//line views/hypha.qtpl:51 qw422016.N().S(`
      `) -//line views/hypha.qtpl:76 +//line views/hypha.qtpl:59 default: -//line views/hypha.qtpl:76 +//line views/hypha.qtpl:59 qw422016.N().S(` `) -//line views/hypha.qtpl:80 +//line views/hypha.qtpl:63 } -//line views/hypha.qtpl:80 +//line views/hypha.qtpl:63 qw422016.N().S(` `) -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 } -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 StreamAttachmentHTML(qw422016, h) -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 qt422016.ReleaseWriter(qw422016) -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 } -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 func AttachmentHTML(h *hyphae.Hypha) string { -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 qb422016 := qt422016.AcquireByteBuffer() -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 WriteAttachmentHTML(qb422016, h) -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 qs422016 := string(qb422016.B) -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 qt422016.ReleaseByteBuffer(qb422016) -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 return qs422016 -//line views/hypha.qtpl:81 +//line views/hypha.qtpl:64 } diff --git a/views/readers.qtpl b/views/readers.qtpl index 08e6eb9..cf7c478 100644 --- a/views/readers.qtpl +++ b/views/readers.qtpl @@ -108,7 +108,6 @@ If `contents` == "", a helpful message is shown instead. {%= SubhyphaeHTML(subhyphae) %}
{%= RelativeHyphaeHTML(relatives) %} -{%= BackLinksHTML(h) %}
{% endfunc %} diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index f9921e4..ef9c851 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -345,110 +345,105 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hyph StreamRelativeHyphaeHTML(qw422016, relatives) //line views/readers.qtpl:110 qw422016.N().S(` -`) -//line views/readers.qtpl:111 - StreamBackLinksHTML(qw422016, h) -//line views/readers.qtpl:111 - qw422016.N().S(` `) -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 } -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 StreamHyphaHTML(qw422016, rq, h, contents) -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 } -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) string { -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 WriteHyphaHTML(qb422016, rq, h, contents) -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 qs422016 := string(qb422016.B) -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 return qs422016 -//line views/readers.qtpl:113 +//line views/readers.qtpl:112 } -//line views/readers.qtpl:115 +//line views/readers.qtpl:114 func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:115 +//line views/readers.qtpl:114 qw422016.N().S(` `) -//line views/readers.qtpl:117 +//line views/readers.qtpl:116 relatives, subhyphae, _, _ := tree.Tree(h.Name) -//line views/readers.qtpl:118 +//line views/readers.qtpl:117 qw422016.N().S(` `) -//line views/readers.qtpl:119 +//line views/readers.qtpl:118 StreamNavHTML(qw422016, rq, h.Name, "revision", revHash) -//line views/readers.qtpl:119 +//line views/readers.qtpl:118 qw422016.N().S(`

Please note that viewing binary parts of hyphae is not supported in history for now.

`) -//line views/readers.qtpl:124 +//line views/readers.qtpl:123 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:124 +//line views/readers.qtpl:123 qw422016.N().S(` `) -//line views/readers.qtpl:125 +//line views/readers.qtpl:124 qw422016.N().S(contents) -//line views/readers.qtpl:125 +//line views/readers.qtpl:124 qw422016.N().S(`
`) -//line views/readers.qtpl:127 +//line views/readers.qtpl:126 StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:127 +//line views/readers.qtpl:126 qw422016.N().S(`
`) -//line views/readers.qtpl:129 +//line views/readers.qtpl:128 StreamRelativeHyphaeHTML(qw422016, relatives) -//line views/readers.qtpl:129 +//line views/readers.qtpl:128 qw422016.N().S(`
`) -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 } -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 StreamRevisionHTML(qw422016, rq, h, contents, revHash) -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 } -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) string { -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 WriteRevisionHTML(qb422016, rq, h, contents, revHash) -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 qs422016 := string(qb422016.B) -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 return qs422016 -//line views/readers.qtpl:131 +//line views/readers.qtpl:130 } From f11314488c87786dbf753581adf038181bf77350 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 14 Mar 2021 18:29:57 +0500 Subject: [PATCH 13/18] Add /admin/reindex-users --- http_admin.go | 10 ++++++++++ views/stuff.qtpl | 6 ++++++ views/stuff.qtpl.go | 32 +++++++++++++++++++------------- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/http_admin.go b/http_admin.go index 2b20fb5..2b95e22 100644 --- a/http_admin.go +++ b/http_admin.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/bouncepaw/mycorrhiza/user" + "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/views" ) @@ -13,6 +14,7 @@ func initAdmin() { if user.AuthUsed { http.HandleFunc("/admin", handlerAdmin) http.HandleFunc("/admin/shutdown", handlerAdminShutdown) + http.HandleFunc("/admin/reindex-users", handlerAdminReindexUsers) } } @@ -31,3 +33,11 @@ func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { log.Fatal("An admin commanded the wiki to shutdown") } } + +func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { + log.Println(rq.URL) + if user.CanProceed(rq, "admin") && rq.Method == "POST" { + user.ReadUsersFromFilesystem() + http.Redirect(w, rq, "/hypha/"+util.UserHypha, http.StatusSeeOther) + } +} diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 99354ca..96ee43e 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -141,6 +141,12 @@ for u := range user.YieldUsers() { +
+
+ Reindex users + +
+
diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index e5c2dda..170db4c 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -468,35 +468,41 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { +
+
+ Reindex users + +
+
`) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 } -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 func WriteAdminPanelHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 StreamAdminPanelHTML(qw422016) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 } -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 func AdminPanelHTML() string { -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 WriteAdminPanelHTML(qb422016) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 return qs422016 -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:153 } From f3c4a45c3d9d8e2da2a01de11a141b464053376e Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 14 Mar 2021 20:01:32 +0500 Subject: [PATCH 14/18] Add primitive diffs accessible from history pages --- history/information.go | 7 +- http_readers.go | 18 +++ user/user.go | 1 + views/history.qtpl | 21 +++ views/history.qtpl.go | 292 ++++++++++++++++++++++++++--------------- 5 files changed, 229 insertions(+), 110 deletions(-) diff --git a/history/information.go b/history/information.go index f3cf8a7..cd22f0c 100644 --- a/history/information.go +++ b/history/information.go @@ -143,7 +143,7 @@ func (rev *Revision) asHistoryEntry(hyphaName string) (html string) {
  • - %[3]s + %[3]s %[4]s %[5]s
  • @@ -175,3 +175,8 @@ func FileAtRevision(filepath, hash string) (string, error) { out, err := gitsh("show", hash+":"+strings.TrimPrefix(filepath, util.WikiDir+"/")) return out.String(), err } + +func PrimitiveDiffAtRevision(filepath, hash string) (string, error) { + out, err := gitsh("diff", "--unified=1", "--no-color", hash+"~", hash, "--", filepath) + return out.String(), err +} diff --git a/http_readers.go b/http_readers.go index 807d478..597d8b8 100644 --- a/http_readers.go +++ b/http_readers.go @@ -24,6 +24,7 @@ func init() { http.HandleFunc("/text/", handlerText) http.HandleFunc("/binary/", handlerBinary) http.HandleFunc("/rev/", handlerRevision) + http.HandleFunc("/primitive-diff/", handlerPrimitiveDiff) http.HandleFunc("/attachment/", handlerAttachment) } @@ -41,6 +42,23 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) { u)) } +func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { + log.Println(rq.URL) + var ( + shorterUrl = strings.TrimPrefix(rq.URL.Path, "/primitive-diff/") + firstSlashIndex = strings.IndexRune(shorterUrl, '/') + revHash = shorterUrl[:firstSlashIndex] + hyphaName = util.CanonicalName(shorterUrl[firstSlashIndex+1:]) + h = hyphae.ByName(hyphaName) + u = user.FromRequest(rq) + ) + util.HTTP200Page(w, + views.BaseHTML( + fmt.Sprintf("Diff of %s at %s", hyphaName, revHash), + views.PrimitiveDiffHTML(rq, h, u, revHash), + u)) +} + // handlerRevision displays a specific revision of text part a page func handlerRevision(w http.ResponseWriter, rq *http.Request) { log.Println(rq.URL) diff --git a/user/user.go b/user/user.go index aa7a74c..e126d76 100644 --- a/user/user.go +++ b/user/user.go @@ -26,6 +26,7 @@ var minimalRights = map[string]int{ "delete-ask": 3, "delete-confirm": 3, "reindex": 4, + "admin": 4, "admin/shutdown": 4, } diff --git a/views/history.qtpl b/views/history.qtpl index e76565f..cf645be 100644 --- a/views/history.qtpl +++ b/views/history.qtpl @@ -1,8 +1,29 @@ {% import "net/http" %} {% import "github.com/bouncepaw/mycorrhiza/util" %} +{% import "github.com/bouncepaw/mycorrhiza/user" %} +{% import "github.com/bouncepaw/mycorrhiza/hyphae" %} {% import "github.com/bouncepaw/mycorrhiza/history" %} + +{% func PrimitiveDiffHTML(rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) %} +{% code +text, err := history.PrimitiveDiffAtRevision(h.TextPath, hash) +if err != nil { + text = err.Error() +} +%} +{%= NavHTML(rq, h.Name, "history") %} +
    +
    +
    +

    Diff {%s util.BeautifulName(h.Name) %} at {%s hash %}

    +
    {%s text %}
    +
    +
    +
    +{% endfunc %} + {% func RecentChangesHTML(n int) %}
    diff --git a/views/history.qtpl.go b/views/history.qtpl.go index 6d81497..d61101f 100644 --- a/views/history.qtpl.go +++ b/views/history.qtpl.go @@ -11,24 +11,98 @@ import "net/http" import "github.com/bouncepaw/mycorrhiza/util" //line views/history.qtpl:4 -import "github.com/bouncepaw/mycorrhiza/history" +import "github.com/bouncepaw/mycorrhiza/user" + +//line views/history.qtpl:5 +import "github.com/bouncepaw/mycorrhiza/hyphae" //line views/history.qtpl:6 +import "github.com/bouncepaw/mycorrhiza/history" + +//line views/history.qtpl:9 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/history.qtpl:6 +//line views/history.qtpl:9 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/history.qtpl:6 +//line views/history.qtpl:9 +func StreamPrimitiveDiffHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) { +//line views/history.qtpl:9 + qw422016.N().S(` +`) +//line views/history.qtpl:11 + text, err := history.PrimitiveDiffAtRevision(h.TextPath, hash) + if err != nil { + text = err.Error() + } + +//line views/history.qtpl:15 + qw422016.N().S(` +`) +//line views/history.qtpl:16 + StreamNavHTML(qw422016, rq, h.Name, "history") +//line views/history.qtpl:16 + qw422016.N().S(` +
    +
    +
    +

    Diff `) +//line views/history.qtpl:20 + qw422016.E().S(util.BeautifulName(h.Name)) +//line views/history.qtpl:20 + qw422016.N().S(` at `) +//line views/history.qtpl:20 + qw422016.E().S(hash) +//line views/history.qtpl:20 + qw422016.N().S(`

    +
    `)
    +//line views/history.qtpl:21
    +	qw422016.E().S(text)
    +//line views/history.qtpl:21
    +	qw422016.N().S(`
    +
    +
    +
    +`) +//line views/history.qtpl:25 +} + +//line views/history.qtpl:25 +func WritePrimitiveDiffHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) { +//line views/history.qtpl:25 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/history.qtpl:25 + StreamPrimitiveDiffHTML(qw422016, rq, h, u, hash) +//line views/history.qtpl:25 + qt422016.ReleaseWriter(qw422016) +//line views/history.qtpl:25 +} + +//line views/history.qtpl:25 +func PrimitiveDiffHTML(rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) string { +//line views/history.qtpl:25 + qb422016 := qt422016.AcquireByteBuffer() +//line views/history.qtpl:25 + WritePrimitiveDiffHTML(qb422016, rq, h, u, hash) +//line views/history.qtpl:25 + qs422016 := string(qb422016.B) +//line views/history.qtpl:25 + qt422016.ReleaseByteBuffer(qb422016) +//line views/history.qtpl:25 + return qs422016 +//line views/history.qtpl:25 +} + +//line views/history.qtpl:27 func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) { -//line views/history.qtpl:6 +//line views/history.qtpl:27 qw422016.N().S(`
    @@ -38,51 +112,51 @@ func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) { @@ -90,216 +164,216 @@ func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) {

    Subscribe via RSS, Atom or JSON feed.

    `) -//line views/history.qtpl:34 +//line views/history.qtpl:55 qw422016.N().S(` `) -//line views/history.qtpl:37 +//line views/history.qtpl:58 changes := history.RecentChanges(n) -//line views/history.qtpl:38 +//line views/history.qtpl:59 qw422016.N().S(`
    `) -//line views/history.qtpl:40 +//line views/history.qtpl:61 if len(changes) == 0 { -//line views/history.qtpl:40 +//line views/history.qtpl:61 qw422016.N().S(`

    Could not find any recent changes.

    `) -//line views/history.qtpl:42 +//line views/history.qtpl:63 } else { -//line views/history.qtpl:42 +//line views/history.qtpl:63 qw422016.N().S(` `) -//line views/history.qtpl:43 +//line views/history.qtpl:64 for i, entry := range changes { -//line views/history.qtpl:43 +//line views/history.qtpl:64 qw422016.N().S(`
      `) -//line views/history.qtpl:46 +//line views/history.qtpl:67 qw422016.N().S(recentChangesEntry(entry)) -//line views/history.qtpl:46 +//line views/history.qtpl:67 qw422016.N().S(`
    `) -//line views/history.qtpl:48 +//line views/history.qtpl:69 } -//line views/history.qtpl:48 +//line views/history.qtpl:69 qw422016.N().S(` `) -//line views/history.qtpl:49 +//line views/history.qtpl:70 } -//line views/history.qtpl:49 +//line views/history.qtpl:70 qw422016.N().S(`
    `) -//line views/history.qtpl:53 +//line views/history.qtpl:74 } -//line views/history.qtpl:53 +//line views/history.qtpl:74 func WriteRecentChangesHTML(qq422016 qtio422016.Writer, n int) { -//line views/history.qtpl:53 +//line views/history.qtpl:74 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:53 +//line views/history.qtpl:74 StreamRecentChangesHTML(qw422016, n) -//line views/history.qtpl:53 +//line views/history.qtpl:74 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:53 +//line views/history.qtpl:74 } -//line views/history.qtpl:53 +//line views/history.qtpl:74 func RecentChangesHTML(n int) string { -//line views/history.qtpl:53 +//line views/history.qtpl:74 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:53 +//line views/history.qtpl:74 WriteRecentChangesHTML(qb422016, n) -//line views/history.qtpl:53 +//line views/history.qtpl:74 qs422016 := string(qb422016.B) -//line views/history.qtpl:53 +//line views/history.qtpl:74 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:53 +//line views/history.qtpl:74 return qs422016 -//line views/history.qtpl:53 +//line views/history.qtpl:74 } -//line views/history.qtpl:55 +//line views/history.qtpl:76 func streamrecentChangesEntry(qw422016 *qt422016.Writer, rev history.Revision) { -//line views/history.qtpl:55 +//line views/history.qtpl:76 qw422016.N().S(`
  • `) -//line views/history.qtpl:57 +//line views/history.qtpl:78 qw422016.E().S(rev.Hash) -//line views/history.qtpl:57 +//line views/history.qtpl:78 qw422016.N().S(`
  • `) -//line views/history.qtpl:58 +//line views/history.qtpl:79 qw422016.N().S(rev.HyphaeLinksHTML()) -//line views/history.qtpl:58 +//line views/history.qtpl:79 qw422016.N().S(`
  • `) -//line views/history.qtpl:59 +//line views/history.qtpl:80 qw422016.E().S(rev.Message) -//line views/history.qtpl:59 +//line views/history.qtpl:80 qw422016.N().S(` `) -//line views/history.qtpl:59 +//line views/history.qtpl:80 if rev.Username != "anon" { -//line views/history.qtpl:59 +//line views/history.qtpl:80 qw422016.N().S(``) -//line views/history.qtpl:59 +//line views/history.qtpl:80 } -//line views/history.qtpl:59 +//line views/history.qtpl:80 qw422016.N().S(`
  • `) -//line views/history.qtpl:60 +//line views/history.qtpl:81 } -//line views/history.qtpl:60 +//line views/history.qtpl:81 func writerecentChangesEntry(qq422016 qtio422016.Writer, rev history.Revision) { -//line views/history.qtpl:60 +//line views/history.qtpl:81 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:60 +//line views/history.qtpl:81 streamrecentChangesEntry(qw422016, rev) -//line views/history.qtpl:60 +//line views/history.qtpl:81 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:60 +//line views/history.qtpl:81 } -//line views/history.qtpl:60 +//line views/history.qtpl:81 func recentChangesEntry(rev history.Revision) string { -//line views/history.qtpl:60 +//line views/history.qtpl:81 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:60 +//line views/history.qtpl:81 writerecentChangesEntry(qb422016, rev) -//line views/history.qtpl:60 +//line views/history.qtpl:81 qs422016 := string(qb422016.B) -//line views/history.qtpl:60 +//line views/history.qtpl:81 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:60 +//line views/history.qtpl:81 return qs422016 -//line views/history.qtpl:60 +//line views/history.qtpl:81 } -//line views/history.qtpl:62 +//line views/history.qtpl:83 func StreamHistoryHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, list string) { -//line views/history.qtpl:62 +//line views/history.qtpl:83 qw422016.N().S(` `) -//line views/history.qtpl:63 +//line views/history.qtpl:84 StreamNavHTML(qw422016, rq, hyphaName, "history") -//line views/history.qtpl:63 +//line views/history.qtpl:84 qw422016.N().S(`

    History of `) -//line views/history.qtpl:67 +//line views/history.qtpl:88 qw422016.E().S(util.BeautifulName(hyphaName)) -//line views/history.qtpl:67 +//line views/history.qtpl:88 qw422016.N().S(`

    `) -//line views/history.qtpl:68 +//line views/history.qtpl:89 qw422016.N().S(list) -//line views/history.qtpl:68 +//line views/history.qtpl:89 qw422016.N().S(`
    `) -//line views/history.qtpl:72 +//line views/history.qtpl:93 } -//line views/history.qtpl:72 +//line views/history.qtpl:93 func WriteHistoryHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, list string) { -//line views/history.qtpl:72 +//line views/history.qtpl:93 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:72 +//line views/history.qtpl:93 StreamHistoryHTML(qw422016, rq, hyphaName, list) -//line views/history.qtpl:72 +//line views/history.qtpl:93 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:72 +//line views/history.qtpl:93 } -//line views/history.qtpl:72 +//line views/history.qtpl:93 func HistoryHTML(rq *http.Request, hyphaName, list string) string { -//line views/history.qtpl:72 +//line views/history.qtpl:93 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:72 +//line views/history.qtpl:93 WriteHistoryHTML(qb422016, rq, hyphaName, list) -//line views/history.qtpl:72 +//line views/history.qtpl:93 qs422016 := string(qb422016.B) -//line views/history.qtpl:72 +//line views/history.qtpl:93 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:72 +//line views/history.qtpl:93 return qs422016 -//line views/history.qtpl:72 +//line views/history.qtpl:93 } From 140d97ddf4d6e775e43a9525a36b9192ae62adad Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 14 Mar 2021 20:10:08 +0500 Subject: [PATCH 15/18] Handle anchored links correctly --- link/link.go | 5 +++++ metarrhiza | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/link/link.go b/link/link.go index cde5c4b..d547df2 100644 --- a/link/link.go +++ b/link/link.go @@ -97,6 +97,11 @@ func From(address, display, hyphaName string) *Link { link.Display = strings.TrimSpace(display) } + if pos := strings.IndexRune(address, '#'); pos != -1 { + link.Anchor = address[pos:] + address = address[:pos] + } + switch { case strings.ContainsRune(address, ':'): pos := strings.IndexRune(address, ':') diff --git a/metarrhiza b/metarrhiza index e7040f3..133b268 160000 --- a/metarrhiza +++ b/metarrhiza @@ -1 +1 @@ -Subproject commit e7040f3e0dc41809063b77fcbc12fe33b234ea87 +Subproject commit 133b2689fbd67cad274f1c10fc6cbe8adbfc156a From 016aa83016b19ad0a247eead3c60e57748879aa1 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 14 Mar 2021 20:20:02 +0500 Subject: [PATCH 16/18] Fix a bug related to hypha creation --- hyphae/hyphae.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hyphae/hyphae.go b/hyphae/hyphae.go index 996b65f..aa9e991 100644 --- a/hyphae/hyphae.go +++ b/hyphae/hyphae.go @@ -45,6 +45,10 @@ func storeHypha(h *Hypha) { byNamesMutex.Lock() byNames[h.Name] = h byNamesMutex.Unlock() + + h.Lock() + h.Exists = true + h.Unlock() } // Insert inserts the hypha into the storage. A previous record is used if possible. Count incrementation is done if needed. @@ -101,6 +105,5 @@ func (h *Hypha) MergeIn(oh *Hypha) { } h.BinaryPath = oh.BinaryPath } - h.Exists = oh.Exists h.Unlock() } From bcb33f7048e911189eadf1ecf977bf429ddf83a6 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 14 Mar 2021 20:24:46 +0500 Subject: [PATCH 17/18] Delete the markup tests --- markup/img_test.go | 47 ---------------------------- markup/lexer_test.go | 67 ---------------------------------------- markup/paragraph_test.go | 50 ------------------------------ markup/xclusion_test.go | 22 ------------- 4 files changed, 186 deletions(-) delete mode 100644 markup/img_test.go delete mode 100644 markup/lexer_test.go delete mode 100644 markup/paragraph_test.go delete mode 100644 markup/xclusion_test.go diff --git a/markup/img_test.go b/markup/img_test.go deleted file mode 100644 index f2e2044..0000000 --- a/markup/img_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package markup - -import ( - "fmt" - "testing" -) - -func TestParseStartOfEntry(t *testing.T) { - img := ImgFromFirstLine("img {", "h") - tests := []struct { - line string - entry imgEntry - followedByDesc bool - }{ - {"apple", imgEntry{"/binary/apple", "", "", ""}, false}, - {"pear|", imgEntry{"/binary/pear", "", "", ""}, false}, - {"яблоко| 30*60", imgEntry{"/binary/яблоко", "30", "60", ""}, false}, - {"груша | 65 ", imgEntry{"/binary/груша", "65", "", ""}, false}, - {"жеронимо | 30 { full desc }", imgEntry{"/binary/жеронимо", "30", "", " full desc "}, false}, - {"жорно жованна | *5555 {partial description", imgEntry{"/binary/жорно_жованна", "", "5555", "partial description"}, true}, - {"иноске | {full}", imgEntry{"/binary/иноске", "", "", "full"}, false}, - {"j|{partial", imgEntry{"/binary/j", "", "", "partial"}, true}, - } - for _, triplet := range tests { - entry, followedByDesc := img.parseStartOfEntry(triplet.line) - if entry != triplet.entry || followedByDesc != triplet.followedByDesc { - t.Error(fmt.Sprintf("%q:%q != %q; %v != %v", triplet.line, entry, triplet.entry, followedByDesc, triplet.followedByDesc)) - } - } -} - -func TestParseDimensions(t *testing.T) { - tests := [][]string{ - {"500", "500", ""}, - {"3em", "3em", ""}, - {"500*", "500", ""}, - {"*500", "", "500"}, - {"800*520", "800", "520"}, - {"17%*5rem", "17%", "5rem"}, - } - for _, triplet := range tests { - sizeH, sizeV := parseDimensions(triplet[0]) - if sizeH != triplet[1] || sizeV != triplet[2] { - t.Error(sizeH, "*", sizeV, " != ", triplet[1], "*", triplet[2]) - } - } -} diff --git a/markup/lexer_test.go b/markup/lexer_test.go deleted file mode 100644 index b19bec2..0000000 --- a/markup/lexer_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package markup - -import ( - "fmt" - "io/ioutil" - "reflect" - "testing" -) - -// TODO: move test markup docs to files, perhaps? These strings sure are ugly -func TestLex(t *testing.T) { - check := func(name, content string, expectedAst []Line) { - if ast := lex(name, content); !reflect.DeepEqual(ast, expectedAst) { - if len(ast) != len(expectedAst) { - t.Error("Expected and generated AST length of", name, "do not match. Printed generated AST.") - for _, l := range ast { - fmt.Printf("%d: %s\n", l.id, l.contents) - } - return - } - for i, e := range ast { - if !reflect.DeepEqual(e, expectedAst[i]) { - t.Error(fmt.Sprintf("Expected: %q\nGot:%q", expectedAst[i], e)) - } - } - } - } - contentsB, err := ioutil.ReadFile("testdata/test.myco") - if err != nil { - t.Error("Could not read test markup file!") - } - contents := string(contentsB) - check("Apple", contents, []Line{ - {1, "

    1

    "}, - {2, "

    2

    "}, - {3, "

    3

    "}, - {4, "
    quote
    "}, - {5, `
      -
    • li 1
    • -
    • li 2
    • -
    `}, - {6, "

    text

    "}, - {7, "

    more text

    "}, - {8, `

    some link

    `}, - {9, `
      -
    • lin"+
    • -
    `}, - {10, `
    => preformatted text
    -where markup is not lexed
    `}, - {11, `

    linking

    `}, - {12, "

    text

    "}, - {13, `
    ()
    -/\
    `}, - {14, Transclusion{"apple", 1, 3}}, - {15, Img{ - hyphaName: "Apple", - inDesc: false, - entries: []imgEntry{ - {"/binary/hypha1", "", "", ""}, - {"/binary/hypha2", "", "", ""}, - {"/binary/hypha3", "60", "", ""}, - {"/binary/hypha4", "", "", " line1\nline2\n"}, - {"/binary/hypha5", "", "", "\nstate of minnesota\n"}, - }, - }}, - }) -} diff --git a/markup/paragraph_test.go b/markup/paragraph_test.go deleted file mode 100644 index 71bd5fc..0000000 --- a/markup/paragraph_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package markup - -import ( - "fmt" - "testing" -) - -/* -func TestGetTextNode(t *testing.T) { - tests := [][]string{ - // input textNode rest - {"barab", "barab", ""}, - {"test, ", "test", ", "}, - {"/test/", "", "/test/"}, - {"\\/test/", "/test", "/"}, - {"test \\/ar", "test /ar", ""}, - {"test //italian// test", "test ", "//italian// test"}, - } - for _, triplet := range tests { - a, b := getTextNode([]byte(triplet[0])) - if a != triplet[1] || string(b) != triplet[2] { - t.Error(fmt.Sprintf("Wanted: %q\nGot: %q %q", triplet, a, b)) - } - } -} -*/ - -func TestParagraphToHtml(t *testing.T) { - tests := [][]string{ - {"a simple paragraph", "a simple paragraph"}, - {"//italic//", "italic"}, - {"Embedded //italic//", "Embedded italic"}, - {"double //italian// //text//", "double italian text"}, - {"it has `mono`", "it has mono"}, - {"it has ~~strike~~", "it has strike"}, - {"this is a left **bold", "this is a left bold"}, - {"this line has a ,comma, two of them", "this line has a ,comma, two of them"}, - {"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."}, - {"A [[simple]] link", `A simple link`}, - } - for _, test := range tests { - if ParagraphToHtml("Apple", test[0]) != test[1] { - t.Error(fmt.Sprintf("%q: Wanted %q, got %q", test[0], test[1], ParagraphToHtml("Apple", test[0]))) - } - } -} - -func init() { - HyphaExists = func(_ string) bool { return true } -} diff --git a/markup/xclusion_test.go b/markup/xclusion_test.go deleted file mode 100644 index d61a2ad..0000000 --- a/markup/xclusion_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package markup - -import ( - "testing" -) - -func TestParseTransclusion(t *testing.T) { - check := func(line string, expectedXclusion Transclusion) { - if xcl := parseTransclusion(line, "t"); xcl != expectedXclusion { - t.Error(line, "; got:", xcl, "wanted:", expectedXclusion) - } - } - check("<= ", Transclusion{"", -9, -9}) - check("<=hypha", Transclusion{"hypha", 0, 0}) - check("<= hypha\t", Transclusion{"hypha", 0, 0}) - check("<= hypha :", Transclusion{"hypha", 0, 0}) - check("<= hypha : ..", Transclusion{"hypha", 0, 0}) - check("<= hypha : 3", Transclusion{"hypha", 3, 3}) - check("<= hypha : 3..", Transclusion{"hypha", 3, 0}) - check("<= hypha : ..3", Transclusion{"hypha", 0, 3}) - check("<= hypha : 3..4", Transclusion{"hypha", 3, 4}) -} From 215ce70c082b7babd0382ad65e1bec043977ac82 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sun, 14 Mar 2021 20:34:24 +0500 Subject: [PATCH 18/18] Write 1.0 version --- README.md | 26 +++++--------------------- views/stuff.qtpl | 2 +- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ac4de92..72405b7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 🍄 MycorrhizaWiki 0.14 +# 🍄 MycorrhizaWiki A wiki engine. [Main wiki](https://mycorrhiza.lesarbr.es) @@ -21,26 +21,10 @@ mycorrhiza [OPTIONS...] WIKI_PATH WIKI_PATH must be a path to git repository which you want to be a wiki. Options: - -auth-method string - What auth method to use. Variants: "none", "fixed" (default "none") - -fixed-credentials-path string - Used when -auth-method=fixed. Path to file with user credentials. (default "mycocredentials.json") - -gemini-cert-path string - Directory where you store Gemini certificates. Leave empty if you don't want to use Gemini. - -header-links-hypha string - Optional hypha that overrides the header links - -home string - The home page (default "home") - -icon string - What to show in the navititle in the beginning, before the colon (default "🍄") - -name string - What is the name of your wiki (default "wiki") - -port string - Port to serve the wiki at (default "1737") - -url string - URL at which your wiki can be found. Used to generate feeds (default "http://0.0.0.0:$port") - -user-hypha string - Hypha which is a superhypha of all user pages (default "u") + -config-path string + Path to a configuration file. Leave empty if you don't want to use it. + -print-example-config + If true, print an example configuration file contents and exit. You can save the output to a file and base your own configuration on it. ``` ## Features diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 96ee43e..f1ce50f 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -97,7 +97,7 @@ for u := range user.YieldUsers() {

    About {%s util.SiteName %}