From 7c1f38d5b0c06dab1f5230fb2ad3757090e391c1 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sat, 1 May 2021 21:26:21 +0500 Subject: [PATCH 01/41] Increment version --- README.md | 2 +- views/stuff.qtpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b13f99c..6cdca9b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 🍄 MycorrhizaWiki 1.1 +# 🍄 MycorrhizaWiki 1.2 A wiki engine. [Main wiki](https://mycorrhiza.lesarbr.es) diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 3f8e4ea..2aa9fbf 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -97,7 +97,7 @@ for u := range user.YieldUsers() {

About {%s util.SiteName %}

`) -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 } -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 func WriteToolbar(qq422016 qtio422016.Writer, u *user.User) { -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 StreamToolbar(qw422016, u) -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 qt422016.ReleaseWriter(qw422016) -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 } -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 func Toolbar(u *user.User) string { -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 qb422016 := qt422016.AcquireByteBuffer() -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 WriteToolbar(qb422016, u) -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 qs422016 := string(qb422016.B) -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 qt422016.ReleaseByteBuffer(qb422016) -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 return qs422016 -//line views/mutators.qtpl:66 +//line views/mutators.qtpl:67 } -//line views/mutators.qtpl:68 +//line views/mutators.qtpl:69 func StreamEditHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string) { -//line views/mutators.qtpl:68 +//line views/mutators.qtpl:69 qw422016.N().S(` `) -//line views/mutators.qtpl:69 +//line views/mutators.qtpl:70 qw422016.N().S(NavHTML(rq, hyphaName, "edit")) -//line views/mutators.qtpl:69 +//line views/mutators.qtpl:70 qw422016.N().S(`

Edit `) -//line views/mutators.qtpl:72 +//line views/mutators.qtpl:73 qw422016.E().S(util.BeautifulName(hyphaName)) -//line views/mutators.qtpl:72 +//line views/mutators.qtpl:73 qw422016.N().S(`

`) -//line views/mutators.qtpl:73 +//line views/mutators.qtpl:74 qw422016.N().S(warning) -//line views/mutators.qtpl:73 +//line views/mutators.qtpl:74 qw422016.N().S(`

Cancel
`) -//line views/mutators.qtpl:83 +//line views/mutators.qtpl:84 qw422016.N().S(Toolbar(user.FromRequest(rq))) -//line views/mutators.qtpl:83 +//line views/mutators.qtpl:84 qw422016.N().S(`
`) -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 } -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 func WriteEditHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string) { -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 StreamEditHTML(qw422016, rq, hyphaName, textAreaFill, warning) -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 qt422016.ReleaseWriter(qw422016) -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 } -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) string { -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 qb422016 := qt422016.AcquireByteBuffer() -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 WriteEditHTML(qb422016, rq, hyphaName, textAreaFill, warning) -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 qs422016 := string(qb422016.B) -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 qt422016.ReleaseByteBuffer(qb422016) -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 return qs422016 -//line views/mutators.qtpl:85 +//line views/mutators.qtpl:86 } -//line views/mutators.qtpl:87 +//line views/mutators.qtpl:88 func StreamPreviewHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) { -//line views/mutators.qtpl:87 +//line views/mutators.qtpl:88 qw422016.N().S(` `) -//line views/mutators.qtpl:88 +//line views/mutators.qtpl:89 qw422016.N().S(NavHTML(rq, hyphaName, "edit")) -//line views/mutators.qtpl:88 +//line views/mutators.qtpl:89 qw422016.N().S(`

Edit `) -//line views/mutators.qtpl:91 +//line views/mutators.qtpl:92 qw422016.E().S(util.BeautifulName(hyphaName)) -//line views/mutators.qtpl:91 +//line views/mutators.qtpl:92 qw422016.N().S(` (preview)

`) -//line views/mutators.qtpl:92 +//line views/mutators.qtpl:93 qw422016.N().S(warning) -//line views/mutators.qtpl:92 +//line views/mutators.qtpl:93 qw422016.N().S(`

Cancel

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

`) -//line views/mutators.qtpl:102 +//line views/mutators.qtpl:103 qw422016.N().S(renderedPage) -//line views/mutators.qtpl:102 +//line views/mutators.qtpl:103 qw422016.N().S(`
`) -//line views/mutators.qtpl:104 +//line views/mutators.qtpl:105 qw422016.N().S(Toolbar(user.FromRequest(rq))) -//line views/mutators.qtpl:104 +//line views/mutators.qtpl:105 qw422016.N().S(`
`) -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 } -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 func WritePreviewHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) { -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 StreamPreviewHTML(qw422016, rq, hyphaName, textAreaFill, warning, renderedPage) -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 qt422016.ReleaseWriter(qw422016) -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 } -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 func PreviewHTML(rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) string { -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 qb422016 := qt422016.AcquireByteBuffer() -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 WritePreviewHTML(qb422016, rq, hyphaName, textAreaFill, warning, renderedPage) -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 qs422016 := string(qb422016.B) -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 qt422016.ReleaseByteBuffer(qb422016) -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 return qs422016 -//line views/mutators.qtpl:106 +//line views/mutators.qtpl:107 } From 01f7791d4aa82a2ee1b5bde4c79aa39ac5857d74 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sun, 9 May 2021 13:34:14 +0500 Subject: [PATCH 05/41] Do not redirect from / to /hypha/home --- .github/workflows/codeql-analysis.yml | 71 +++++++++++++++++++++++++++ main.go | 5 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..27b588f --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,71 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '21 18 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go', 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled languagehttps://github.com/bouncepaw/mycorrhiza/commit/c7ab41a3b0bb21575dd5e896116f3b193b57165a + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/main.go b/main.go index 295c974..f029695 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "log" "math/rand" "net/http" + "net/url" "os" "strings" @@ -224,7 +225,9 @@ func main() { http.HandleFunc("/static/icon/", handlerIcon) http.HandleFunc("/robots.txt", handlerRobotsTxt) http.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) { - http.Redirect(w, rq, "/hypha/"+util.HomePage, http.StatusSeeOther) + addr, _ := url.Parse("/hypha/" + util.HomePage) // Let's pray it never fails + rq.URL = addr + handlerHypha(w, rq) }) log.Fatal(http.ListenAndServe("0.0.0.0:"+util.ServerPort, nil)) } From e5107252d1800498e2fa005f1691b46ec21f0ad8 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sun, 9 May 2021 14:00:21 +0500 Subject: [PATCH 06/41] Be more reasonable with trailing slashes --- http_admin.go | 6 +++--- http_auth.go | 6 +++--- http_history.go | 6 +++--- http_mutators.go | 10 +++++----- http_readers.go | 12 ++++++------ main.go | 29 +++++++++++++++++------------ name.go | 3 ++- 7 files changed, 39 insertions(+), 33 deletions(-) diff --git a/http_admin.go b/http_admin.go index 2b95e22..286d5af 100644 --- a/http_admin.go +++ b/http_admin.go @@ -19,7 +19,7 @@ func initAdmin() { } func handlerAdmin(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) if user.CanProceed(rq, "admin") { w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) @@ -28,14 +28,14 @@ func handlerAdmin(w http.ResponseWriter, rq *http.Request) { } func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" { log.Fatal("An admin commanded the wiki to shutdown") } } func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) if user.CanProceed(rq, "admin") && rq.Method == "POST" { user.ReadUsersFromFilesystem() http.Redirect(w, rq, "/hypha/"+util.UserHypha, http.StatusSeeOther) diff --git a/http_auth.go b/http_auth.go index b248b62..4028495 100644 --- a/http_auth.go +++ b/http_auth.go @@ -19,7 +19,7 @@ func init() { } func handlerRegister(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) if !util.UseRegistration { w.WriteHeader(http.StatusForbidden) } @@ -69,7 +69,7 @@ func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) { } func handlerLoginData(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( username = util.CanonicalName(rq.PostFormValue("username")) password = rq.PostFormValue("password") @@ -83,7 +83,7 @@ func handlerLoginData(w http.ResponseWriter, rq *http.Request) { } func handlerLogin(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) w.Header().Set("Content-Type", "text/html;charset=utf-8") if user.AuthUsed { w.WriteHeader(http.StatusOK) diff --git a/http_history.go b/http_history.go index 110ca3a..e65e84b 100644 --- a/http_history.go +++ b/http_history.go @@ -23,7 +23,7 @@ func init() { // handlerHistory lists all revisions of a hypha func handlerHistory(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) hyphaName := HyphaNameFromRq(rq, "history") var list string @@ -40,7 +40,7 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) { // Recent changes func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( noPrefix = strings.TrimPrefix(rq.URL.String(), "/recent-changes/") n, err = strconv.Atoi(noPrefix) @@ -53,7 +53,7 @@ func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { } func genericHandlerOfFeeds(w http.ResponseWriter, rq *http.Request, f func() (string, error), name string) { - log.Println(rq.URL) + prepareRq(rq) if content, err := f(); err != nil { w.Header().Set("Content-Type", "text/plain;charset=utf-8") w.WriteHeader(http.StatusInternalServerError) diff --git a/http_mutators.go b/http_mutators.go index 5835420..a3d98aa 100644 --- a/http_mutators.go +++ b/http_mutators.go @@ -35,7 +35,7 @@ func factoryHandlerAsker( succPageTemplate func(*http.Request, string, bool) string, ) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( hyphaName = HyphaNameFromRq(rq, actionPath) h = hyphae.ByName(hyphaName) @@ -85,7 +85,7 @@ func factoryHandlerConfirmer( confirmer func(*hyphae.Hypha, *user.User, *http.Request) (*history.HistoryOp, string), ) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( hyphaName = HyphaNameFromRq(rq, actionPath) h = hyphae.ByName(hyphaName) @@ -129,7 +129,7 @@ var handlerRenameConfirm = factoryHandlerConfirmer( // handlerEdit shows the edit form. It doesn't edit anything actually. func handlerEdit(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( hyphaName = HyphaNameFromRq(rq, "edit") h = hyphae.ByName(hyphaName) @@ -166,7 +166,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { // handlerUploadText uploads a new text part for the hypha. func handlerUploadText(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( hyphaName = HyphaNameFromRq(rq, "upload-text") h = hyphae.ByName(hyphaName) @@ -206,7 +206,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { // handlerUploadBinary uploads a new binary part for the hypha. func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) rq.ParseMultipartForm(10 << 20) // Set upload limit var ( hyphaName = HyphaNameFromRq(rq, "upload-binary") diff --git a/http_readers.go b/http_readers.go index 597d8b8..0d8e492 100644 --- a/http_readers.go +++ b/http_readers.go @@ -29,7 +29,7 @@ func init() { } func handlerAttachment(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( hyphaName = HyphaNameFromRq(rq, "attachment") h = hyphae.ByName(hyphaName) @@ -43,7 +43,7 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) { } func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( shorterUrl = strings.TrimPrefix(rq.URL.Path, "/primitive-diff/") firstSlashIndex = strings.IndexRune(shorterUrl, '/') @@ -61,7 +61,7 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { // handlerRevision displays a specific revision of text part a page func handlerRevision(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( shorterUrl = strings.TrimPrefix(rq.URL.Path, "/rev/") firstSlashIndex = strings.IndexRune(shorterUrl, '/') @@ -88,7 +88,7 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { // handlerText serves raw source text of the hypha. func handlerText(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) hyphaName := HyphaNameFromRq(rq, "text") if h := hyphae.ByName(hyphaName); h.Exists { log.Println("Serving", h.TextPath) @@ -99,7 +99,7 @@ func handlerText(w http.ResponseWriter, rq *http.Request) { // handlerBinary serves binary part of the hypha. func handlerBinary(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) hyphaName := HyphaNameFromRq(rq, "binary") if h := hyphae.ByName(hyphaName); h.Exists { log.Println("Serving", h.BinaryPath) @@ -110,7 +110,7 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) { // handlerHypha is the main hypha action that displays the hypha and the binary upload form along with some navigation. func handlerHypha(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) var ( hyphaName = HyphaNameFromRq(rq, "page", "hypha") h = hyphae.ByName(hyphaName) diff --git a/main.go b/main.go index f029695..f0cd142 100644 --- a/main.go +++ b/main.go @@ -48,7 +48,7 @@ func HttpErr(w http.ResponseWriter, status int, name, title, errMsg string) { // Show all hyphae func handlerList(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) util.HTTP200Page(w, base("List of pages", views.HyphaListHTML(), user.FromRequest(rq))) } @@ -57,7 +57,7 @@ var base = views.BaseHTML // Reindex all hyphae by checking the wiki storage directory anew. func handlerReindex(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) if ok := user.CanProceed(rq, "reindex"); !ok { HttpErr(w, http.StatusForbidden, util.HomePage, "Not enough rights", "You must be an admin to reindex hyphae.") log.Println("Rejected", rq.URL) @@ -75,7 +75,7 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) { // Update header links by reading the configured hypha, if there is any, or resorting to default values. func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) if ok := user.CanProceed(rq, "update-header-links"); !ok { HttpErr(w, http.StatusForbidden, util.HomePage, "Not enough rights", "You must be a moderator to update header links.") log.Println("Rejected", rq.URL) @@ -87,7 +87,7 @@ 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) + prepareRq(rq) var ( randomHyphaName string amountOfHyphae int = hyphae.Count() @@ -108,7 +108,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) { } func handlerStyle(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) if _, err := os.Stat(util.WikiDir + "/static/common.css"); err == nil { http.ServeFile(w, rq, util.WikiDir+"/static/common.css") } else { @@ -121,7 +121,7 @@ func handlerStyle(w http.ResponseWriter, rq *http.Request) { } func handlerToolbar(w http.ResponseWriter, rq *http.Request) { - log.Println(rq.URL) + prepareRq(rq) w.Header().Set("Content-Type", "text/javascript;charset=utf-8") w.Write([]byte(assets.ToolbarJS())) } @@ -178,6 +178,11 @@ Disallow: / Crawl-delay: 5`)) } +func prepareRq(rq *http.Request) { + log.Println(rq.RequestURI) + rq.URL.Path = strings.TrimSuffix(rq.URL.Path, "/") +} + func main() { parseCliArgs() @@ -210,12 +215,12 @@ func main() { // See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/ // See http_auth.go for /login, /login-data, /logout, /logout-confirm // See http_history.go for /history/, /recent-changes - http.HandleFunc("/list", handlerList) - http.HandleFunc("/reindex", handlerReindex) - http.HandleFunc("/update-header-links", handlerUpdateHeaderLinks) - http.HandleFunc("/random", handlerRandom) - http.HandleFunc("/about", handlerAbout) - http.HandleFunc("/user-list", handlerUserList) + http.HandleFunc("/list/", handlerList) + http.HandleFunc("/reindex/", handlerReindex) + http.HandleFunc("/update-header-links/", handlerUpdateHeaderLinks) + http.HandleFunc("/random/", handlerRandom) + http.HandleFunc("/about/", handlerAbout) + http.HandleFunc("/user-list/", handlerUserList) http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(WikiDir+"/static")))) http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { http.ServeFile(w, rq, WikiDir+"/static/favicon.ico") diff --git a/name.go b/name.go index 7da76ba..59bd9fc 100644 --- a/name.go +++ b/name.go @@ -18,7 +18,8 @@ func HyphaNameFromRq(rq *http.Request, actions ...string) string { return util.CanonicalName(strings.TrimPrefix(p, "/"+action+"/")) } } - panic("HyphaNameFromRq: no matching action passed") + log.Println("HyphaNameFromRq: this request is invalid, fallback to home hypha") + return util.HomePage } // geminiHyphaNameFromRq extracts hypha name from gemini request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". From 9bf5e8e47136c11d94b451fbaff38b33ba92ad44 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sun, 9 May 2021 14:18:21 +0500 Subject: [PATCH 07/41] Move some web stuff to http_stuff.go --- http_stuff.go | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 71 ++-------------------------------------- 2 files changed, 93 insertions(+), 69 deletions(-) create mode 100644 http_stuff.go diff --git a/http_stuff.go b/http_stuff.go new file mode 100644 index 0000000..5ca70d4 --- /dev/null +++ b/http_stuff.go @@ -0,0 +1,91 @@ +// http_stuff.go is used for meta stuff about the wiki or all hyphae at once. +package main + +import ( + "io" + "log" + "math/rand" + "net/http" + + "github.com/bouncepaw/mycorrhiza/hyphae" + "github.com/bouncepaw/mycorrhiza/shroom" + "github.com/bouncepaw/mycorrhiza/user" + "github.com/bouncepaw/mycorrhiza/util" + "github.com/bouncepaw/mycorrhiza/views" +) + +func init() { + http.HandleFunc("/list/", handlerList) + http.HandleFunc("/reindex/", handlerReindex) + http.HandleFunc("/update-header-links/", handlerUpdateHeaderLinks) + http.HandleFunc("/random/", handlerRandom) + http.HandleFunc("/about/", handlerAbout) +} + +// handlerList shows a list of all hyphae in the wiki in random order. +func handlerList(w http.ResponseWriter, rq *http.Request) { + prepareRq(rq) + util.HTTP200Page(w, base("List of pages", views.HyphaListHTML(), user.FromRequest(rq))) +} + +// handlerReindex reindexes all hyphae by checking the wiki storage directory anew. +func handlerReindex(w http.ResponseWriter, rq *http.Request) { + prepareRq(rq) + if ok := user.CanProceed(rq, "reindex"); !ok { + HttpErr(w, http.StatusForbidden, util.HomePage, "Not enough rights", "You must be an admin to reindex hyphae.") + log.Println("Rejected", rq.URL) + return + } + hyphae.ResetCount() + log.Println("Wiki storage directory is", WikiDir) + log.Println("Start indexing hyphae...") + hyphae.Index(WikiDir) + log.Println("Indexed", hyphae.Count(), "hyphae") + http.Redirect(w, rq, "/", http.StatusSeeOther) +} + +// handlerUpdateHeaderLinks updates header links by reading the configured hypha, if there is any, or resorting to default values. +// +// See https://mycorrhiza.lesarbr.es/hypha/configuration/header +func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { + prepareRq(rq) + if ok := user.CanProceed(rq, "update-header-links"); !ok { + HttpErr(w, http.StatusForbidden, util.HomePage, "Not enough rights", "You must be a moderator to update header links.") + log.Println("Rejected", rq.URL) + return + } + shroom.SetHeaderLinks() + http.Redirect(w, rq, "/", http.StatusSeeOther) +} + +// handlerRandom redirects to a random hypha. +func handlerRandom(w http.ResponseWriter, rq *http.Request) { + prepareRq(rq) + var ( + randomHyphaName string + amountOfHyphae = hyphae.Count() + ) + if amountOfHyphae == 0 { + HttpErr(w, http.StatusNotFound, util.HomePage, "There are no hyphae", + "It is impossible 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 + } + i-- + } + http.Redirect(w, rq, "/hypha/"+randomHyphaName, http.StatusSeeOther) +} + +// handlerAbout shows a summary of wiki's software. +func handlerAbout(w http.ResponseWriter, rq *http.Request) { + w.Header().Set("Content-Type", "text/html;charset=utf-8") + w.WriteHeader(http.StatusOK) + _, err := io.WriteString(w, base("About "+util.SiteName, views.AboutHTML(), user.FromRequest(rq))) + if err != nil { + log.Println(err) + } +} diff --git a/main.go b/main.go index f0cd142..d358c39 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ import ( "fmt" "io/ioutil" "log" - "math/rand" "net/http" "net/url" "os" @@ -46,67 +45,11 @@ func HttpErr(w http.ResponseWriter, status int, name, title, errMsg string) { ) } -// Show all hyphae -func handlerList(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - util.HTTP200Page(w, base("List of pages", views.HyphaListHTML(), user.FromRequest(rq))) -} - // This part is present in all html documents. var base = views.BaseHTML -// Reindex all hyphae by checking the wiki storage directory anew. -func handlerReindex(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - if ok := user.CanProceed(rq, "reindex"); !ok { - HttpErr(w, http.StatusForbidden, util.HomePage, "Not enough rights", "You must be an admin to reindex hyphae.") - log.Println("Rejected", rq.URL) - return - } - hyphae.ResetCount() - log.Println("Wiki storage directory is", WikiDir) - log.Println("Start indexing hyphae...") - hyphae.Index(WikiDir) - log.Println("Indexed", hyphae.Count(), "hyphae") - http.Redirect(w, rq, "/", http.StatusSeeOther) -} - // Stop the wiki -// Update header links by reading the configured hypha, if there is any, or resorting to default values. -func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - if ok := user.CanProceed(rq, "update-header-links"); !ok { - HttpErr(w, http.StatusForbidden, util.HomePage, "Not enough rights", "You must be a moderator to update header links.") - log.Println("Rejected", rq.URL) - return - } - shroom.SetHeaderLinks() - http.Redirect(w, rq, "/", http.StatusSeeOther) -} - -// Redirect to a random hypha. -func handlerRandom(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - 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 - } - i-- - } - http.Redirect(w, rq, "/hypha/"+randomHyphaName, http.StatusSeeOther) -} - func handlerStyle(w http.ResponseWriter, rq *http.Request) { prepareRq(rq) if _, err := os.Stat(util.WikiDir + "/static/common.css"); err == nil { @@ -155,12 +98,6 @@ func handlerIcon(w http.ResponseWriter, rq *http.Request) { } } -func handlerAbout(w http.ResponseWriter, rq *http.Request) { - w.Header().Set("Content-Type", "text/html;charset=utf-8") - w.WriteHeader(http.StatusOK) - w.Write([]byte(base("About "+util.SiteName, views.AboutHTML(), user.FromRequest(rq)))) -} - func handlerUserList(w http.ResponseWriter, rq *http.Request) { w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) @@ -214,13 +151,9 @@ func main() { // See http_readers.go for /page/, /hypha/, /text/, /binary/, /attachment/ // See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/ // See http_auth.go for /login, /login-data, /logout, /logout-confirm - // See http_history.go for /history/, /recent-changes - http.HandleFunc("/list/", handlerList) - http.HandleFunc("/reindex/", handlerReindex) - http.HandleFunc("/update-header-links/", handlerUpdateHeaderLinks) - http.HandleFunc("/random/", handlerRandom) - http.HandleFunc("/about/", handlerAbout) http.HandleFunc("/user-list/", handlerUserList) + // See http_history.go for /history/, /recent-changes + // See http_stuff.go for list, reindex, update-header-links, random, about http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(WikiDir+"/static")))) http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { http.ServeFile(w, rq, WikiDir+"/static/favicon.ico") From 662794dd590aee070394cb58fdfff2ea87e12b16 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sun, 9 May 2021 14:36:39 +0500 Subject: [PATCH 08/41] Move config-related stuff to its own module --- {util => cfg}/config.go | 44 ++++- files/files.go | 8 +- flag.go | 15 +- gemini.go | 8 +- history/history.go | 5 +- history/information.go | 10 +- http_admin.go | 4 +- http_auth.go | 3 +- http_stuff.go | 9 +- main.go | 14 +- markup/mycomarkup.go | 8 +- name.go | 3 +- shroom/init.go | 6 +- shroom/upload.go | 4 +- shroom/view.go | 3 +- user/files.go | 10 +- user/net.go | 5 +- util/header_links.go | 5 +- util/util.go | 32 +--- views/auth.qtpl | 10 +- views/auth.qtpl.go | 10 +- views/history.qtpl | 3 +- views/history.qtpl.go | 279 +++++++++++++++---------------- views/hypha.qtpl | 5 +- views/hypha.qtpl.go | 173 ++++++++++---------- views/nav.qtpl | 4 +- views/nav.qtpl.go | 6 +- views/stuff.qtpl | 13 +- views/stuff.qtpl.go | 355 ++++++++++++++++++++-------------------- 29 files changed, 540 insertions(+), 514 deletions(-) rename {util => cfg}/config.go (58%) diff --git a/util/config.go b/cfg/config.go similarity index 58% rename from util/config.go rename to cfg/config.go index 6b1212e..09f4088 100644 --- a/util/config.go +++ b/cfg/config.go @@ -1,4 +1,4 @@ -package util +package cfg import ( "log" @@ -8,7 +8,31 @@ import ( "github.com/go-ini/ini" ) -// See https://mycorrhiza.lesarbr.es/hypha/configuration/fields +var ( + WikiName string + NaviTitleIcon string + + HomeHypha string + UserHypha string + HeaderLinksHypha string + + HTTPPort string + URL string + GeminiCertificatePath string + + WikiDir string + ConfigFilePath string + + UseFixedAuth bool + FixedAuthCredentialsPath string + UseRegistration bool + RegistrationCredentialsPath string + LimitRegistration int +) + +// Config represents a Mycorrhiza wiki configuration file. +// +// See https://mycorrhiza.lesarbr.es/hypha/configuration/fields for fields' docs. type Config struct { WikiName string NaviTitleIcon string @@ -17,18 +41,21 @@ type Config struct { Authorization } +// Hyphae is a section of Config which has fields related to special hyphae. type Hyphae struct { HomeHypha string UserHypha string HeaderLinksHypha string } +// Network is a section of Config that has fields related to network stuff: HTTP and Gemini. type Network struct { HTTPPort uint64 URL string GeminiCertificatePath string } +// Authorization is a section of Config that has fields related to authorization and authentication. type Authorization struct { UseFixedAuth bool FixedAuthCredentialsPath string @@ -38,6 +65,7 @@ type Authorization struct { LimitRegistration uint64 } +// ReadConfigFile reads a config on the given path and stores the configuration. func ReadConfigFile(path string) { cfg := &Config{ WikiName: "MycorrhizaWiki", @@ -76,16 +104,16 @@ func ReadConfigFile(path string) { } // Map the struct to the global variables - SiteName = cfg.WikiName - SiteNavIcon = cfg.NaviTitleIcon - HomePage = cfg.HomeHypha + WikiName = cfg.WikiName + NaviTitleIcon = cfg.NaviTitleIcon + HomeHypha = cfg.HomeHypha UserHypha = cfg.UserHypha HeaderLinksHypha = cfg.HeaderLinksHypha - ServerPort = strconv.FormatUint(cfg.HTTPPort, 10) + HTTPPort = strconv.FormatUint(cfg.HTTPPort, 10) URL = cfg.URL - GeminiCertPath = cfg.GeminiCertificatePath + GeminiCertificatePath = cfg.GeminiCertificatePath UseFixedAuth = cfg.UseFixedAuth - FixedCredentialsPath = cfg.FixedAuthCredentialsPath + FixedAuthCredentialsPath = cfg.FixedAuthCredentialsPath UseRegistration = cfg.UseRegistration RegistrationCredentialsPath = cfg.RegistrationCredentialsPath LimitRegistration = int(cfg.LimitRegistration) diff --git a/files/files.go b/files/files.go index 5f03a10..634cc16 100644 --- a/files/files.go +++ b/files/files.go @@ -3,11 +3,11 @@ package files import ( "errors" "fmt" + "github.com/bouncepaw/mycorrhiza/cfg" "path/filepath" "strings" "github.com/adrg/xdg" - "github.com/bouncepaw/mycorrhiza/util" "github.com/mitchellh/go-homedir" ) @@ -49,7 +49,7 @@ func tokenStoragePath() (string, error) { if err != nil { return "", err } - if strings.HasPrefix(dir, util.WikiDir) { + if strings.HasPrefix(dir, cfg.WikiDir) { return "", errors.New("wiki storage directory includes private config files") } return dir, nil @@ -57,7 +57,7 @@ func tokenStoragePath() (string, error) { func registrationCredentialsPath() (string, error) { var err error - path := util.RegistrationCredentialsPath + path := cfg.RegistrationCredentialsPath if len(path) == 0 { path, err = xdg.DataFile("mycorrhiza/registration.json") @@ -81,7 +81,7 @@ func registrationCredentialsPath() (string, error) { func fixedCredentialsPath() (string, error) { var err error - path := util.FixedCredentialsPath + path := cfg.FixedAuthCredentialsPath if len(path) > 0 { path, err = homedir.Expand(path) diff --git a/flag.go b/flag.go index 6cb3fef..35bb9da 100644 --- a/flag.go +++ b/flag.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "github.com/bouncepaw/mycorrhiza/cfg" "log" "os" "path/filepath" @@ -14,7 +15,7 @@ import ( var printExampleConfig bool func init() { - flag.StringVar(&util.ConfigFilePath, "config-path", "", "Path to a configuration file. Leave empty if you don't want to use it.") + flag.StringVar(&cfg.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( @@ -42,16 +43,16 @@ func parseCliArgs() { var err error WikiDir, err = filepath.Abs(args[0]) - util.WikiDir = WikiDir + cfg.WikiDir = WikiDir if err != nil { log.Fatal(err) } - if util.URL == "" { - util.URL = "http://0.0.0.0:" + util.ServerPort + if cfg.URL == "" { + cfg.URL = "http://0.0.0.0:" + cfg.HTTPPort } - util.HomePage = util.CanonicalName(util.HomePage) - util.UserHypha = util.CanonicalName(util.UserHypha) - util.HeaderLinksHypha = util.CanonicalName(util.HeaderLinksHypha) + cfg.HomeHypha = util.CanonicalName(cfg.HomeHypha) + cfg.UserHypha = util.CanonicalName(cfg.UserHypha) + cfg.HeaderLinksHypha = util.CanonicalName(cfg.HeaderLinksHypha) } diff --git a/gemini.go b/gemini.go index b86c3a4..050edc1 100644 --- a/gemini.go +++ b/gemini.go @@ -3,6 +3,7 @@ package main import ( "crypto/tls" "crypto/x509/pkix" + "github.com/bouncepaw/mycorrhiza/cfg" "io/ioutil" "log" "path/filepath" @@ -13,7 +14,6 @@ import ( "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/markup" - "github.com/bouncepaw/mycorrhiza/util" ) func geminiHomeHypha(w *gemini.ResponseWriter, rq *gemini.Request) { @@ -23,7 +23,7 @@ func geminiHomeHypha(w *gemini.ResponseWriter, rq *gemini.Request) { You have successfully served the wiki through Gemini. Currently, support is really work-in-progress; you should resort to using Mycorrhiza through the web protocols. Visit home hypha: -=> /hypha/` + util.HomePage)) +=> /hypha/` + cfg.HomeHypha)) } func geminiHypha(w *gemini.ResponseWriter, rq *gemini.Request) { @@ -48,10 +48,10 @@ func geminiHypha(w *gemini.ResponseWriter, rq *gemini.Request) { } func handleGemini() { - if util.GeminiCertPath == "" { + if cfg.GeminiCertificatePath == "" { return } - certPath, err := filepath.Abs(util.GeminiCertPath) + certPath, err := filepath.Abs(cfg.GeminiCertificatePath) if err != nil { log.Fatal(err) } diff --git a/history/history.go b/history/history.go index dd53203..b94ee51 100644 --- a/history/history.go +++ b/history/history.go @@ -3,6 +3,7 @@ package history import ( "bytes" "fmt" + "github.com/bouncepaw/mycorrhiza/cfg" "html" "log" "os/exec" @@ -167,7 +168,7 @@ func (rev *Revision) bestLink() string { func gitsh(args ...string) (out bytes.Buffer, err error) { fmt.Printf("$ %v\n", args) cmd := exec.Command(gitpath, args...) - cmd.Dir = util.WikiDir + cmd.Dir = cfg.WikiDir b, err := cmd.CombinedOutput() if err != nil { @@ -179,7 +180,7 @@ func gitsh(args ...string) (out bytes.Buffer, err error) { // silentGitsh is like gitsh, except it writes less to the stdout. func silentGitsh(args ...string) (out bytes.Buffer, err error) { cmd := exec.Command(gitpath, args...) - cmd.Dir = util.WikiDir + cmd.Dir = cfg.WikiDir b, err := cmd.CombinedOutput() return *bytes.NewBuffer(b), err diff --git a/history/information.go b/history/information.go index 75b7501..0570e6e 100644 --- a/history/information.go +++ b/history/information.go @@ -4,20 +4,20 @@ package history import ( "fmt" + "github.com/bouncepaw/mycorrhiza/cfg" "log" "regexp" "strconv" "strings" "time" - "github.com/bouncepaw/mycorrhiza/util" "github.com/gorilla/feeds" ) func recentChangesFeed() *feeds.Feed { feed := &feeds.Feed{ Title: "Recent changes", - Link: &feeds.Link{Href: util.URL}, + Link: &feeds.Link{Href: cfg.URL}, Description: "List of 30 recent changes on the wiki", Author: &feeds.Author{Name: "Wikimind", Email: "wikimind@mycorrhiza"}, Updated: time.Now(), @@ -44,7 +44,7 @@ func recentChangesFeed() *feeds.Feed { Description: rev.descriptionForFeed(), Created: rev.Time, Updated: rev.Time, - Link: &feeds.Link{Href: util.URL + rev.bestLink()}, + Link: &feeds.Link{Href: cfg.URL + rev.bestLink()}, }) } return feed @@ -141,7 +141,7 @@ func (rev *Revision) asHistoryEntry(hyphaName string) (html string) { author := "" if rev.Username != "anon" { author = fmt.Sprintf(` -
  • - {% elseif util.UseFixedAuth %} + {% elseif cfg.UseFixedAuth %}

    Administrators have forbidden registration for this wiki. Administrators can make an account for you by hand; contact them.

    ← Go back

    {% else %} @@ -43,7 +43,7 @@ {% if user.AuthUsed %}
  • {% endif %} diff --git a/views/nav.qtpl.go b/views/nav.qtpl.go index c3b14ec..2cbdcce 100644 --- a/views/nav.qtpl.go +++ b/views/nav.qtpl.go @@ -11,10 +11,10 @@ import "net/http" import "strings" //line views/nav.qtpl:3 -import "github.com/bouncepaw/mycorrhiza/user" +import "github.com/bouncepaw/mycorrhiza/cfg" //line views/nav.qtpl:4 -import "github.com/bouncepaw/mycorrhiza/util" +import "github.com/bouncepaw/mycorrhiza/user" // This is the -

    Subscribe via RSS, Atom or JSON feed.

    +

    Subscribe via RSS, Atom or JSON feed.

    {% comment %} Here I am, willing to add some accessibility using ARIA. Turns out, diff --git a/views/history.qtpl.go b/views/history.qtpl.go index 262db7d..0a0462b 100644 --- a/views/history.qtpl.go +++ b/views/history.qtpl.go @@ -163,7 +163,7 @@ func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) { recent changes -

    Subscribe via RSS, Atom or JSON feed.

    +

    Subscribe via RSS, Atom or JSON feed.

    `) //line views/history.qtpl:55 From 5b4ff5ef68b29192191b0bd1af1e1ad986f0b369 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sun, 9 May 2021 15:42:12 +0500 Subject: [PATCH 10/41] Move all web-related stuff to a new module --- flag.go | 5 +- http_admin.go | 43 ------- main.go | 142 ++--------------------- name.go | 14 --- util/util.go | 18 +++ web/http_admin.go | 44 +++++++ http_auth.go => web/http_auth.go | 16 +-- http_history.go => web/http_history.go | 14 +-- http_mutators.go => web/http_mutators.go | 28 ++--- http_readers.go => web/http_readers.go | 24 ++-- http_stuff.go => web/http_stuff.go | 18 +-- web/web.go | 127 ++++++++++++++++++++ 12 files changed, 250 insertions(+), 243 deletions(-) delete mode 100644 http_admin.go create mode 100644 web/http_admin.go rename http_auth.go => web/http_auth.go (86%) rename http_history.go => web/http_history.go (86%) rename http_mutators.go => web/http_mutators.go (93%) rename http_readers.go => web/http_readers.go (90%) rename http_stuff.go => web/http_stuff.go (87%) create mode 100644 web/web.go diff --git a/flag.go b/flag.go index 35bb9da..d801d3d 100644 --- a/flag.go +++ b/flag.go @@ -41,9 +41,8 @@ func parseCliArgs() { log.Fatal("Error: pass a wiki directory") } - var err error - WikiDir, err = filepath.Abs(args[0]) - cfg.WikiDir = WikiDir + wikiDir, err := filepath.Abs(args[0]) + cfg.WikiDir = wikiDir if err != nil { log.Fatal(err) } diff --git a/http_admin.go b/http_admin.go deleted file mode 100644 index d4d1612..0000000 --- a/http_admin.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "github.com/bouncepaw/mycorrhiza/cfg" - "log" - "net/http" - - "github.com/bouncepaw/mycorrhiza/user" - "github.com/bouncepaw/mycorrhiza/views" -) - -// This is not init(), because user.AuthUsed is not set at init-stage. -func initAdmin() { - if user.AuthUsed { - http.HandleFunc("/admin", handlerAdmin) - http.HandleFunc("/admin/shutdown", handlerAdminShutdown) - http.HandleFunc("/admin/reindex-users", handlerAdminReindexUsers) - } -} - -func handlerAdmin(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - if user.CanProceed(rq, "admin") { - w.Header().Set("Content-Type", "text/html;charset=utf-8") - w.WriteHeader(http.StatusOK) - w.Write([]byte(base("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq)))) - } -} - -func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" { - log.Fatal("An admin commanded the wiki to shutdown") - } -} - -func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - if user.CanProceed(rq, "admin") && rq.Method == "POST" { - user.ReadUsersFromFilesystem() - http.Redirect(w, rq, "/hypha/"+cfg.UserHypha, http.StatusSeeOther) - } -} diff --git a/main.go b/main.go index 3d5d722..da0d6e6 100644 --- a/main.go +++ b/main.go @@ -5,121 +5,18 @@ package main import ( - "fmt" "github.com/bouncepaw/mycorrhiza/cfg" - "io" - "io/ioutil" - "log" - "net/http" - "net/url" - "os" - "strings" - - "github.com/bouncepaw/mycorrhiza/assets" "github.com/bouncepaw/mycorrhiza/files" "github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/shroom" "github.com/bouncepaw/mycorrhiza/user" - "github.com/bouncepaw/mycorrhiza/views" + "github.com/bouncepaw/mycorrhiza/web" + "log" + "net/http" + "os" ) -// WikiDir is a rooted path to the wiki storage directory. -var WikiDir string - -// HttpErr is used by many handlers to signal errors in a compact way. -func HttpErr(w http.ResponseWriter, status int, name, title, errMsg string) { - log.Println(errMsg, "for", name) - w.Header().Set("Content-Type", "text/html;charset=utf-8") - w.WriteHeader(status) - fmt.Fprint( - w, - base( - title, - fmt.Sprintf( - `

    %s. Go back to the hypha.

    `, - errMsg, - name, - ), - user.EmptyUser(), - ), - ) -} - -// This part is present in all html documents. -var base = views.BaseHTML - -func handlerStyle(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - if _, err := os.Stat(cfg.WikiDir + "/static/common.css"); err == nil { - http.ServeFile(w, rq, cfg.WikiDir+"/static/common.css") - } else { - w.Header().Set("Content-Type", "text/css;charset=utf-8") - w.Write([]byte(assets.DefaultCSS())) - } - if bytes, err := ioutil.ReadFile(cfg.WikiDir + "/static/custom.css"); err == nil { - w.Write(bytes) - } -} - -func handlerToolbar(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - w.Header().Set("Content-Type", "text/javascript;charset=utf-8") - w.Write([]byte(assets.ToolbarJS())) -} - -// handlerIcon serves the requested icon. All icons are distributed as part of the Mycorrhiza binary. -// -// See assets/assets/icon/ for icons themselves, see assets/assets.qtpl for their sources. -func handlerIcon(w http.ResponseWriter, rq *http.Request) { - iconName := strings.TrimPrefix(rq.URL.Path, "/assets/icon/") - if iconName == "https" { - iconName = "http" - } - w.Header().Set("Content-Type", "image/svg+xml") - icon := func() string { - switch iconName { - case "gemini": - return assets.IconGemini() - case "mailto": - return assets.IconMailto() - case "gopher": - return assets.IconGopher() - case "feed": - return assets.IconFeed() - default: - return assets.IconHTTP() - } - }() - _, err := io.WriteString(w, icon) - if err != nil { - log.Println(err) - } - -} - -func handlerUserList(w http.ResponseWriter, rq *http.Request) { - w.Header().Set("Content-Type", "text/html;charset=utf-8") - w.WriteHeader(http.StatusOK) - w.Write([]byte(base("User list", views.UserListHTML(), user.FromRequest(rq)))) -} - -func handlerRobotsTxt(w http.ResponseWriter, rq *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - w.Write([]byte( - `User-agent: * -Allow: /page/ -Allow: /recent-changes -Disallow: / -Crawl-delay: 5`)) -} - -func prepareRq(rq *http.Request) { - log.Println(rq.RequestURI) - rq.URL.Path = strings.TrimSuffix(rq.URL.Path, "/") -} - func main() { parseCliArgs() @@ -131,41 +28,20 @@ func main() { } log.Println("Running MycorrhizaWiki") - if err := os.Chdir(WikiDir); err != nil { + if err := os.Chdir(cfg.WikiDir); err != nil { log.Fatal(err) } - log.Println("Wiki storage directory is", WikiDir) - hyphae.Index(WikiDir) + log.Println("Wiki storage directory is", cfg.WikiDir) + hyphae.Index(cfg.WikiDir) log.Println("Indexed", hyphae.Count(), "hyphae") - // Initialize user database user.InitUserDatabase() - history.Start(WikiDir) + history.Start(cfg.WikiDir) shroom.SetHeaderLinks() go handleGemini() - // See http_admin.go for /admin, /admin/* - initAdmin() - // See http_readers.go for /page/, /hypha/, /text/, /binary/, /attachment/ - // See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/ - // See http_auth.go for /login, /login-data, /logout, /logout-confirm - http.HandleFunc("/user-list/", handlerUserList) - // See http_history.go for /history/, /recent-changes - // See http_stuff.go for list, reindex, update-header-links, random, about - http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(WikiDir+"/static")))) - http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { - http.ServeFile(w, rq, WikiDir+"/static/favicon.ico") - }) - http.HandleFunc("/static/common.css", handlerStyle) - http.HandleFunc("/static/toolbar.js", handlerToolbar) - http.HandleFunc("/assets/icon/", handlerIcon) - http.HandleFunc("/robots.txt", handlerRobotsTxt) - http.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) { - addr, _ := url.Parse("/hypha/" + cfg.HomeHypha) // Let's pray it never fails - rq.URL = addr - handlerHypha(w, rq) - }) + web.Init() log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil)) } diff --git a/name.go b/name.go index fd2a742..f05a44f 100644 --- a/name.go +++ b/name.go @@ -1,9 +1,7 @@ package main import ( - "github.com/bouncepaw/mycorrhiza/cfg" "log" - "net/http" "strings" "git.sr.ht/~adnano/go-gemini" @@ -11,18 +9,6 @@ import ( "github.com/bouncepaw/mycorrhiza/util" ) -// HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". -func HyphaNameFromRq(rq *http.Request, actions ...string) string { - p := rq.URL.Path - for _, action := range actions { - if strings.HasPrefix(p, "/"+action+"/") { - return util.CanonicalName(strings.TrimPrefix(p, "/"+action+"/")) - } - } - log.Println("HyphaNameFromRq: this request is invalid, fallback to home hypha") - return cfg.HomeHypha -} - // geminiHyphaNameFromRq extracts hypha name from gemini request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". func geminiHyphaNameFromRq(rq *gemini.Request, actions ...string) string { p := rq.URL.Path diff --git a/util/util.go b/util/util.go index 92fcd68..1f3aced 100644 --- a/util/util.go +++ b/util/util.go @@ -4,12 +4,18 @@ import ( "crypto/rand" "encoding/hex" "github.com/bouncepaw/mycorrhiza/cfg" + "log" "net/http" "regexp" "strings" "unicode" ) +func PrepareRq(rq *http.Request) { + log.Println(rq.RequestURI) + rq.URL.Path = strings.TrimSuffix(rq.URL.Path, "/") +} + // LettersNumbersOnly keeps letters and numbers only in the given string. func LettersNumbersOnly(s string) string { var ( @@ -93,3 +99,15 @@ func IsCanonicalName(name string) bool { func IsPossibleUsername(username string) bool { return UsernamePattern.MatchString(strings.TrimSpace(username)) } + +// HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". +func HyphaNameFromRq(rq *http.Request, actions ...string) string { + p := rq.URL.Path + for _, action := range actions { + if strings.HasPrefix(p, "/"+action+"/") { + return CanonicalName(strings.TrimPrefix(p, "/"+action+"/")) + } + } + log.Println("HyphaNameFromRq: this request is invalid, fallback to home hypha") + return cfg.HomeHypha +} diff --git a/web/http_admin.go b/web/http_admin.go new file mode 100644 index 0000000..0cd01a2 --- /dev/null +++ b/web/http_admin.go @@ -0,0 +1,44 @@ +package web + +import ( + "log" + "net/http" + + "github.com/bouncepaw/mycorrhiza/cfg" + "github.com/bouncepaw/mycorrhiza/user" + "github.com/bouncepaw/mycorrhiza/util" + "github.com/bouncepaw/mycorrhiza/views" +) + +// InitAdmin sets up /admin routes if auth is used. Call it after you have decided if you want to use auth. +func InitAdmin() { + if user.AuthUsed { + http.HandleFunc("/admin", HandlerAdmin) + http.HandleFunc("/admin/shutdown", HandlerAdminShutdown) + http.HandleFunc("/admin/reindex-users", HandlerAdminReindexUsers) + } +} + +func HandlerAdmin(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + if user.CanProceed(rq, "admin") { + w.Header().Set("Content-Type", "text/html;charset=utf-8") + w.WriteHeader(http.StatusOK) + w.Write([]byte(views.BaseHTML("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq)))) + } +} + +func HandlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" { + log.Fatal("An admin commanded the wiki to shutdown") + } +} + +func HandlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + if user.CanProceed(rq, "admin") && rq.Method == "POST" { + user.ReadUsersFromFilesystem() + http.Redirect(w, rq, "/hypha/"+cfg.UserHypha, http.StatusSeeOther) + } +} diff --git a/http_auth.go b/web/http_auth.go similarity index 86% rename from http_auth.go rename to web/http_auth.go index fb0337f..84cdff2 100644 --- a/http_auth.go +++ b/web/http_auth.go @@ -1,4 +1,4 @@ -package main +package web import ( "github.com/bouncepaw/mycorrhiza/cfg" @@ -20,14 +20,14 @@ func init() { } func handlerRegister(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) if !cfg.UseRegistration { w.WriteHeader(http.StatusForbidden) } if rq.Method == http.MethodGet { io.WriteString( w, - base( + views.BaseHTML( "Register", views.RegisterHTML(rq), user.FromRequest(rq), @@ -61,7 +61,7 @@ func handlerLogout(w http.ResponseWriter, rq *http.Request) { log.Println("Unknown user tries to log out") w.WriteHeader(http.StatusForbidden) } - w.Write([]byte(base("Logout?", views.LogoutHTML(can), u))) + w.Write([]byte(views.BaseHTML("Logout?", views.LogoutHTML(can), u))) } func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) { @@ -70,26 +70,26 @@ func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) { } func handlerLoginData(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( username = util.CanonicalName(rq.PostFormValue("username")) password = rq.PostFormValue("password") err = user.LoginDataHTTP(w, rq, username, password) ) if err != "" { - w.Write([]byte(base(err, views.LoginErrorHTML(err), user.EmptyUser()))) + w.Write([]byte(views.BaseHTML(err, views.LoginErrorHTML(err), user.EmptyUser()))) } else { http.Redirect(w, rq, "/", http.StatusSeeOther) } } func handlerLogin(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) w.Header().Set("Content-Type", "text/html;charset=utf-8") if user.AuthUsed { w.WriteHeader(http.StatusOK) } else { w.WriteHeader(http.StatusForbidden) } - w.Write([]byte(base("Login", views.LoginHTML(), user.EmptyUser()))) + w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser()))) } diff --git a/http_history.go b/web/http_history.go similarity index 86% rename from http_history.go rename to web/http_history.go index e65e84b..9cba85b 100644 --- a/http_history.go +++ b/web/http_history.go @@ -1,4 +1,4 @@ -package main +package web import ( "fmt" @@ -23,8 +23,8 @@ func init() { // handlerHistory lists all revisions of a hypha func handlerHistory(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - hyphaName := HyphaNameFromRq(rq, "history") + util.PrepareRq(rq) + hyphaName := util.HyphaNameFromRq(rq, "history") var list string // History can be found for files that do not exist anymore. @@ -35,25 +35,25 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) { log.Println("Found", len(revs), "revisions for", hyphaName) util.HTTP200Page(w, - base(hyphaName, views.HistoryHTML(rq, hyphaName, list), user.FromRequest(rq))) + views.BaseHTML(hyphaName, views.HistoryHTML(rq, hyphaName, list), user.FromRequest(rq))) } // Recent changes func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( noPrefix = strings.TrimPrefix(rq.URL.String(), "/recent-changes/") n, err = strconv.Atoi(noPrefix) ) if err == nil && n < 101 { - util.HTTP200Page(w, base(strconv.Itoa(n)+" recent changes", views.RecentChangesHTML(n), user.FromRequest(rq))) + util.HTTP200Page(w, views.BaseHTML(strconv.Itoa(n)+" recent changes", views.RecentChangesHTML(n), user.FromRequest(rq))) } else { http.Redirect(w, rq, "/recent-changes/20", http.StatusSeeOther) } } func genericHandlerOfFeeds(w http.ResponseWriter, rq *http.Request, f func() (string, error), name string) { - prepareRq(rq) + util.PrepareRq(rq) if content, err := f(); err != nil { w.Header().Set("Content-Type", "text/plain;charset=utf-8") w.WriteHeader(http.StatusInternalServerError) diff --git a/http_mutators.go b/web/http_mutators.go similarity index 93% rename from http_mutators.go rename to web/http_mutators.go index a3d98aa..fd6a5fc 100644 --- a/http_mutators.go +++ b/web/http_mutators.go @@ -1,4 +1,4 @@ -package main +package web import ( "fmt" @@ -35,9 +35,9 @@ func factoryHandlerAsker( succPageTemplate func(*http.Request, string, bool) string, ) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( - hyphaName = HyphaNameFromRq(rq, actionPath) + hyphaName = util.HyphaNameFromRq(rq, actionPath) h = hyphae.ByName(hyphaName) u = user.FromRequest(rq) ) @@ -52,7 +52,7 @@ func factoryHandlerAsker( } util.HTTP200Page( w, - base( + views.BaseHTML( fmt.Sprintf(succTitleTemplate, hyphaName), succPageTemplate(rq, hyphaName, h.Exists), u)) @@ -85,9 +85,9 @@ func factoryHandlerConfirmer( confirmer func(*hyphae.Hypha, *user.User, *http.Request) (*history.HistoryOp, string), ) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( - hyphaName = HyphaNameFromRq(rq, actionPath) + hyphaName = util.HyphaNameFromRq(rq, actionPath) h = hyphae.ByName(hyphaName) u = user.FromRequest(rq) ) @@ -129,9 +129,9 @@ var handlerRenameConfirm = factoryHandlerConfirmer( // handlerEdit shows the edit form. It doesn't edit anything actually. func handlerEdit(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( - hyphaName = HyphaNameFromRq(rq, "edit") + hyphaName = util.HyphaNameFromRq(rq, "edit") h = hyphae.ByName(hyphaName) warning string textAreaFill string @@ -158,7 +158,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { } util.HTTP200Page( w, - base( + views.BaseHTML( "Edit "+hyphaName, views.EditHTML(rq, hyphaName, textAreaFill, warning), u)) @@ -166,9 +166,9 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { // handlerUploadText uploads a new text part for the hypha. func handlerUploadText(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( - hyphaName = HyphaNameFromRq(rq, "upload-text") + hyphaName = util.HyphaNameFromRq(rq, "upload-text") h = hyphae.ByName(hyphaName) textData = rq.PostFormValue("text") action = rq.PostFormValue("action") @@ -190,7 +190,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { if action == "Preview" { util.HTTP200Page( w, - base( + views.BaseHTML( "Preview "+hyphaName, views.PreviewHTML( rq, @@ -206,10 +206,10 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { // handlerUploadBinary uploads a new binary part for the hypha. func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) rq.ParseMultipartForm(10 << 20) // Set upload limit var ( - hyphaName = HyphaNameFromRq(rq, "upload-binary") + hyphaName = util.HyphaNameFromRq(rq, "upload-binary") h = hyphae.ByName(hyphaName) u = user.FromRequest(rq) file, handler, err = rq.FormFile("binary") diff --git a/http_readers.go b/web/http_readers.go similarity index 90% rename from http_readers.go rename to web/http_readers.go index 0d8e492..bd86ff4 100644 --- a/http_readers.go +++ b/web/http_readers.go @@ -1,4 +1,4 @@ -package main +package web import ( "fmt" @@ -29,9 +29,9 @@ func init() { } func handlerAttachment(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( - hyphaName = HyphaNameFromRq(rq, "attachment") + hyphaName = util.HyphaNameFromRq(rq, "attachment") h = hyphae.ByName(hyphaName) u = user.FromRequest(rq) ) @@ -43,7 +43,7 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) { } func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( shorterUrl = strings.TrimPrefix(rq.URL.Path, "/primitive-diff/") firstSlashIndex = strings.IndexRune(shorterUrl, '/') @@ -61,7 +61,7 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { // handlerRevision displays a specific revision of text part a page func handlerRevision(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( shorterUrl = strings.TrimPrefix(rq.URL.Path, "/rev/") firstSlashIndex = strings.IndexRune(shorterUrl, '/') @@ -83,13 +83,13 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { ) w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) - w.Write([]byte(base(util.BeautifulName(hyphaName), page, u))) + w.Write([]byte(views.BaseHTML(util.BeautifulName(hyphaName), page, u))) } // handlerText serves raw source text of the hypha. func handlerText(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - hyphaName := HyphaNameFromRq(rq, "text") + util.PrepareRq(rq) + hyphaName := util.HyphaNameFromRq(rq, "text") if h := hyphae.ByName(hyphaName); h.Exists { log.Println("Serving", h.TextPath) w.Header().Set("Content-Type", "text/plain; charset=utf-8") @@ -99,8 +99,8 @@ func handlerText(w http.ResponseWriter, rq *http.Request) { // handlerBinary serves binary part of the hypha. func handlerBinary(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - hyphaName := HyphaNameFromRq(rq, "binary") + util.PrepareRq(rq) + hyphaName := util.HyphaNameFromRq(rq, "binary") if h := hyphae.ByName(hyphaName); h.Exists { log.Println("Serving", h.BinaryPath) w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.BinaryPath))) @@ -110,9 +110,9 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) { // handlerHypha is the main hypha action that displays the hypha and the binary upload form along with some navigation. func handlerHypha(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( - hyphaName = HyphaNameFromRq(rq, "page", "hypha") + hyphaName = util.HyphaNameFromRq(rq, "page", "hypha") h = hyphae.ByName(hyphaName) contents string openGraph string diff --git a/http_stuff.go b/web/http_stuff.go similarity index 87% rename from http_stuff.go rename to web/http_stuff.go index 8984fc1..605a227 100644 --- a/http_stuff.go +++ b/web/http_stuff.go @@ -1,5 +1,5 @@ // http_stuff.go is used for meta stuff about the wiki or all hyphae at once. -package main +package web import ( "github.com/bouncepaw/mycorrhiza/cfg" @@ -25,22 +25,22 @@ func init() { // handlerList shows a list of all hyphae in the wiki in random order. func handlerList(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) - util.HTTP200Page(w, base("List of pages", views.HyphaListHTML(), user.FromRequest(rq))) + util.PrepareRq(rq) + util.HTTP200Page(w, views.BaseHTML("List of pages", views.HyphaListHTML(), user.FromRequest(rq))) } // handlerReindex reindexes all hyphae by checking the wiki storage directory anew. func handlerReindex(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) if ok := user.CanProceed(rq, "reindex"); !ok { HttpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be an admin to reindex hyphae.") log.Println("Rejected", rq.URL) return } hyphae.ResetCount() - log.Println("Wiki storage directory is", WikiDir) + log.Println("Wiki storage directory is", cfg.WikiDir) log.Println("Start indexing hyphae...") - hyphae.Index(WikiDir) + hyphae.Index(cfg.WikiDir) log.Println("Indexed", hyphae.Count(), "hyphae") http.Redirect(w, rq, "/", http.StatusSeeOther) } @@ -49,7 +49,7 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) { // // See https://mycorrhiza.lesarbr.es/hypha/configuration/header func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) if ok := user.CanProceed(rq, "update-header-links"); !ok { HttpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be a moderator to update header links.") log.Println("Rejected", rq.URL) @@ -61,7 +61,7 @@ func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { // handlerRandom redirects to a random hypha. func handlerRandom(w http.ResponseWriter, rq *http.Request) { - prepareRq(rq) + util.PrepareRq(rq) var ( randomHyphaName string amountOfHyphae = hyphae.Count() @@ -85,7 +85,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) { func handlerAbout(w http.ResponseWriter, rq *http.Request) { w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) - _, err := io.WriteString(w, base("About "+cfg.WikiName, views.AboutHTML(), user.FromRequest(rq))) + _, err := io.WriteString(w, views.BaseHTML("About "+cfg.WikiName, views.AboutHTML(), user.FromRequest(rq))) if err != nil { log.Println(err) } diff --git a/web/web.go b/web/web.go new file mode 100644 index 0000000..6d49f81 --- /dev/null +++ b/web/web.go @@ -0,0 +1,127 @@ +package web + +import ( + "fmt" + "github.com/bouncepaw/mycorrhiza/assets" + "github.com/bouncepaw/mycorrhiza/cfg" + "github.com/bouncepaw/mycorrhiza/util" + "io" + "io/ioutil" + "log" + "net/http" + "net/url" + "os" + "strings" + + "github.com/bouncepaw/mycorrhiza/user" + "github.com/bouncepaw/mycorrhiza/views" +) + +// HttpErr is used by many handlers to signal errors in a compact way. +func HttpErr(w http.ResponseWriter, status int, name, title, errMsg string) { + log.Println(errMsg, "for", name) + w.Header().Set("Content-Type", "text/html;charset=utf-8") + w.WriteHeader(status) + fmt.Fprint( + w, + views.BaseHTML( + title, + fmt.Sprintf( + `

    %s. Go back to the hypha.

    `, + errMsg, + name, + ), + user.EmptyUser(), + ), + ) +} + +func handlerStyle(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + if _, err := os.Stat(cfg.WikiDir + "/static/common.css"); err == nil { + http.ServeFile(w, rq, cfg.WikiDir+"/static/common.css") + } else { + w.Header().Set("Content-Type", "text/css;charset=utf-8") + w.Write([]byte(assets.DefaultCSS())) + } + if bytes, err := ioutil.ReadFile(cfg.WikiDir + "/static/custom.css"); err == nil { + w.Write(bytes) + } +} + +func handlerToolbar(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + w.Header().Set("Content-Type", "text/javascript;charset=utf-8") + w.Write([]byte(assets.ToolbarJS())) +} + +// handlerIcon serves the requested icon. All icons are distributed as part of the Mycorrhiza binary. +// +// See assets/assets/icon/ for icons themselves, see assets/assets.qtpl for their sources. +func handlerIcon(w http.ResponseWriter, rq *http.Request) { + iconName := strings.TrimPrefix(rq.URL.Path, "/assets/icon/") + if iconName == "https" { + iconName = "http" + } + w.Header().Set("Content-Type", "image/svg+xml") + icon := func() string { + switch iconName { + case "gemini": + return assets.IconGemini() + case "mailto": + return assets.IconMailto() + case "gopher": + return assets.IconGopher() + case "feed": + return assets.IconFeed() + default: + return assets.IconHTTP() + } + }() + _, err := io.WriteString(w, icon) + if err != nil { + log.Println(err) + } + +} + +func handlerUserList(w http.ResponseWriter, rq *http.Request) { + w.Header().Set("Content-Type", "text/html;charset=utf-8") + w.WriteHeader(http.StatusOK) + w.Write([]byte(views.BaseHTML("User list", views.UserListHTML(), user.FromRequest(rq)))) +} + +func handlerRobotsTxt(w http.ResponseWriter, rq *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + w.Write([]byte( + `User-agent: * +Allow: /page/ +Allow: /recent-changes +Disallow: / +Crawl-delay: 5`)) +} + +func Init() { + // See http_admin.go for /admin, /admin/* + InitAdmin() + // See http_readers.go for /page/, /hypha/, /text/, /binary/, /attachment/ + // See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/ + // See http_auth.go for /login, /login-data, /logout, /logout-confirm + http.HandleFunc("/user-list/", handlerUserList) + // See http_history.go for /history/, /recent-changes + // See http_stuff.go for list, reindex, update-header-links, random, about + http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(cfg.WikiDir+"/static")))) + http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { + http.ServeFile(w, rq, cfg.WikiDir+"/static/favicon.ico") + }) + http.HandleFunc("/static/common.css", handlerStyle) + http.HandleFunc("/static/toolbar.js", handlerToolbar) + http.HandleFunc("/assets/icon/", handlerIcon) + http.HandleFunc("/robots.txt", handlerRobotsTxt) + http.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) { + addr, _ := url.Parse("/hypha/" + cfg.HomeHypha) // Let's pray it never fails + rq.URL = addr + handlerHypha(w, rq) + }) +} From d69ce77251571c8b1fca97fe8df94b4001ca1fbf Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sun, 9 May 2021 16:09:27 +0500 Subject: [PATCH 11/41] Reorganise and document the web stuff a little --- hyphae/files.go | 2 ++ main.go | 7 +++---- web/http_admin.go | 25 ++++++++++++++++--------- web/http_auth.go | 40 +++++++++++++++++++++++++++------------- web/http_history.go | 7 ++++--- web/http_mutators.go | 18 +++++++++--------- web/http_readers.go | 2 +- web/http_stuff.go | 8 ++++---- web/web.go | 21 ++++++++++++--------- 9 files changed, 78 insertions(+), 52 deletions(-) diff --git a/hyphae/files.go b/hyphae/files.go index ad98fd8..082a6df 100644 --- a/hyphae/files.go +++ b/hyphae/files.go @@ -27,6 +27,8 @@ func Index(path string) { h.Insert() } } + + log.Println("Indexed", Count(), "hyphae") } // indexHelper finds all hypha files in the full `path` and sends them to the channel. Handling of duplicate entries and attachment and counting them is up to the caller. diff --git a/main.go b/main.go index da0d6e6..8f08ee6 100644 --- a/main.go +++ b/main.go @@ -32,16 +32,15 @@ func main() { log.Fatal(err) } log.Println("Wiki storage directory is", cfg.WikiDir) + + // Init the subsystems: hyphae.Index(cfg.WikiDir) - log.Println("Indexed", hyphae.Count(), "hyphae") - user.InitUserDatabase() - history.Start(cfg.WikiDir) shroom.SetHeaderLinks() + // Network: go handleGemini() - web.Init() log.Fatal(http.ListenAndServe("0.0.0.0:"+cfg.HTTPPort, nil)) } diff --git a/web/http_admin.go b/web/http_admin.go index 0cd01a2..a78f884 100644 --- a/web/http_admin.go +++ b/web/http_admin.go @@ -1,6 +1,7 @@ package web import ( + "io" "log" "net/http" @@ -10,32 +11,38 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -// InitAdmin sets up /admin routes if auth is used. Call it after you have decided if you want to use auth. -func InitAdmin() { +// initAdmin sets up /admin routes if auth is used. Call it after you have decided if you want to use auth. +func initAdmin() { if user.AuthUsed { - http.HandleFunc("/admin", HandlerAdmin) - http.HandleFunc("/admin/shutdown", HandlerAdminShutdown) - http.HandleFunc("/admin/reindex-users", HandlerAdminReindexUsers) + http.HandleFunc("/admin", handlerAdmin) + http.HandleFunc("/admin/shutdown", handlerAdminShutdown) + http.HandleFunc("/admin/reindex-users", handlerAdminReindexUsers) } } -func HandlerAdmin(w http.ResponseWriter, rq *http.Request) { +// handlerAdmin provides the admin panel. +func handlerAdmin(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if user.CanProceed(rq, "admin") { w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) - w.Write([]byte(views.BaseHTML("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq)))) + _, err := io.WriteString(w, views.BaseHTML("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq))) + if err != nil { + log.Println(err) + } } } -func HandlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { +// handlerAdminShutdown kills the wiki. +func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" { log.Fatal("An admin commanded the wiki to shutdown") } } -func HandlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { +// handlerAdminReindexUsers reinitialises the user system. +func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if user.CanProceed(rq, "admin") && rq.Method == "POST" { user.ReadUsersFromFilesystem() diff --git a/web/http_auth.go b/web/http_auth.go index 84cdff2..51a0c89 100644 --- a/web/http_auth.go +++ b/web/http_auth.go @@ -11,14 +11,20 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { - http.HandleFunc("/register", handlerRegister) +func initAuth() { + if !user.AuthUsed { + return + } + if cfg.UseRegistration { + http.HandleFunc("/register", handlerRegister) + } http.HandleFunc("/login", handlerLogin) http.HandleFunc("/login-data", handlerLoginData) http.HandleFunc("/logout", handlerLogout) http.HandleFunc("/logout-confirm", handlerLogoutConfirm) } +// handlerRegister both displays the register form (GET) and registers users (POST). func handlerRegister(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if !cfg.UseRegistration { @@ -48,6 +54,7 @@ func handlerRegister(w http.ResponseWriter, rq *http.Request) { } } +// handlerLogout shows the logout form. func handlerLogout(w http.ResponseWriter, rq *http.Request) { var ( u = user.FromRequest(rq) @@ -64,11 +71,29 @@ func handlerLogout(w http.ResponseWriter, rq *http.Request) { w.Write([]byte(views.BaseHTML("Logout?", views.LogoutHTML(can), u))) } +// handlerLogoutConfirm logs the user out. +// +// TODO: merge into handlerLogout as POST method. func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) { user.LogoutFromRequest(w, rq) http.Redirect(w, rq, "/", http.StatusSeeOther) } +// handlerLogin shows the login form. +func handlerLogin(w http.ResponseWriter, rq *http.Request) { + util.PrepareRq(rq) + w.Header().Set("Content-Type", "text/html;charset=utf-8") + if user.AuthUsed { + w.WriteHeader(http.StatusOK) + } else { + w.WriteHeader(http.StatusForbidden) + } + w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser()))) +} + +// handlerLoginData logs the user in. +// +// TODO: merge into handlerLogin as POST method. func handlerLoginData(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( @@ -82,14 +107,3 @@ func handlerLoginData(w http.ResponseWriter, rq *http.Request) { http.Redirect(w, rq, "/", http.StatusSeeOther) } } - -func handlerLogin(w http.ResponseWriter, rq *http.Request) { - util.PrepareRq(rq) - w.Header().Set("Content-Type", "text/html;charset=utf-8") - if user.AuthUsed { - w.WriteHeader(http.StatusOK) - } else { - w.WriteHeader(http.StatusForbidden) - } - w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser()))) -} diff --git a/web/http_history.go b/web/http_history.go index 9cba85b..0ad71a8 100644 --- a/web/http_history.go +++ b/web/http_history.go @@ -13,7 +13,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initHistory() { http.HandleFunc("/history/", handlerHistory) http.HandleFunc("/recent-changes/", handlerRecentChanges) http.HandleFunc("/recent-changes-rss", handlerRecentChangesRSS) @@ -21,7 +21,7 @@ func init() { http.HandleFunc("/recent-changes-json", handlerRecentChangesJSON) } -// handlerHistory lists all revisions of a hypha +// handlerHistory lists all revisions of a hypha. func handlerHistory(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) hyphaName := util.HyphaNameFromRq(rq, "history") @@ -38,7 +38,7 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) { views.BaseHTML(hyphaName, views.HistoryHTML(rq, hyphaName, list), user.FromRequest(rq))) } -// Recent changes +// handlerRecentChanges displays the /recent-changes/ page. func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( @@ -52,6 +52,7 @@ func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { } } +// genericHandlerOfFeeds is a helper function for the web feed handlers. func genericHandlerOfFeeds(w http.ResponseWriter, rq *http.Request, f func() (string, error), name string) { util.PrepareRq(rq) if content, err := f(); err != nil { diff --git a/web/http_mutators.go b/web/http_mutators.go index fd6a5fc..c534eff 100644 --- a/web/http_mutators.go +++ b/web/http_mutators.go @@ -14,7 +14,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initMutators() { // Those that do not actually mutate anything: http.HandleFunc("/edit/", handlerEdit) http.HandleFunc("/delete-ask/", handlerDeleteAsk) @@ -42,7 +42,7 @@ func factoryHandlerAsker( u = user.FromRequest(rq) ) if err, errtitle := asker(u, h); err != nil { - HttpErr( + httpErr( w, http.StatusInternalServerError, hyphaName, @@ -92,7 +92,7 @@ func factoryHandlerConfirmer( u = user.FromRequest(rq) ) if hop, errtitle := confirmer(h, u, rq); hop.HasErrors() { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText()) return @@ -139,7 +139,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { u = user.FromRequest(rq) ) if err, errtitle := shroom.CanEdit(u, h); err != nil { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, err.Error()) return @@ -148,7 +148,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { textAreaFill, err = shroom.FetchTextPart(h) if err != nil { log.Println(err) - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, "Error", "Could not fetch text data") return @@ -180,7 +180,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { if action != "Preview" { hop, errtitle = shroom.UploadText(h, []byte(textData), u) if hop.HasErrors() { - HttpErr(w, http.StatusForbidden, hyphaName, + httpErr(w, http.StatusForbidden, hyphaName, errtitle, hop.FirstErrorText()) return @@ -215,12 +215,12 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { file, handler, err = rq.FormFile("binary") ) if err != nil { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, "Error", err.Error()) } if err, errtitle := shroom.CanAttach(u, h); err != nil { - HttpErr(w, http.StatusInternalServerError, hyphaName, + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, err.Error()) } @@ -240,7 +240,7 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { ) if hop.HasErrors() { - HttpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText()) + httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText()) return } http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther) diff --git a/web/http_readers.go b/web/http_readers.go index bd86ff4..864aa30 100644 --- a/web/http_readers.go +++ b/web/http_readers.go @@ -18,7 +18,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initReaders() { http.HandleFunc("/page/", handlerHypha) http.HandleFunc("/hypha/", handlerHypha) http.HandleFunc("/text/", handlerText) diff --git a/web/http_stuff.go b/web/http_stuff.go index 605a227..edf8c9e 100644 --- a/web/http_stuff.go +++ b/web/http_stuff.go @@ -15,7 +15,7 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -func init() { +func initStuff() { http.HandleFunc("/list/", handlerList) http.HandleFunc("/reindex/", handlerReindex) http.HandleFunc("/update-header-links/", handlerUpdateHeaderLinks) @@ -33,7 +33,7 @@ func handlerList(w http.ResponseWriter, rq *http.Request) { func handlerReindex(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if ok := user.CanProceed(rq, "reindex"); !ok { - HttpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be an admin to reindex hyphae.") + httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be an admin to reindex hyphae.") log.Println("Rejected", rq.URL) return } @@ -51,7 +51,7 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) { func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if ok := user.CanProceed(rq, "update-header-links"); !ok { - HttpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be a moderator to update header links.") + httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be a moderator to update header links.") log.Println("Rejected", rq.URL) return } @@ -67,7 +67,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) { amountOfHyphae = hyphae.Count() ) if amountOfHyphae == 0 { - HttpErr(w, http.StatusNotFound, cfg.HomeHypha, "There are no hyphae", + httpErr(w, http.StatusNotFound, cfg.HomeHypha, "There are no hyphae", "It is impossible to display a random hypha because the wiki does not contain any hyphae") return } diff --git a/web/web.go b/web/web.go index 6d49f81..7f2fa8e 100644 --- a/web/web.go +++ b/web/web.go @@ -1,3 +1,6 @@ +// Package web contains web handlers and initialization stuff. +// +// It exports just one function: Init. Call it if you want to have web capabilities. package web import ( @@ -17,8 +20,8 @@ import ( "github.com/bouncepaw/mycorrhiza/views" ) -// HttpErr is used by many handlers to signal errors in a compact way. -func HttpErr(w http.ResponseWriter, status int, name, title, errMsg string) { +// httpErr is used by many handlers to signal errors in a compact way. +func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) { log.Println(errMsg, "for", name) w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(status) @@ -103,14 +106,14 @@ Crawl-delay: 5`)) } func Init() { - // See http_admin.go for /admin, /admin/* - InitAdmin() - // See http_readers.go for /page/, /hypha/, /text/, /binary/, /attachment/ - // See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/ - // See http_auth.go for /login, /login-data, /logout, /logout-confirm + initAdmin() + initReaders() + initMutators() + initAuth() + initHistory() + initStuff() + http.HandleFunc("/user-list/", handlerUserList) - // See http_history.go for /history/, /recent-changes - // See http_stuff.go for list, reindex, update-header-links, random, about http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(cfg.WikiDir+"/static")))) http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { http.ServeFile(w, rq, cfg.WikiDir+"/static/favicon.ico") From a1852d363e7fcf2dd5dbc6aa2a10c3801670c674 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Tue, 11 May 2021 13:33:00 +0500 Subject: [PATCH 12/41] Refactor and document some stuff --- .idea/inspectionProfiles/Project_Default.xml | 4 ++ cfg/config.go | 34 ++++++++++---- cfg/header_links.go | 48 ++++++++++++++++++++ files/files.go | 16 ++++++- flag.go | 35 +++++++------- gemini.go | 30 ++++++++++-- main.go | 3 +- name.go | 22 --------- shroom/view.go | 7 ++- util/header_links.go | 36 --------------- util/util.go | 3 +- views/stuff.qtpl.go | 2 +- web/{http_admin.go => admin.go} | 0 web/{http_auth.go => auth.go} | 0 web/{http_history.go => history.go} | 0 web/{http_mutators.go => mutators.go} | 0 web/{http_readers.go => readers.go} | 0 web/{http_stuff.go => stuff.go} | 2 +- 18 files changed, 141 insertions(+), 101 deletions(-) create mode 100644 cfg/header_links.go delete mode 100644 name.go delete mode 100644 util/header_links.go rename web/{http_admin.go => admin.go} (100%) rename web/{http_auth.go => auth.go} (100%) rename web/{http_history.go => history.go} (100%) rename web/{http_mutators.go => mutators.go} (100%) rename web/{http_readers.go => readers.go} (100%) rename web/{http_stuff.go => stuff.go} (97%) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 5154f76..304a7ba 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,5 +2,9 @@ \ No newline at end of file diff --git a/cfg/config.go b/cfg/config.go index 09f4088..e1671be 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -1,3 +1,4 @@ +// Package cfg contains global variables that represent the current wiki configuration, including CLI options, configuration file values and header links. package cfg import ( @@ -8,6 +9,9 @@ import ( "github.com/go-ini/ini" ) +// These variables represent the configuration. You are not meant to modify them after they were set. +// +// See https://mycorrhiza.lesarbr.es/hypha/configuration/fields for their docs. var ( WikiName string NaviTitleIcon string @@ -20,9 +24,6 @@ var ( URL string GeminiCertificatePath string - WikiDir string - ConfigFilePath string - UseFixedAuth bool FixedAuthCredentialsPath string UseRegistration bool @@ -30,9 +31,15 @@ var ( LimitRegistration int ) -// Config represents a Mycorrhiza wiki configuration file. -// -// See https://mycorrhiza.lesarbr.es/hypha/configuration/fields for fields' docs. +// These variables are set before reading the config file, they are set in main.parseCliArgs. +var ( + // WikiDir is a full path to the wiki storage directory, which also must be a git repo. + WikiDir string + // ConfigFilePath is a path to the config file. Its value is used when calling ReadConfigFile. + ConfigFilePath string +) + +// Config represents a Mycorrhiza wiki configuration file. This type is used only when reading configs. type Config struct { WikiName string NaviTitleIcon string @@ -65,8 +72,10 @@ type Authorization struct { LimitRegistration uint64 } -// ReadConfigFile reads a config on the given path and stores the configuration. -func ReadConfigFile(path string) { +// ReadConfigFile reads a config on the given path and stores the configuration. Call it sometime during the initialization. +// +// Note that it may log.Fatal. +func ReadConfigFile() { cfg := &Config{ WikiName: "MycorrhizaWiki", NaviTitleIcon: "🍄", @@ -90,8 +99,8 @@ func ReadConfigFile(path string) { }, } - if path != "" { - path, err := filepath.Abs(path) + if ConfigFilePath != "" { + path, err := filepath.Abs(ConfigFilePath) if err != nil { log.Fatalf("cannot expand config file path: %s", err) } @@ -117,4 +126,9 @@ func ReadConfigFile(path string) { UseRegistration = cfg.UseRegistration RegistrationCredentialsPath = cfg.RegistrationCredentialsPath LimitRegistration = int(cfg.LimitRegistration) + + // This URL makes much more sense. + if URL == "" { + URL = "http://0.0.0.0:" + HTTPPort + } } diff --git a/cfg/header_links.go b/cfg/header_links.go new file mode 100644 index 0000000..7afb3f6 --- /dev/null +++ b/cfg/header_links.go @@ -0,0 +1,48 @@ +package cfg + +// See https://mycorrhiza.lesarbr.es/hypha/configuration/header +import ( + "strings" +) + +// HeaderLinks is a list off current header links. Feel free to iterate it directly but do not modify it by yourself. Call ParseHeaderLinks if you need to set new header links. +var HeaderLinks []HeaderLink + +// SetDefaultHeaderLinks sets the header links to the default list of: home hypha, recent changes, hyphae list, random hypha. +func SetDefaultHeaderLinks() { + HeaderLinks = []HeaderLink{ + {"/", WikiName}, + {"/recent-changes", "Recent changes"}, + {"/list", "All hyphae"}, + {"/random", "Random"}, + } +} + +// ParseHeaderLinks extracts all rocketlinks from the given text and saves them as header links. rocketlinkλ must be set to markup.Rocketlink. You have to pass it like that to avoid cyclical dependency. +func ParseHeaderLinks(text string, rocketlinkλ func(string, string) (string, string, string)) { + HeaderLinks = []HeaderLink{} + for _, line := range strings.Split(text, "\n") { + // There is a false positive when parsing markup like that: + // + // ``` + // => this is not a link, it is part of the preformatted block + // ``` + // + // I do not really care. + if strings.HasPrefix(line, "=>") { + href, display, _ := rocketlinkλ(line, HeaderLinksHypha) + HeaderLinks = append(HeaderLinks, HeaderLink{ + Href: href, + Display: display, + }) + } + } +} + +// HeaderLink represents a header link. Header links are the links shown in the top gray bar. +type HeaderLink struct { + // Href is the URL of the link. It goes .... + Href string + // Display is what is shown when the link is rendered. It goes here. + Display string +} diff --git a/files/files.go b/files/files.go index 634cc16..740041b 100644 --- a/files/files.go +++ b/files/files.go @@ -1,3 +1,4 @@ +// Package files is used to get paths to different files Mycorrhiza uses. Also see cfg. package files import ( @@ -17,9 +18,20 @@ var paths struct { fixedCredentialsJSON string } -func TokensJSON() string { return paths.tokensJSON } +// TokensJSON returns a path to the JSON file where users' tokens are stored. +// +// Default path: $XDG_DATA_HOME/mycorrhiza/tokens.json +func TokensJSON() string { return paths.tokensJSON } + +// RegistrationCredentialsJSON returns a path to the JSON file where registration credentials are stored. +// +// Default path: $XDG_DATA_HOME/mycorrhiza/registration.json func RegistrationCredentialsJSON() string { return paths.registrationCredentialsJSON } -func FixedCredentialsJSON() string { return paths.fixedCredentialsJSON } + +// FixedCredentialsJSON returns a path to the JSON file where fixed credentials are stored. +// +// There is no default path. +func FixedCredentialsJSON() string { return paths.fixedCredentialsJSON } // CalculatePaths looks for all external paths and stores them. Tries its best to find any errors. It is safe it to call it multiple times in order to save new paths. func CalculatePaths() error { diff --git a/flag.go b/flag.go index d801d3d..19c69d6 100644 --- a/flag.go +++ b/flag.go @@ -9,25 +9,32 @@ import ( "path/filepath" "github.com/bouncepaw/mycorrhiza/assets" - "github.com/bouncepaw/mycorrhiza/util" ) +// CLI options are read and parsed here. + var printExampleConfig bool func init() { flag.StringVar(&cfg.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() - } + flag.Usage = printHelp } -// Do the things related to cli args and die maybe +// printHelp prints the help message. The help message is stored in assets. +func printHelp() { + _, err := fmt.Fprintf( + flag.CommandLine.Output(), + assets.HelpMessage(), + os.Args[0], + ) + if err != nil { + log.Fatal(err) + } + flag.PrintDefaults() +} + +// parseCliArgs parses CLI options and sets several important global variables. Call it early. func parseCliArgs() { flag.Parse() @@ -46,12 +53,4 @@ func parseCliArgs() { if err != nil { log.Fatal(err) } - - if cfg.URL == "" { - cfg.URL = "http://0.0.0.0:" + cfg.HTTPPort - } - - cfg.HomeHypha = util.CanonicalName(cfg.HomeHypha) - cfg.UserHypha = util.CanonicalName(cfg.UserHypha) - cfg.HeaderLinksHypha = util.CanonicalName(cfg.HeaderLinksHypha) } diff --git a/gemini.go b/gemini.go index 050edc1..8cbd6df 100644 --- a/gemini.go +++ b/gemini.go @@ -1,29 +1,37 @@ package main +// Gemini-related stuff. This is currently a proof-of-concept implementation, no one really uses it. +// Maybe we should deprecate it until we find power to do it properly? +// +// When this stuff gets more serious, a separate module will be needed. + import ( "crypto/tls" "crypto/x509/pkix" - "github.com/bouncepaw/mycorrhiza/cfg" + "io" "io/ioutil" "log" "path/filepath" + "strings" "time" "git.sr.ht/~adnano/go-gemini" "git.sr.ht/~adnano/go-gemini/certificate" + "github.com/bouncepaw/mycorrhiza/cfg" "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/markup" + "github.com/bouncepaw/mycorrhiza/util" ) func geminiHomeHypha(w *gemini.ResponseWriter, rq *gemini.Request) { log.Println(rq.URL) - w.Write([]byte(`# MycorrhizaWiki + _, _ = io.WriteString(w, `# MycorrhizaWiki You have successfully served the wiki through Gemini. Currently, support is really work-in-progress; you should resort to using Mycorrhiza through the web protocols. Visit home hypha: -=> /hypha/` + cfg.HomeHypha)) +=> /hypha/`+cfg.HomeHypha) } func geminiHypha(w *gemini.ResponseWriter, rq *gemini.Request) { @@ -42,9 +50,9 @@ func geminiHypha(w *gemini.ResponseWriter, rq *gemini.Request) { } } if hasAmnt { - w.Write([]byte("This hypha has an attachment\n")) + _, _ = io.WriteString(w, "This hypha has an attachment\n") } - w.Write([]byte(contents)) + _, _ = io.WriteString(w, contents) } func handleGemini() { @@ -82,3 +90,15 @@ func handleGemini() { log.Fatal(err) } } + +// geminiHyphaNameFromRq extracts hypha name from gemini request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". +func geminiHyphaNameFromRq(rq *gemini.Request, actions ...string) string { + p := rq.URL.Path + for _, action := range actions { + if strings.HasPrefix(p, "/"+action+"/") { + return util.CanonicalName(strings.TrimPrefix(p, "/"+action+"/")) + } + } + log.Fatal("HyphaNameFromRq: no matching action passed") + return "" +} diff --git a/main.go b/main.go index 8f08ee6..c6352cf 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ //go:generate qtc -dir=assets //go:generate qtc -dir=views //go:generate qtc -dir=tree +// Command mycorrhiza is a program that runs a mycorrhiza wiki. package main import ( @@ -21,7 +22,7 @@ func main() { parseCliArgs() // It is ok if the path is "" - cfg.ReadConfigFile(cfg.ConfigFilePath) + cfg.ReadConfigFile() if err := files.CalculatePaths(); err != nil { log.Fatal(err) diff --git a/name.go b/name.go deleted file mode 100644 index f05a44f..0000000 --- a/name.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "log" - "strings" - - "git.sr.ht/~adnano/go-gemini" - - "github.com/bouncepaw/mycorrhiza/util" -) - -// geminiHyphaNameFromRq extracts hypha name from gemini request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". -func geminiHyphaNameFromRq(rq *gemini.Request, actions ...string) string { - p := rq.URL.Path - for _, action := range actions { - if strings.HasPrefix(p, "/"+action+"/") { - return util.CanonicalName(strings.TrimPrefix(p, "/"+action+"/")) - } - } - log.Fatal("HyphaNameFromRq: no matching action passed") - return "" -} diff --git a/shroom/view.go b/shroom/view.go index b00bf75..52879c6 100644 --- a/shroom/view.go +++ b/shroom/view.go @@ -7,7 +7,6 @@ import ( "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/markup" - "github.com/bouncepaw/mycorrhiza/util" ) // FetchTextPart tries to read text file of the given hypha. If there is no file, empty string is returned. @@ -26,14 +25,14 @@ func FetchTextPart(h *hyphae.Hypha) (string, error) { func SetHeaderLinks() { if userLinksHypha := hyphae.ByName(cfg.HeaderLinksHypha); !userLinksHypha.Exists { - util.SetDefaultHeaderLinks() + cfg.SetDefaultHeaderLinks() } else { contents, err := ioutil.ReadFile(userLinksHypha.TextPath) if err != nil || len(contents) == 0 { - util.SetDefaultHeaderLinks() + cfg.SetDefaultHeaderLinks() } else { text := string(contents) - util.ParseHeaderLinks(text, markup.Rocketlink) + cfg.ParseHeaderLinks(text, markup.Rocketlink) } } } diff --git a/util/header_links.go b/util/header_links.go deleted file mode 100644 index bc942c7..0000000 --- a/util/header_links.go +++ /dev/null @@ -1,36 +0,0 @@ -package util - -import ( - "github.com/bouncepaw/mycorrhiza/cfg" - "strings" -) - -func SetDefaultHeaderLinks() { - HeaderLinks = []HeaderLink{ - {"/", cfg.WikiName}, - {"/recent-changes", "Recent changes"}, - {"/list", "All hyphae"}, - {"/random", "Random"}, - } -} - -// rocketlinkλ is markup.Rocketlink. You have to pass it like that to avoid cyclical dependency. -func ParseHeaderLinks(text string, rocketlinkλ func(string, string) (string, string, string)) { - HeaderLinks = []HeaderLink{} - for _, line := range strings.Split(text, "\n") { - if strings.HasPrefix(line, "=>") { - href, text, _ := rocketlinkλ(line, cfg.HeaderLinksHypha) - HeaderLinks = append(HeaderLinks, HeaderLink{ - Href: href, - Display: text, - }) - } - } -} - -type HeaderLink struct { - Href string - Display string -} - -var HeaderLinks []HeaderLink diff --git a/util/util.go b/util/util.go index 1f3aced..0cd0ca0 100644 --- a/util/util.go +++ b/util/util.go @@ -3,12 +3,13 @@ package util import ( "crypto/rand" "encoding/hex" - "github.com/bouncepaw/mycorrhiza/cfg" "log" "net/http" "regexp" "strings" "unicode" + + "github.com/bouncepaw/mycorrhiza/cfg" ) func PrepareRq(rq *http.Request) { diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index a2d3de6..9344f8e 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -63,7 +63,7 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User, ") - state.id++ - state.buf = fmt.Sprintf("
    ", state.id, strings.TrimPrefix(line, "```"))
    -	default:
    -		state.where = ""
    -		addLine(state.buf + "")
    -		goto normalState
    -	}
    -	return
    -
    -normalState:
    -	state.id++
    -	switch {
    -
    -	case startsWith("```"):
    -		addParagraphIfNeeded()
    -		state.where = "pre"
    -		state.buf = fmt.Sprintf("
    ", state.id, strings.TrimPrefix(line, "```"))
    -
    -	case startsWith("###### "):
    -		addParagraphIfNeeded()
    -		addHeading(6)
    -	case startsWith("##### "):
    -		addParagraphIfNeeded()
    -		addHeading(5)
    -	case startsWith("#### "):
    -		addParagraphIfNeeded()
    -		addHeading(4)
    -	case startsWith("### "):
    -		addParagraphIfNeeded()
    -		addHeading(3)
    -	case startsWith("## "):
    -		addParagraphIfNeeded()
    -		addHeading(2)
    -	case startsWith("# "):
    -		addParagraphIfNeeded()
    -		addHeading(1)
    -
    -	case startsWith(">"):
    -		addParagraphIfNeeded()
    -		addLine(
    -			fmt.Sprintf(
    -				"
    %s
    ", - state.id, - ParagraphToHtml(state.name, remover(">")(line)), - ), - ) - case startsWith("=>"): - addParagraphIfNeeded() - state.where = "launchpad" - state.buf = fmt.Sprintf("") - } - } - - if len(item.content) > 0 { - b.WriteString("") - } -} - -// A structure representing ordered and unordered lists in the AST. -type List struct { - curr *listItem - hyphaName string - ordered bool - finalized bool -} - -func NewList(line, hyphaName string) (*List, bool) { - list := &List{ - hyphaName: hyphaName, - curr: newListItem(nil), - } - return list, list.Parse(line) -} - -func (list *List) pushItem() { - item := newListItem(list.curr) - list.curr.children = append(list.curr.children, item) - list.curr = item -} - -func (list *List) popItem() { - if list.curr == nil { - return - } - list.curr = list.curr.parent -} - -func (list *List) balance(level int) { - for level > list.curr.depth { - list.pushItem() - } - - for level < list.curr.depth { - list.popItem() - } -} - -func (list *List) Parse(line string) (done bool) { - level, offset, ordered, err := parseListItem(line) - if err != nil { - list.Finalize() - return true - } - - // update ordered flag if the current node is the root one - // (i.e. no parsing has been done yet) - if list.curr.parent == nil { - list.ordered = ordered - } - - // if list type has suddenly changed (ill-formatted list), quit - if ordered != list.ordered { - list.Finalize() - return true - } - - list.balance(level) - - // if the current node already has content, create a new one - // to prevent overwriting existing content (effectively creating - // a new sibling node) - if len(list.curr.content) > 0 { - list.popItem() - list.pushItem() - } - - list.curr.content = line[offset:] - - return false -} - -func (list *List) Finalize() { - if !list.finalized { - // close all opened nodes, effectively going up to the root node - list.balance(0) - list.finalized = true - } -} - -func (list *List) RenderAsHtml() (html string) { - // for a good measure - list.Finalize() - - b := &strings.Builder{} - - // fire up recursive render process - list.curr.renderAsHtmlTo(b, list.hyphaName, list.ordered) - - return b.String() -} diff --git a/markup/mycomarkup.go b/markup/mycomarkup.go deleted file mode 100644 index f8c4946..0000000 --- a/markup/mycomarkup.go +++ /dev/null @@ -1,98 +0,0 @@ -// This is not done yet -package markup - -import ( - "fmt" - "regexp" - "strings" - - "github.com/bouncepaw/mycorrhiza/cfg" - - "github.com/bouncepaw/mycomarkup/links" -) - -// A Mycomarkup-formatted document -type MycoDoc struct { - // data - hyphaName string - contents string - // indicators - parsedAlready bool - // results - ast []Line - html string - firstImageURL string - description string -} - -// Constructor -func Doc(hyphaName, contents string) *MycoDoc { - md := &MycoDoc{ - hyphaName: hyphaName, - contents: contents, - } - return md -} - -func (md *MycoDoc) Lex(recursionLevel int) *MycoDoc { - if !md.parsedAlready { - md.ast = md.lex() - } - md.parsedAlready = true - return md -} - -// AsHTML returns an html representation of the document -func (md *MycoDoc) AsHTML() string { - md.html = Parse(md.Lex(0).ast, 0, 0, 0) - return md.html -} - -// AsGemtext returns a gemtext representation of the document. Currently really limited, just returns source text -func (md *MycoDoc) AsGemtext() string { - return md.contents -} - -// Used to clear opengraph description from html tags. This method is usually bad because of dangers of malformed HTML, but I'm going to use it only for Mycorrhiza-generated HTML, so it's okay. The question mark is required; without it the whole string is eaten away. -var htmlTagRe = regexp.MustCompile(`<.*?>`) - -// OpenGraphHTML returns an html representation of og: meta tags. -func (md *MycoDoc) OpenGraphHTML() string { - md.ogFillVars() - return strings.Join([]string{ - ogTag("title", md.hyphaName), - ogTag("type", "article"), - ogTag("image", md.firstImageURL), - ogTag("url", cfg.URL+"/hypha/"+md.hyphaName), - ogTag("determiner", ""), - ogTag("description", htmlTagRe.ReplaceAllString(md.description, "")), - }, "\n") -} - -func (md *MycoDoc) ogFillVars() *MycoDoc { - md.firstImageURL = cfg.URL + "/favicon.ico" - foundDesc := false - foundImg := false - for _, line := range md.ast { - switch v := line.contents.(type) { - case string: - if !foundDesc { - md.description = v - foundDesc = true - } - case Img: - if !foundImg && len(v.entries) > 0 { - md.firstImageURL = v.entries[0].srclink.ImgSrc() - if !v.entries[0].srclink.OfKind(links.LinkExternal) { - md.firstImageURL = cfg.URL + md.firstImageURL - } - foundImg = true - } - } - } - return md -} - -func ogTag(property, content string) string { - return fmt.Sprintf(``, property, content) -} diff --git a/markup/outlink.go b/markup/outlink.go deleted file mode 100644 index aef4847..0000000 --- a/markup/outlink.go +++ /dev/null @@ -1,57 +0,0 @@ -package markup - -import ( - "regexp" - "strings" - - "github.com/bouncepaw/mycomarkup/links" -) - -// OutLinks returns a channel of names of hyphae this mycodocument links. -// Links include: -// * Regular links -// * Rocketlinks -// * Transclusion -// * Image galleries -// Not needed anymore, I guess. -func (md *MycoDoc) OutLinks() chan string { - ch := make(chan string) - if !md.parsedAlready { - md.Lex(0) - } - go func() { - for _, line := range md.ast { - switch v := line.contents.(type) { - case string: - if strings.HasPrefix(v, "`) - -func extractLinks(html string, ch chan string) { - if results := reLinks.FindAllStringSubmatch(html, -1); results != nil { - for _, result := range results { - // result[0] is always present at this point and is not needed, because it is the whole matched substring (which we don't need) - ch <- result[1] - } - } -} - -func extractImageLinks(img Img, ch chan string) { - for _, entry := range img.entries { - if entry.srclink.OfKind(links.LinkLocalHypha) { - ch <- entry.srclink.Address() - } - } -} diff --git a/markup/paragraph.go b/markup/paragraph.go deleted file mode 100644 index a576fee..0000000 --- a/markup/paragraph.go +++ /dev/null @@ -1,185 +0,0 @@ -package markup - -import ( - "bytes" - "fmt" - "html" - "strings" - "unicode" -) - -type spanTokenType int - -const ( - spanTextNode = iota - spanItalic - spanBold - spanMono - spanSuper - spanSub - spanMark - spanStrike - spanLink -) - -func tagFromState(stt spanTokenType, tagState map[spanTokenType]bool, tagName, originalForm string) string { - if tagState[spanMono] && (stt != spanMono) { - return originalForm - } - if tagState[stt] { - tagState[stt] = false - return fmt.Sprintf("", tagName) - } else { - tagState[stt] = true - return fmt.Sprintf("<%s>", tagName) - } -} - -func getLinkNode(input *bytes.Buffer, hyphaName string, isBracketedLink bool) string { - if isBracketedLink { - input.Next(2) // drop those [[ - } - var ( - escaping = false - addrBuf = bytes.Buffer{} - displayBuf = bytes.Buffer{} - currBuf = &addrBuf - ) - for input.Len() != 0 { - b, _ := input.ReadByte() - if escaping { - currBuf.WriteByte(b) - escaping = false - } else if isBracketedLink && b == '|' && currBuf == &addrBuf { - currBuf = &displayBuf - } else if isBracketedLink && b == ']' && bytes.HasPrefix(input.Bytes(), []byte{']'}) { - input.Next(1) - break - } else if !isBracketedLink && (unicode.IsSpace(rune(b)) || strings.ContainsRune("<>{}|\\^[]`,()", rune(b))) { - input.UnreadByte() - break - } else { - currBuf.WriteByte(b) - } - } - href, text, class := LinkParts(addrBuf.String(), displayBuf.String(), hyphaName) - return fmt.Sprintf(`%s`, href, class, html.EscapeString(text)) -} - -// getTextNode splits the `input` into two parts `textNode` and `rest` by the first encountered rune that resembles a span tag. If there is none, `textNode = input`, `rest = ""`. It handles escaping with backslash. -func getTextNode(input *bytes.Buffer) string { - var ( - textNodeBuffer = bytes.Buffer{} - escaping = false - startsWith = func(t string) bool { - return bytes.HasPrefix(input.Bytes(), []byte(t)) - } - couldBeLinkStart = func() bool { - return startsWith("https://") || startsWith("http://") || startsWith("gemini://") || startsWith("gopher://") || startsWith("ftp://") - } - ) - // Always read the first byte in advance to avoid endless loops that kill computers (sad experience) - if input.Len() != 0 { - b, _ := input.ReadByte() - textNodeBuffer.WriteByte(b) - } - for input.Len() != 0 { - // Assume no error is possible because we check for length - b, _ := input.ReadByte() - if escaping { - textNodeBuffer.WriteByte(b) - escaping = false - } else if b == '\\' { - escaping = true - } else if strings.IndexByte("/*`^,![~", b) >= 0 { - input.UnreadByte() - break - } else if couldBeLinkStart() { - textNodeBuffer.WriteByte(b) - break - } else { - textNodeBuffer.WriteByte(b) - } - } - return textNodeBuffer.String() -} - -func ParagraphToHtml(hyphaName, input string) string { - var ( - p = bytes.NewBufferString(input) - ret strings.Builder - // true = tag is opened, false = tag is not opened - tagState = map[spanTokenType]bool{ - spanItalic: false, - spanBold: false, - spanMono: false, - spanSuper: false, - spanSub: false, - spanMark: false, - spanLink: false, - } - startsWith = func(t string) bool { - return bytes.HasPrefix(p.Bytes(), []byte(t)) - } - noTagsActive = func() bool { - return !(tagState[spanItalic] || tagState[spanBold] || tagState[spanMono] || tagState[spanSuper] || tagState[spanSub] || tagState[spanMark] || tagState[spanLink]) - } - ) - - for p.Len() != 0 { - switch { - case startsWith("//"): - ret.WriteString(tagFromState(spanItalic, tagState, "em", "//")) - p.Next(2) - case startsWith("**"): - ret.WriteString(tagFromState(spanBold, tagState, "strong", "**")) - p.Next(2) - case startsWith("`"): - ret.WriteString(tagFromState(spanMono, tagState, "code", "`")) - p.Next(1) - case startsWith("^"): - ret.WriteString(tagFromState(spanSuper, tagState, "sup", "^")) - p.Next(1) - case startsWith(",,"): - ret.WriteString(tagFromState(spanSub, tagState, "sub", ",,")) - p.Next(2) - case startsWith("!!"): - ret.WriteString(tagFromState(spanMark, tagState, "mark", "!!")) - p.Next(2) - case startsWith("~~"): - ret.WriteString(tagFromState(spanMark, tagState, "s", "~~")) - p.Next(2) - case startsWith("[["): - ret.WriteString(getLinkNode(p, hyphaName, true)) - case (startsWith("https://") || startsWith("http://") || startsWith("gemini://") || startsWith("gopher://") || startsWith("ftp://")) && noTagsActive(): - ret.WriteString(getLinkNode(p, hyphaName, false)) - default: - ret.WriteString(html.EscapeString(getTextNode(p))) - } - } - - for stt, open := range tagState { - if open { - switch stt { - case spanItalic: - ret.WriteString(tagFromState(spanItalic, tagState, "em", "//")) - case spanBold: - ret.WriteString(tagFromState(spanBold, tagState, "strong", "**")) - case spanMono: - ret.WriteString(tagFromState(spanMono, tagState, "code", "`")) - case spanSuper: - ret.WriteString(tagFromState(spanSuper, tagState, "sup", "^")) - case spanSub: - ret.WriteString(tagFromState(spanSub, tagState, "sub", ",,")) - case spanMark: - ret.WriteString(tagFromState(spanMark, tagState, "mark", "!!")) - case spanStrike: - ret.WriteString(tagFromState(spanMark, tagState, "s", "~~")) - case spanLink: - ret.WriteString(tagFromState(spanLink, tagState, "a", "[[")) - } - } - } - - return ret.String() -} diff --git a/markup/parser.go b/markup/parser.go deleted file mode 100644 index db715f1..0000000 --- a/markup/parser.go +++ /dev/null @@ -1,28 +0,0 @@ -package markup - -const maxRecursionLevel = 3 - -func Parse(ast []Line, from, to int, recursionLevel int) (html string) { - if recursionLevel > maxRecursionLevel { - return "Transclusion depth limit" - } - for _, line := range ast { - if line.id >= from && (line.id <= to || to == 0) || line.id == -1 { - switch v := line.contents.(type) { - case Transclusion: - html += Transclude(v, recursionLevel) - case Img: - html += v.ToHtml() - case Table: - html += v.asHtml() - case *List: - html += v.RenderAsHtml() - case string: - html += v - default: - html += "Unknown element." - } - } - } - return html -} diff --git a/markup/table.go b/markup/table.go deleted file mode 100644 index b1ddbff..0000000 --- a/markup/table.go +++ /dev/null @@ -1,230 +0,0 @@ -package markup - -import ( - "fmt" - "regexp" - "strings" - "unicode" -) - -var tableRe = regexp.MustCompile(`^table\s+{`) - -func MatchesTable(line string) bool { - return tableRe.MatchString(line) -} - -func TableFromFirstLine(line, hyphaName string) *Table { - return &Table{ - hyphaName: hyphaName, - caption: line[strings.IndexRune(line, '{')+1:], - rows: make([]*tableRow, 0), - } -} - -func (t *Table) Process(line string) (shouldGoBackToNormal bool) { - if strings.TrimSpace(line) == "}" && !t.inMultiline { - return true - } - if !t.inMultiline { - t.pushRow() - } - var ( - inLink bool - skipNext bool - escaping bool - lookingForNonSpace = !t.inMultiline - countingColspan bool - ) - for i, r := range line { - switch { - case skipNext: - skipNext = false - continue - - case lookingForNonSpace && unicode.IsSpace(r): - case lookingForNonSpace && (r == '!' || r == '|'): - t.currCellMarker = r - t.currColspan = 1 - lookingForNonSpace = false - countingColspan = true - case lookingForNonSpace: - t.currCellMarker = '^' // ^ represents implicit |, not part of syntax - t.currColspan = 1 - lookingForNonSpace = false - t.currCellBuilder.WriteRune(r) - - case escaping: - t.currCellBuilder.WriteRune(r) - case inLink && r == ']' && len(line)-1 > i && line[i+1] == ']': - t.currCellBuilder.WriteString("]]") - inLink = false - skipNext = true - case inLink: - t.currCellBuilder.WriteRune(r) - - case t.inMultiline && r == '}': - t.inMultiline = false - case t.inMultiline && i == len(line)-1: - t.currCellBuilder.WriteRune('\n') - case t.inMultiline: - t.currCellBuilder.WriteRune(r) - - // Not in multiline: - case (r == '|' || r == '!') && !countingColspan: - t.pushCell() - t.currCellMarker = r - t.currColspan = 1 - countingColspan = true - case r == t.currCellMarker && (r == '|' || r == '!') && countingColspan: - t.currColspan++ - case r == '{': - t.inMultiline = true - countingColspan = false - case r == '[' && len(line)-1 > i && line[i+1] == '[': - t.currCellBuilder.WriteString("[[") - inLink = true - skipNext = true - case i == len(line)-1: - t.pushCell() - default: - t.currCellBuilder.WriteRune(r) - countingColspan = false - } - } - return false -} - -type Table struct { - // data - hyphaName string - caption string - rows []*tableRow - // state - inMultiline bool - // tmp - currCellMarker rune - currColspan uint - currCellBuilder strings.Builder -} - -func (t *Table) pushRow() { - t.rows = append(t.rows, &tableRow{ - cells: make([]*tableCell, 0), - }) -} - -func (t *Table) pushCell() { - tc := &tableCell{ - content: t.currCellBuilder.String(), - colspan: t.currColspan, - } - switch t.currCellMarker { - case '|', '^': - tc.kind = tableCellDatum - case '!': - tc.kind = tableCellHeader - } - // We expect the table to have at least one row ready, so no nil-checking - tr := t.rows[len(t.rows)-1] - tr.cells = append(tr.cells, tc) - t.currCellBuilder = strings.Builder{} -} - -func (t *Table) asHtml() (html string) { - if t.caption != "" { - html += fmt.Sprintf("%s", t.caption) - } - if len(t.rows) > 0 && t.rows[0].looksLikeThead() { - html += fmt.Sprintf("%s", t.rows[0].asHtml(t.hyphaName)) - t.rows = t.rows[1:] - } - html += "\n\n" - for _, tr := range t.rows { - html += tr.asHtml(t.hyphaName) - } - return fmt.Sprintf(`%s
    `, html) -} - -type tableRow struct { - cells []*tableCell -} - -func (tr *tableRow) asHtml(hyphaName string) (html string) { - for _, tc := range tr.cells { - html += tc.asHtml(hyphaName) - } - return fmt.Sprintf("%s\n", html) -} - -// Most likely, rows with more than two header cells are theads. I allow one extra datum cell for tables like this: -// | ! a ! b -// ! c | d | e -// ! f | g | h -func (tr *tableRow) looksLikeThead() bool { - var ( - headerAmount = 0 - datumAmount = 0 - ) - for _, tc := range tr.cells { - switch tc.kind { - case tableCellHeader: - headerAmount++ - case tableCellDatum: - datumAmount++ - } - } - return headerAmount >= 2 && datumAmount <= 1 -} - -type tableCell struct { - kind tableCellKind - colspan uint - content string -} - -func (tc *tableCell) asHtml(hyphaName string) string { - return fmt.Sprintf( - "<%[1]s %[2]s>%[3]s\n", - tc.kind.tagName(), - tc.colspanAttribute(), - tc.contentAsHtml(hyphaName), - ) -} - -func (tc *tableCell) colspanAttribute() string { - if tc.colspan <= 1 { - return "" - } - return fmt.Sprintf(`colspan="%d"`, tc.colspan) -} - -func (tc *tableCell) contentAsHtml(hyphaName string) (html string) { - for _, line := range strings.Split(tc.content, "\n") { - if line = strings.TrimSpace(line); line != "" { - if html != "" { - html += `
    ` - } - html += ParagraphToHtml(hyphaName, line) - } - } - return html -} - -type tableCellKind int - -const ( - tableCellUnknown tableCellKind = iota - tableCellHeader - tableCellDatum -) - -func (tck tableCellKind) tagName() string { - switch tck { - case tableCellHeader: - return "th" - case tableCellDatum: - return "td" - default: - return "p" - } -} diff --git a/markup/testdata/test.myco b/markup/testdata/test.myco deleted file mode 100644 index fd5880f..0000000 --- a/markup/testdata/test.myco +++ /dev/null @@ -1,38 +0,0 @@ -# 1 -## 2 -### 3 -> quote - -* li 1 -* li 2 -text -more text -=> Pear some link - -* li\n"+ -```alt text goes here -=> preformatted text -where markup is not lexed -```it ends here" -=>linking - -text -``` -() -/\ -``` -<= Apple : 1..3 - -img { -hypha1 -hypha2| -hypha3| 60 -hypha4| { line1 -line2 -} this is ignored - -hypha5| { -state of minnesota -} -} - diff --git a/markup/utils.go b/markup/utils.go deleted file mode 100644 index 9cc89b7..0000000 --- a/markup/utils.go +++ /dev/null @@ -1,12 +0,0 @@ -package markup - -import ( - "strings" -) - -// Function that returns a function that can strip `prefix` and trim whitespace when called. -func remover(prefix string) func(string) string { - return func(l string) string { - return strings.TrimSpace(strings.TrimPrefix(l, prefix)) - } -} diff --git a/markup/xclusion.go b/markup/xclusion.go deleted file mode 100644 index c20dc96..0000000 --- a/markup/xclusion.go +++ /dev/null @@ -1,108 +0,0 @@ -package markup - -import ( - "fmt" - "github.com/bouncepaw/mycorrhiza/util" - "path" - "strconv" - "strings" -) - -const xclError = -9 - -// Transclusion is used by markup parser to remember what hyphae shall be transcluded. -type Transclusion struct { - name string - from int // inclusive - to int // inclusive -} - -// Transclude transcludes `xcl` and returns html representation. -func Transclude(xcl Transclusion, recursionLevel int) (html string) { - recursionLevel++ - tmptOk := `
    - %s -
    %s
    -
    ` - tmptFailed := `
    -

    Hypha %s does not exist

    -
    ` - if xcl.from == xclError || xcl.to == xclError || xcl.from > xcl.to { - return fmt.Sprintf(tmptFailed, xcl.name, xcl.name) - } - - rawText, binaryHtml, err := HyphaAccess(xcl.name) - if err != nil { - return fmt.Sprintf(tmptFailed, xcl.name, xcl.name) - } - md := Doc(xcl.name, rawText) - xclText := Parse(md.lex(), xcl.from, xcl.to, recursionLevel) - return fmt.Sprintf(tmptOk, xcl.name, xcl.name, binaryHtml+xclText) -} - -/* Grammar from hypha ‘transclusion’: -transclusion_line ::= transclusion_token hypha_name LWS* [":" LWS* range LWS*] -transclusion_token ::= "<=" LWS+ -hypha_name ::= canonical_name | noncanonical_name -range ::= id | (from_id two_dots to_id) | (from_id two_dots) | (two_dots to_id) -two_dots ::= ".." -*/ - -func parseTransclusion(line, hyphaName string) (xclusion Transclusion) { - line = strings.TrimSpace(remover("<=")(line)) - if line == "" { - return Transclusion{"", xclError, xclError} - } - - if strings.ContainsRune(line, ':') { - parts := strings.SplitN(line, ":", 2) - xclusion.name = xclCanonicalName(hyphaName, strings.TrimSpace(parts[0])) - selector := strings.TrimSpace(parts[1]) - xclusion.from, xclusion.to = parseSelector(selector) - } else { - xclusion.name = xclCanonicalName(hyphaName, strings.TrimSpace(line)) - } - return xclusion -} - -func xclCanonicalName(hyphaName, xclName string) string { - switch { - case strings.HasPrefix(xclName, "./"): - return util.CanonicalName(path.Join(hyphaName, strings.TrimPrefix(xclName, "./"))) - case strings.HasPrefix(xclName, "../"): - return util.CanonicalName(path.Join(path.Dir(hyphaName), strings.TrimPrefix(xclName, "../"))) - default: - return util.CanonicalName(xclName) - } -} - -// At this point: -// selector ::= id -// | from ".." -// | from ".." to -// | ".." to -// If it is not, return (xclError, xclError). -func parseSelector(selector string) (from, to int) { - if selector == "" { - return 0, 0 - } - if strings.Contains(selector, "..") { - parts := strings.Split(selector, "..") - - var ( - fromStr = strings.TrimSpace(parts[0]) - from, fromErr = strconv.Atoi(fromStr) - toStr = strings.TrimSpace(parts[1]) - to, toErr = strconv.Atoi(toStr) - ) - if fromStr == "" && toStr == "" { - return 0, 0 - } - if fromErr == nil || toErr == nil { - return from, to - } - } else if id, err := strconv.Atoi(selector); err == nil { - return id, id - } - return xclError, xclError -} diff --git a/shroom/init.go b/shroom/init.go index f5e28f1..dfcad5a 100644 --- a/shroom/init.go +++ b/shroom/init.go @@ -2,11 +2,11 @@ package shroom import ( "errors" - "github.com/bouncepaw/mycorrhiza/cfg" "github.com/bouncepaw/mycorrhiza/hyphae" - "github.com/bouncepaw/mycorrhiza/markup" "github.com/bouncepaw/mycorrhiza/views" + + "github.com/bouncepaw/mycomarkup/legacy" ) func init() { @@ -29,10 +29,4 @@ func init() { λ(h.Name) } } - markup.HyphaImageForOG = func(hyphaName string) string { - if h := hyphae.ByName(hyphaName); h.Exists && h.BinaryPath != "" { - return cfg.URL + "/binary/" + hyphaName - } - return cfg.URL + "/favicon.ico" - } } diff --git a/shroom/view.go b/shroom/view.go index 52879c6..444db3b 100644 --- a/shroom/view.go +++ b/shroom/view.go @@ -1,12 +1,13 @@ package shroom import ( - "github.com/bouncepaw/mycorrhiza/cfg" "io/ioutil" "os" + "github.com/bouncepaw/mycorrhiza/cfg" "github.com/bouncepaw/mycorrhiza/hyphae" - "github.com/bouncepaw/mycorrhiza/markup" + + "github.com/bouncepaw/mycomarkup/blocks" ) // FetchTextPart tries to read text file of the given hypha. If there is no file, empty string is returned. @@ -32,7 +33,7 @@ func SetHeaderLinks() { cfg.SetDefaultHeaderLinks() } else { text := string(contents) - cfg.ParseHeaderLinks(text, markup.Rocketlink) + cfg.ParseHeaderLinks(text, blocks.Rocketlink) } } } diff --git a/web/mutators.go b/web/mutators.go index c534eff..675d5b7 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -7,11 +7,12 @@ import ( "github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/hyphae" - "github.com/bouncepaw/mycorrhiza/markup" "github.com/bouncepaw/mycorrhiza/shroom" "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/views" + + "github.com/bouncepaw/mycomarkup/legacy" ) func initMutators() { diff --git a/web/readers.go b/web/readers.go index 864aa30..fbafcaa 100644 --- a/web/readers.go +++ b/web/readers.go @@ -11,11 +11,12 @@ import ( "github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/hyphae" - "github.com/bouncepaw/mycorrhiza/markup" "github.com/bouncepaw/mycorrhiza/mimetype" "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/views" + + "github.com/bouncepaw/mycomarkup/legacy" ) func initReaders() { From 71c89a64f3139c8268fa82605601f0c783672e5b Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Wed, 12 May 2021 19:08:01 +0500 Subject: [PATCH 16/41] Use a newer commit of mycomarkup... --- go.mod | 2 +- go.sum | 2 ++ main.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index de01040..188e0b5 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.0.0-20210512131946-becfae76473f + github.com/bouncepaw/mycomarkup v0.0.0-20210512135928-b81258c9a977 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index a6fcdf1..9c070a0 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/bouncepaw/mycomarkup v0.0.0-20210511092446-956f169b1499 h1:RLKVj992Qu github.com/bouncepaw/mycomarkup v0.0.0-20210511092446-956f169b1499/go.mod h1:fx0FBKaCaV1fofgCQOu2lNIVB/5EoDg/83i8BgBdgpc= github.com/bouncepaw/mycomarkup v0.0.0-20210512131946-becfae76473f h1:PgXG/AqO96jahMGQA81CWclIg90gsGt5kK4o7y0eZy8= github.com/bouncepaw/mycomarkup v0.0.0-20210512131946-becfae76473f/go.mod h1:4Fz80hsrXi3lRVZuVfIk5+2xocp50CFAbJfGeJWb5aM= +github.com/bouncepaw/mycomarkup v0.0.0-20210512135928-b81258c9a977 h1:xLVu4JAcNhaLRaVVn7VL/l0/ZgESwuqQ2GWErrP7H8k= +github.com/bouncepaw/mycomarkup v0.0.0-20210512135928-b81258c9a977/go.mod h1:4Fz80hsrXi3lRVZuVfIk5+2xocp50CFAbJfGeJWb5aM= 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= diff --git a/main.go b/main.go index 3d6b34f..33e17f9 100644 --- a/main.go +++ b/main.go @@ -28,7 +28,7 @@ func main() { log.Fatal(err) } - log.Println("Running MycorrhizaWiki") + log.Println("Running MycorrhizaWiki 1.2.0 indev") if err := os.Chdir(cfg.WikiDir); err != nil { log.Fatal(err) } From dbae2b35476b7c8d6abdcdc4897da46eee7245ee Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Thu, 13 May 2021 23:13:11 +0500 Subject: [PATCH 17/41] Update mycomarkup to v0.1.0 --- gemini.go | 4 ++-- go.mod | 2 +- go.sum | 29 ++--------------------------- shroom/init.go | 8 ++++---- web/mutators.go | 5 ++--- web/readers.go | 7 +++---- 6 files changed, 14 insertions(+), 41 deletions(-) diff --git a/gemini.go b/gemini.go index 858f91a..91fa479 100644 --- a/gemini.go +++ b/gemini.go @@ -22,7 +22,7 @@ import ( "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/util" - "github.com/bouncepaw/mycomarkup/legacy" + "github.com/bouncepaw/mycomarkup/doc" ) func geminiHomeHypha(w *gemini.ResponseWriter, rq *gemini.Request) { @@ -46,7 +46,7 @@ func geminiHypha(w *gemini.ResponseWriter, rq *gemini.Request) { if h.Exists { fileContentsT, errT := ioutil.ReadFile(h.TextPath) if errT == nil { - md := markup.Doc(hyphaName, string(fileContentsT)) + md := doc.Doc(hyphaName, string(fileContentsT)) contents = md.AsGemtext() } } diff --git a/go.mod b/go.mod index 188e0b5..778bbb1 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.0.0-20210512135928-b81258c9a977 + github.com/bouncepaw/mycomarkup v0.1.0 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index 9c070a0..37c9e73 100644 --- a/go.sum +++ b/go.sum @@ -3,14 +3,8 @@ git.sr.ht/~adnano/go-gemini v0.1.13/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3V github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= 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/bouncepaw/mycomarkup v0.0.0-20210502065108-4ddae294864d h1:H20wX93QMeQhQbXYdhofRrsFwn8jJ41zmJk5jr/1VOA= -github.com/bouncepaw/mycomarkup v0.0.0-20210502065108-4ddae294864d/go.mod h1:fx0FBKaCaV1fofgCQOu2lNIVB/5EoDg/83i8BgBdgpc= -github.com/bouncepaw/mycomarkup v0.0.0-20210511092446-956f169b1499 h1:RLKVj992QuayqjpIJ7M2csRjfhAnu9EO2r1Bm4D/WlU= -github.com/bouncepaw/mycomarkup v0.0.0-20210511092446-956f169b1499/go.mod h1:fx0FBKaCaV1fofgCQOu2lNIVB/5EoDg/83i8BgBdgpc= -github.com/bouncepaw/mycomarkup v0.0.0-20210512131946-becfae76473f h1:PgXG/AqO96jahMGQA81CWclIg90gsGt5kK4o7y0eZy8= -github.com/bouncepaw/mycomarkup v0.0.0-20210512131946-becfae76473f/go.mod h1:4Fz80hsrXi3lRVZuVfIk5+2xocp50CFAbJfGeJWb5aM= -github.com/bouncepaw/mycomarkup v0.0.0-20210512135928-b81258c9a977 h1:xLVu4JAcNhaLRaVVn7VL/l0/ZgESwuqQ2GWErrP7H8k= -github.com/bouncepaw/mycomarkup v0.0.0-20210512135928-b81258c9a977/go.mod h1:4Fz80hsrXi3lRVZuVfIk5+2xocp50CFAbJfGeJWb5aM= +github.com/bouncepaw/mycomarkup v0.1.0 h1:WsvWe1+ygGXexjjLo1Gq7Qxh7INkLZ9YCjj4SjZOUk4= +github.com/bouncepaw/mycomarkup v0.1.0/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= 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= @@ -45,37 +39,18 @@ github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl github.com/valyala/quicktemplate v1.6.3 h1:O7EuMwuH7Q94U2CXD6sOX8AYHqQqWtmIk690IhmpkKA= github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.1-0.20210319172145-bda8f5cee399/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= diff --git a/shroom/init.go b/shroom/init.go index dfcad5a..003f8f5 100644 --- a/shroom/init.go +++ b/shroom/init.go @@ -6,14 +6,14 @@ import ( "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/views" - "github.com/bouncepaw/mycomarkup/legacy" + "github.com/bouncepaw/mycomarkup/globals" ) func init() { - markup.HyphaExists = func(hyphaName string) bool { + globals.HyphaExists = func(hyphaName string) bool { return hyphae.ByName(hyphaName).Exists } - markup.HyphaAccess = func(hyphaName string) (rawText, binaryBlock string, err error) { + globals.HyphaAccess = func(hyphaName string) (rawText, binaryBlock string, err error) { if h := hyphae.ByName(hyphaName); h.Exists { rawText, err = FetchTextPart(h) if h.BinaryPath != "" { @@ -24,7 +24,7 @@ func init() { } return } - markup.HyphaIterate = func(λ func(string)) { + globals.HyphaIterate = func(λ func(string)) { for h := range hyphae.YieldExistingHyphae() { λ(h.Name) } diff --git a/web/mutators.go b/web/mutators.go index 675d5b7..8c9cc05 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -2,6 +2,7 @@ package web import ( "fmt" + "github.com/bouncepaw/mycomarkup/doc" "log" "net/http" @@ -11,8 +12,6 @@ import ( "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/views" - - "github.com/bouncepaw/mycomarkup/legacy" ) func initMutators() { @@ -198,7 +197,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { hyphaName, textData, "", - markup.Doc(hyphaName, textData).AsHTML()), + doc.Doc(hyphaName, textData).AsHTML()), u)) } else { http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther) diff --git a/web/readers.go b/web/readers.go index fbafcaa..ecc2e5d 100644 --- a/web/readers.go +++ b/web/readers.go @@ -2,6 +2,7 @@ package web import ( "fmt" + "github.com/bouncepaw/mycomarkup/doc" "io/ioutil" "log" "net/http" @@ -15,8 +16,6 @@ import ( "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/views" - - "github.com/bouncepaw/mycomarkup/legacy" ) func initReaders() { @@ -74,7 +73,7 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { u = user.FromRequest(rq) ) if err == nil { - contents = markup.Doc(hyphaName, textContents).AsHTML() + contents = doc.Doc(hyphaName, textContents).AsHTML() } page := views.RevisionHTML( rq, @@ -123,7 +122,7 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { fileContentsT, errT := ioutil.ReadFile(h.TextPath) _, errB := os.Stat(h.BinaryPath) if errT == nil { - md := markup.Doc(hyphaName, string(fileContentsT)) + md := doc.Doc(hyphaName, string(fileContentsT)) contents = md.AsHTML() openGraph = md.OpenGraphHTML() } From a540e8c3f842089ad627a148402795bd2fe4d677 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Fri, 14 May 2021 14:05:07 +0500 Subject: [PATCH 18/41] Provide a better non-existent hypha notive --- .idea/codeStyles/Project.xml | 9 + .idea/codeStyles/codeStyleConfig.xml | 5 + assets/assets.qtpl.go | 21 ++- assets/default.css | 19 +- views/hypha.qtpl | 38 ++++ views/hypha.qtpl.go | 268 ++++++++++++++++++--------- views/readers.qtpl | 17 +- views/readers.qtpl.go | 183 ++++++++---------- 8 files changed, 357 insertions(+), 203 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..e2c07cf --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 4877da2..aef5d36 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -113,9 +113,14 @@ func StreamDefaultCSS(qw422016 *qt422016.Writer) { qw422016.N().S(` `) //line assets/assets.qtpl:10 - qw422016.N().S(` + qw422016.N().S(`.non-existent-hypha { } +.non-existent-hypha__ways { display: flex; flex-direction: column; width: 100%; margin: 0 0 1rem 0;} +.non-existent-hypha__way { border: 1px #999 solid; border-radius: .25rem; padding: .25rem; } +.non-existent-hypha__title { margin-bottom: 1rem; } +.non-existent-hypha__subtitle { margin: 0; } + .amnt-grid { display: grid; grid-template-columns: 1fr 1fr; } -.upload-binary__input { display: block; margin: .25rem 0; } +#upload-binary__input { display: block; margin: .25rem 0 .5rem 0; } .modal__title { font-size: 2rem; } .modal__title_small { font-size: 1.5rem; } @@ -157,6 +162,12 @@ header { width: 100%; margin-bottom: 1rem; } main { padding: 1rem; margin: 0; } } +@media screen and (min-width: 500px) { + .non-existent-hypha__way { flex: 1; margin-right: .5rem; } + .non-existent-hypha__ways { flex-direction: row; } + .non-existent-hypha__way:last-child { margin-right: 0; } +} + /* No longer a phone but still small screen: draw normal tabs, center main */ @media screen and (min-width: 801px) { .main-width { padding: 1rem 2rem; width: 800px; margin: 0 auto; } @@ -310,8 +321,13 @@ caption { caption-side: top; font-size: small; } .relative-hyphae__link { text-decoration: none; display: block; padding: .25rem .5rem; } +.btn { display: inline-block; border: 1px #999 solid; border-radius: .25rem; text-decoration: none; padding: .25rem; font-size: 1rem; } + /* Color stuff */ /* Lighter stuff #eee */ +.btn { background-color: #eee; color: black; } +.btn:visited { color: black; } + article code, article .codeblock, .transclusion, @@ -394,6 +410,7 @@ mark { background: rgba(130, 80, 30, 5); color: inherit; } @media screen and (max-width: 800px) { .hypha-tabs { background-color: #232323; } } + .btn { background-color: #ddd; color: black; } } diff --git a/assets/default.css b/assets/default.css index 96d6791..24f0a24 100644 --- a/assets/default.css +++ b/assets/default.css @@ -1,6 +1,11 @@ +.non-existent-hypha { } +.non-existent-hypha__ways { display: flex; flex-direction: column; width: 100%; margin: 0 0 1rem 0;} +.non-existent-hypha__way { border: 1px #999 solid; border-radius: .25rem; padding: .25rem; } +.non-existent-hypha__title { margin-bottom: 1rem; } +.non-existent-hypha__subtitle { margin: 0; } .amnt-grid { display: grid; grid-template-columns: 1fr 1fr; } -.upload-binary__input { display: block; margin: .25rem 0; } +#upload-binary__input { display: block; margin: .25rem 0 .5rem 0; } .modal__title { font-size: 2rem; } .modal__title_small { font-size: 1.5rem; } @@ -42,6 +47,12 @@ header { width: 100%; margin-bottom: 1rem; } main { padding: 1rem; margin: 0; } } +@media screen and (min-width: 500px) { + .non-existent-hypha__way { flex: 1; margin-right: .5rem; } + .non-existent-hypha__ways { flex-direction: row; } + .non-existent-hypha__way:last-child { margin-right: 0; } +} + /* No longer a phone but still small screen: draw normal tabs, center main */ @media screen and (min-width: 801px) { .main-width { padding: 1rem 2rem; width: 800px; margin: 0 auto; } @@ -195,8 +206,13 @@ caption { caption-side: top; font-size: small; } .relative-hyphae__link { text-decoration: none; display: block; padding: .25rem .5rem; } +.btn { display: inline-block; border: 1px #999 solid; border-radius: .25rem; text-decoration: none; padding: .25rem; font-size: 1rem; } + /* Color stuff */ /* Lighter stuff #eee */ +.btn { background-color: #eee; color: black; } +.btn:visited { color: black; } + article code, article .codeblock, .transclusion, @@ -279,6 +295,7 @@ mark { background: rgba(130, 80, 30, 5); color: inherit; } @media screen and (max-width: 800px) { .hypha-tabs { background-color: #232323; } } + .btn { background-color: #ddd; color: black; } } diff --git a/views/hypha.qtpl b/views/hypha.qtpl index b6d5f77..e514fdd 100644 --- a/views/hypha.qtpl +++ b/views/hypha.qtpl @@ -1,9 +1,47 @@ {% import "path/filepath" %} {% import "strings" %} + {% import "github.com/bouncepaw/mycorrhiza/cfg" %} {% import "github.com/bouncepaw/mycorrhiza/hyphae" %} +{% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/util" %} +{% func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User) %} +
    +

    This hypha does not exist

    + {% if user.AuthUsed && u.Group == "anon" %} +

    You are not authorized to create new hyphae. Here is what you can do:

    + + {% else %} + +
    +
    +

    📝 Write a text

    +

    Write a note, a diary, an article, a story or anything textual using Mycomarkup.

    +

    Make sure to follow this wiki's writing conventions if there are any.

    + Create +
    + +
    +

    🖼 Upload a media

    +

    Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.

    +
    + + + + +
    +
    +
    + {% endif %} +
    +{% endfunc %} + {% func NaviTitleHTML(h *hyphae.Hypha) %} {% code var ( diff --git a/views/hypha.qtpl.go b/views/hypha.qtpl.go index 9f6ad65..24824d3 100644 --- a/views/hypha.qtpl.go +++ b/views/hypha.qtpl.go @@ -10,227 +10,325 @@ import "path/filepath" //line views/hypha.qtpl:2 import "strings" -//line views/hypha.qtpl:3 +//line views/hypha.qtpl:4 import "github.com/bouncepaw/mycorrhiza/cfg" -//line views/hypha.qtpl:4 +//line views/hypha.qtpl:5 import "github.com/bouncepaw/mycorrhiza/hyphae" -//line views/hypha.qtpl:5 -import "github.com/bouncepaw/mycorrhiza/util" +//line views/hypha.qtpl:6 +import "github.com/bouncepaw/mycorrhiza/user" //line views/hypha.qtpl:7 +import "github.com/bouncepaw/mycorrhiza/util" + +//line views/hypha.qtpl:9 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/hypha.qtpl:7 +//line views/hypha.qtpl:9 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/hypha.qtpl:7 +//line views/hypha.qtpl:9 +func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u *user.User) { +//line views/hypha.qtpl:9 + qw422016.N().S(` +
    +

    This hypha does not exist

    + `) +//line views/hypha.qtpl:12 + if user.AuthUsed && u.Group == "anon" { +//line views/hypha.qtpl:12 + qw422016.N().S(` +

    You are not authorized to create new hyphae. Here is what you can do:

    + + `) +//line views/hypha.qtpl:18 + } else { +//line views/hypha.qtpl:18 + qw422016.N().S(` + +
    +
    +

    📝 Write a text

    +

    Write a note, a diary, an article, a story or anything textual using Mycomarkup.

    +

    Make sure to follow this wiki's writing conventions if there are any.

    + Create +
    + +
    +

    🖼 Upload a media

    +

    Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.

    +
    + + + + +
    +
    +
    + `) +//line views/hypha.qtpl:41 + } +//line views/hypha.qtpl:41 + qw422016.N().S(` +
    +`) +//line views/hypha.qtpl:43 +} + +//line views/hypha.qtpl:43 +func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h *hyphae.Hypha, u *user.User) { +//line views/hypha.qtpl:43 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/hypha.qtpl:43 + streamnonExistentHyphaNotice(qw422016, h, u) +//line views/hypha.qtpl:43 + qt422016.ReleaseWriter(qw422016) +//line views/hypha.qtpl:43 +} + +//line views/hypha.qtpl:43 +func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User) string { +//line views/hypha.qtpl:43 + qb422016 := qt422016.AcquireByteBuffer() +//line views/hypha.qtpl:43 + writenonExistentHyphaNotice(qb422016, h, u) +//line views/hypha.qtpl:43 + qs422016 := string(qb422016.B) +//line views/hypha.qtpl:43 + qt422016.ReleaseByteBuffer(qb422016) +//line views/hypha.qtpl:43 + return qs422016 +//line views/hypha.qtpl:43 +} + +//line views/hypha.qtpl:45 func StreamNaviTitleHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:7 +//line views/hypha.qtpl:45 qw422016.N().S(` `) -//line views/hypha.qtpl:9 +//line views/hypha.qtpl:47 var ( prevAcc = "/hypha/" parts = strings.Split(h.Name, "/") ) -//line views/hypha.qtpl:13 +//line views/hypha.qtpl:51 qw422016.N().S(`

    `) -//line views/hypha.qtpl:15 +//line views/hypha.qtpl:53 qw422016.N().S(``) -//line views/hypha.qtpl:17 +//line views/hypha.qtpl:55 qw422016.N().S(cfg.NaviTitleIcon) -//line views/hypha.qtpl:17 +//line views/hypha.qtpl:55 qw422016.N().S(``) -//line views/hypha.qtpl:21 +//line views/hypha.qtpl:59 for i, part := range parts { -//line views/hypha.qtpl:22 +//line views/hypha.qtpl:60 if i > 0 { -//line views/hypha.qtpl:22 +//line views/hypha.qtpl:60 qw422016.N().S(``) -//line views/hypha.qtpl:24 +//line views/hypha.qtpl:62 } -//line views/hypha.qtpl:24 +//line views/hypha.qtpl:62 qw422016.N().S(``) -//line views/hypha.qtpl:27 +//line views/hypha.qtpl:65 qw422016.N().S(util.BeautifulName(part)) -//line views/hypha.qtpl:27 +//line views/hypha.qtpl:65 qw422016.N().S(``) -//line views/hypha.qtpl:29 +//line views/hypha.qtpl:67 prevAcc += part + "/" -//line views/hypha.qtpl:30 +//line views/hypha.qtpl:68 } -//line views/hypha.qtpl:31 +//line views/hypha.qtpl:69 qw422016.N().S(`

    `) -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 } -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 func WriteNaviTitleHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 StreamNaviTitleHTML(qw422016, h) -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 qt422016.ReleaseWriter(qw422016) -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 } -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 func NaviTitleHTML(h *hyphae.Hypha) string { -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 qb422016 := qt422016.AcquireByteBuffer() -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 WriteNaviTitleHTML(qb422016, h) -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 qs422016 := string(qb422016.B) -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 qt422016.ReleaseByteBuffer(qb422016) -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 return qs422016 -//line views/hypha.qtpl:33 +//line views/hypha.qtpl:71 } -//line views/hypha.qtpl:35 +//line views/hypha.qtpl:73 func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:35 +//line views/hypha.qtpl:73 qw422016.N().S(` `) -//line views/hypha.qtpl:36 +//line views/hypha.qtpl:74 switch filepath.Ext(h.BinaryPath) { -//line views/hypha.qtpl:38 +//line views/hypha.qtpl:76 case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico": -//line views/hypha.qtpl:38 +//line views/hypha.qtpl:76 qw422016.N().S(`
    `) -//line views/hypha.qtpl:43 +//line views/hypha.qtpl:81 case ".ogg", ".webm", ".mp4": -//line views/hypha.qtpl:43 +//line views/hypha.qtpl:81 qw422016.N().S(`
    `) -//line views/hypha.qtpl:51 +//line views/hypha.qtpl:89 case ".mp3": -//line views/hypha.qtpl:51 +//line views/hypha.qtpl:89 qw422016.N().S(`
    `) -//line views/hypha.qtpl:59 +//line views/hypha.qtpl:97 default: -//line views/hypha.qtpl:59 +//line views/hypha.qtpl:97 qw422016.N().S(` `) -//line views/hypha.qtpl:63 +//line views/hypha.qtpl:101 } -//line views/hypha.qtpl:63 +//line views/hypha.qtpl:101 qw422016.N().S(` `) -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 } -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 StreamAttachmentHTML(qw422016, h) -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 qt422016.ReleaseWriter(qw422016) -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 } -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 func AttachmentHTML(h *hyphae.Hypha) string { -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 qb422016 := qt422016.AcquireByteBuffer() -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 WriteAttachmentHTML(qb422016, h) -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 qs422016 := string(qb422016.B) -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 qt422016.ReleaseByteBuffer(qb422016) -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 return qs422016 -//line views/hypha.qtpl:64 +//line views/hypha.qtpl:102 } diff --git a/views/readers.qtpl b/views/readers.qtpl index cf7c478..22c4ac8 100644 --- a/views/readers.qtpl +++ b/views/readers.qtpl @@ -75,26 +75,17 @@ If `contents` == "", a helpful message is shown instead. {% func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) %} {% code relatives, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name) + u := user.FromRequest(rq) %} {%= NavHTML(rq, h.Name, "page") %}
    {%s= NaviTitleHTML(h) %} - {% if contents == "" %} -

    This hypha has no text. Why not create it?

    - {% if u := user.FromRequest(rq); (!user.AuthUsed || u.Group != "anon") && !h.Exists %} -
    - - - -
    -
    - {% endif %} - {% else %} + {% if h.Exists %} {%s= contents %} + {% else %} + {%= nonExistentHyphaNotice(h, u) %} {% endif %}
    diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index ef9c851..bba5bba 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -230,220 +230,199 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hyph `) //line views/readers.qtpl:77 relatives, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name) + u := user.FromRequest(rq) -//line views/readers.qtpl:78 +//line views/readers.qtpl:79 qw422016.N().S(` `) -//line views/readers.qtpl:79 +//line views/readers.qtpl:80 StreamNavHTML(qw422016, rq, h.Name, "page") -//line views/readers.qtpl:79 +//line views/readers.qtpl:80 qw422016.N().S(`
    `) -//line views/readers.qtpl:83 +//line views/readers.qtpl:84 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:83 +//line views/readers.qtpl:84 qw422016.N().S(` `) -//line views/readers.qtpl:84 - if contents == "" { -//line views/readers.qtpl:84 - qw422016.N().S(` -

    This hypha has no text. Why not create it?

    - `) -//line views/readers.qtpl:86 - if u := user.FromRequest(rq); (!user.AuthUsed || u.Group != "anon") && !h.Exists { -//line views/readers.qtpl:86 - qw422016.N().S(` -
    - - - -
    -
    - `) -//line views/readers.qtpl:95 - } -//line views/readers.qtpl:95 - qw422016.N().S(` - `) -//line views/readers.qtpl:96 - } else { -//line views/readers.qtpl:96 qw422016.N().S(` `) -//line views/readers.qtpl:97 +//line views/readers.qtpl:86 qw422016.N().S(contents) -//line views/readers.qtpl:97 +//line views/readers.qtpl:86 qw422016.N().S(` `) -//line views/readers.qtpl:98 +//line views/readers.qtpl:87 + } else { +//line views/readers.qtpl:87 + qw422016.N().S(` + `) +//line views/readers.qtpl:88 + streamnonExistentHyphaNotice(qw422016, h, u) +//line views/readers.qtpl:88 + qw422016.N().S(` + `) +//line views/readers.qtpl:89 } -//line views/readers.qtpl:98 +//line views/readers.qtpl:89 qw422016.N().S(`
    `) -//line views/readers.qtpl:101 +//line views/readers.qtpl:92 if prevHyphaName != "" { -//line views/readers.qtpl:101 +//line views/readers.qtpl:92 qw422016.N().S(` `) -//line views/readers.qtpl:103 +//line views/readers.qtpl:94 } -//line views/readers.qtpl:103 +//line views/readers.qtpl:94 qw422016.N().S(` `) -//line views/readers.qtpl:104 +//line views/readers.qtpl:95 if nextHyphaName != "" { -//line views/readers.qtpl:104 +//line views/readers.qtpl:95 qw422016.N().S(` `) -//line views/readers.qtpl:106 +//line views/readers.qtpl:97 } -//line views/readers.qtpl:106 +//line views/readers.qtpl:97 qw422016.N().S(`
    `) -//line views/readers.qtpl:108 +//line views/readers.qtpl:99 StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:108 +//line views/readers.qtpl:99 qw422016.N().S(`
    `) -//line views/readers.qtpl:110 +//line views/readers.qtpl:101 StreamRelativeHyphaeHTML(qw422016, relatives) -//line views/readers.qtpl:110 +//line views/readers.qtpl:101 qw422016.N().S(`
    `) -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 } -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 StreamHyphaHTML(qw422016, rq, h, contents) -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 } -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) string { -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 WriteHyphaHTML(qb422016, rq, h, contents) -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 qs422016 := string(qb422016.B) -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 return qs422016 -//line views/readers.qtpl:112 +//line views/readers.qtpl:103 } -//line views/readers.qtpl:114 +//line views/readers.qtpl:105 func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:114 +//line views/readers.qtpl:105 qw422016.N().S(` `) -//line views/readers.qtpl:116 +//line views/readers.qtpl:107 relatives, subhyphae, _, _ := tree.Tree(h.Name) -//line views/readers.qtpl:117 +//line views/readers.qtpl:108 qw422016.N().S(` `) -//line views/readers.qtpl:118 +//line views/readers.qtpl:109 StreamNavHTML(qw422016, rq, h.Name, "revision", revHash) -//line views/readers.qtpl:118 +//line views/readers.qtpl:109 qw422016.N().S(`

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

    `) -//line views/readers.qtpl:123 +//line views/readers.qtpl:114 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:123 +//line views/readers.qtpl:114 qw422016.N().S(` `) -//line views/readers.qtpl:124 +//line views/readers.qtpl:115 qw422016.N().S(contents) -//line views/readers.qtpl:124 +//line views/readers.qtpl:115 qw422016.N().S(`
    `) -//line views/readers.qtpl:126 +//line views/readers.qtpl:117 StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:126 +//line views/readers.qtpl:117 qw422016.N().S(`
    `) -//line views/readers.qtpl:128 +//line views/readers.qtpl:119 StreamRelativeHyphaeHTML(qw422016, relatives) -//line views/readers.qtpl:128 +//line views/readers.qtpl:119 qw422016.N().S(`
    `) -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 } -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 StreamRevisionHTML(qw422016, rq, h, contents, revHash) -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 } -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) string { -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 WriteRevisionHTML(qb422016, rq, h, contents, revHash) -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 qs422016 := string(qb422016.B) -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 return qs422016 -//line views/readers.qtpl:130 +//line views/readers.qtpl:121 } From f7b4ec938e4f9100e44cac8ab5a6b1cbaf68f15a Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Fri, 14 May 2021 14:24:31 +0500 Subject: [PATCH 19/41] Make new hypha notice's buttons dark in the dark theme --- assets/assets.qtpl.go | 5 ++++- assets/default.css | 5 ++++- views/hypha.qtpl | 4 ++-- views/hypha.qtpl.go | 4 ++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index aef5d36..2cbf0bd 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -394,6 +394,8 @@ a:visited, .wikilink_external:visited { color: #ffb86c; } blockquote { border-left: 4px #ddd solid; } .transclusion .transclusion__link { color: #ddd; } + +.btn, article code, article .codeblock, .transclusion, @@ -404,13 +406,14 @@ article .codeblock, .upload-amnt, textarea, table { border: 0; background-color: #444444; color: #ddd; } +.btn:visited { color: #ddd;} + .transclusion code, .transclusion .codeblock { background-color: #454545; } mark { background: rgba(130, 80, 30, 5); color: inherit; } @media screen and (max-width: 800px) { .hypha-tabs { background-color: #232323; } } - .btn { background-color: #ddd; color: black; } } diff --git a/assets/default.css b/assets/default.css index 24f0a24..696b0cd 100644 --- a/assets/default.css +++ b/assets/default.css @@ -279,6 +279,8 @@ a:visited, .wikilink_external:visited { color: #ffb86c; } blockquote { border-left: 4px #ddd solid; } .transclusion .transclusion__link { color: #ddd; } + +.btn, article code, article .codeblock, .transclusion, @@ -289,13 +291,14 @@ article .codeblock, .upload-amnt, textarea, table { border: 0; background-color: #444444; color: #ddd; } +.btn:visited { color: #ddd;} + .transclusion code, .transclusion .codeblock { background-color: #454545; } mark { background: rgba(130, 80, 30, 5); color: inherit; } @media screen and (max-width: 800px) { .hypha-tabs { background-color: #232323; } } - .btn { background-color: #ddd; color: black; } } diff --git a/views/hypha.qtpl b/views/hypha.qtpl index e514fdd..d611049 100644 --- a/views/hypha.qtpl +++ b/views/hypha.qtpl @@ -22,7 +22,7 @@

    📝 Write a text

    Write a note, a diary, an article, a story or anything textual using Mycomarkup.

    Make sure to follow this wiki's writing conventions if there are any.

    - Create + Create
    @@ -34,7 +34,7 @@ - +
    diff --git a/views/hypha.qtpl.go b/views/hypha.qtpl.go index 24824d3..042cfb8 100644 --- a/views/hypha.qtpl.go +++ b/views/hypha.qtpl.go @@ -70,7 +70,7 @@ func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u

    📝 Write a text

    Write a note, a diary, an article, a story or anything textual using Mycomarkup.

    Make sure to follow this wiki's writing conventions if there are any.

    - - + From 1d1b5af50bb4f465d676f8ecf3b091cb311ede38 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Fri, 14 May 2021 14:31:47 +0500 Subject: [PATCH 20/41] Make the finishing touches on the non-existent hypha notice --- assets/assets.qtpl.go | 7 ++++--- assets/default.css | 7 ++++--- views/hypha.qtpl | 2 +- views/hypha.qtpl.go | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 2cbf0bd..c265a2f 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -320,12 +320,12 @@ caption { caption-side: top; font-size: small; } .relative-hyphae__entry_this { padding: .25rem .5rem; font-weight: bold; } .relative-hyphae__link { text-decoration: none; display: block; padding: .25rem .5rem; } - -.btn { display: inline-block; border: 1px #999 solid; border-radius: .25rem; text-decoration: none; padding: .25rem; font-size: 1rem; } +::-webkit-file-upload-button, +.btn { display: inline-block; border: 1px #999 solid; border-radius: .25rem; text-decoration: none; padding: .25rem; font-size: 1rem; margin: 0; } /* Color stuff */ /* Lighter stuff #eee */ -.btn { background-color: #eee; color: black; } +::-webkit-file-upload-button, .btn { background-color: #eee; color: black; } .btn:visited { color: black; } article code, @@ -395,6 +395,7 @@ blockquote { border-left: 4px #ddd solid; } .transclusion .transclusion__link { color: #ddd; } +::-webkit-file-upload-button, .btn, article code, article .codeblock, diff --git a/assets/default.css b/assets/default.css index 696b0cd..c44b911 100644 --- a/assets/default.css +++ b/assets/default.css @@ -205,12 +205,12 @@ caption { caption-side: top; font-size: small; } .relative-hyphae__entry_this { padding: .25rem .5rem; font-weight: bold; } .relative-hyphae__link { text-decoration: none; display: block; padding: .25rem .5rem; } - -.btn { display: inline-block; border: 1px #999 solid; border-radius: .25rem; text-decoration: none; padding: .25rem; font-size: 1rem; } +::-webkit-file-upload-button, +.btn { display: inline-block; border: 1px #999 solid; border-radius: .25rem; text-decoration: none; padding: .25rem; font-size: 1rem; margin: 0; } /* Color stuff */ /* Lighter stuff #eee */ -.btn { background-color: #eee; color: black; } +::-webkit-file-upload-button, .btn { background-color: #eee; color: black; } .btn:visited { color: black; } article code, @@ -280,6 +280,7 @@ blockquote { border-left: 4px #ddd solid; } .transclusion .transclusion__link { color: #ddd; } +::-webkit-file-upload-button, .btn, article code, article .codeblock, diff --git a/views/hypha.qtpl b/views/hypha.qtpl index d611049..a814216 100644 --- a/views/hypha.qtpl +++ b/views/hypha.qtpl @@ -20,7 +20,7 @@

    📝 Write a text

    -

    Write a note, a diary, an article, a story or anything textual using Mycomarkup.

    +

    Write a note, a diary, an article, a story or anything textual using Mycomarkup. Full history of edits to the document will be saved.

    Make sure to follow this wiki's writing conventions if there are any.

    Create
    diff --git a/views/hypha.qtpl.go b/views/hypha.qtpl.go index 042cfb8..a942fc8 100644 --- a/views/hypha.qtpl.go +++ b/views/hypha.qtpl.go @@ -68,7 +68,7 @@ func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u

    📝 Write a text

    -

    Write a note, a diary, an article, a story or anything textual using Mycomarkup.

    +

    Write a note, a diary, an article, a story or anything textual using Mycomarkup. Full history of edits to the document will be saved.

    Make sure to follow this wiki's writing conventions if there are any.

    The server stores your password in an encrypted form; even administrators cannot read it.

    By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.

    - -
    Cancel + + Cancel {% elseif cfg.UseFixedAuth %}

    Administrators have forbidden registration for this wiki. Administrators can make an account for you by hand; contact them.

    -

    ← Go back

    +

    ← Go back

    {% else %}

    Administrators of this wiki have not configured any authorization method. You can make edits anonymously.

    -

    ← Go back

    +

    ← Go back

    {% endif %}
    @@ -44,7 +44,6 @@ {% else %} diff --git a/views/auth.qtpl.go b/views/auth.qtpl.go index 104516b..b1120cd 100644 --- a/views/auth.qtpl.go +++ b/views/auth.qtpl.go @@ -59,8 +59,12 @@ func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) {

    The server stores your password in an encrypted form; even administrators cannot read it.

    By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.

    - - Cancel + + Cancel `) @@ -69,7 +73,7 @@ func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) { //line views/auth.qtpl:27 qw422016.N().S(`

    Administrators have forbidden registration for this wiki. Administrators can make an account for you by hand; contact them.

    -

    Administrators of this wiki have not configured any authorization method. You can make edits anonymously.

    -

    -

    Use the data you were given by an administrator.


    @@ -151,182 +154,182 @@ func StreamLoginHTML(qw422016 *qt422016.Writer) {

    By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.

    - -
    Cancel + + Cancel `) -//line views/auth.qtpl:60 +//line views/auth.qtpl:59 } else { -//line views/auth.qtpl:60 +//line views/auth.qtpl:59 qw422016.N().S(`

    Administrators of this wiki have not configured any authorization method. You can make edits anonymously.

    ← Go home

    `) -//line views/auth.qtpl:63 +//line views/auth.qtpl:62 } -//line views/auth.qtpl:63 +//line views/auth.qtpl:62 qw422016.N().S(`
    `) -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 } -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 func WriteLoginHTML(qq422016 qtio422016.Writer) { -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 StreamLoginHTML(qw422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 } -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 func LoginHTML() string { -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 WriteLoginHTML(qb422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 qs422016 := string(qb422016.B) -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 return qs422016 -//line views/auth.qtpl:67 +//line views/auth.qtpl:66 } -//line views/auth.qtpl:69 +//line views/auth.qtpl:68 func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) { -//line views/auth.qtpl:69 +//line views/auth.qtpl:68 qw422016.N().S(`
    `) -//line views/auth.qtpl:73 +//line views/auth.qtpl:72 switch err { -//line views/auth.qtpl:74 +//line views/auth.qtpl:73 case "unknown username": -//line views/auth.qtpl:74 +//line views/auth.qtpl:73 qw422016.N().S(`

    Unknown username.

    `) -//line views/auth.qtpl:76 +//line views/auth.qtpl:75 case "wrong password": -//line views/auth.qtpl:76 +//line views/auth.qtpl:75 qw422016.N().S(`

    Wrong password.

    `) -//line views/auth.qtpl:78 +//line views/auth.qtpl:77 default: -//line views/auth.qtpl:78 +//line views/auth.qtpl:77 qw422016.N().S(`

    `) -//line views/auth.qtpl:79 +//line views/auth.qtpl:78 qw422016.E().S(err) -//line views/auth.qtpl:79 +//line views/auth.qtpl:78 qw422016.N().S(`

    `) -//line views/auth.qtpl:80 +//line views/auth.qtpl:79 } -//line views/auth.qtpl:80 +//line views/auth.qtpl:79 qw422016.N().S(`

    ← Try again

    `) -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 } -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) { -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 StreamLoginErrorHTML(qw422016, err) -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 } -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 func LoginErrorHTML(err string) string { -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 WriteLoginErrorHTML(qb422016, err) -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 qs422016 := string(qb422016.B) -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 return qs422016 -//line views/auth.qtpl:85 +//line views/auth.qtpl:84 } -//line views/auth.qtpl:87 +//line views/auth.qtpl:86 func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) { -//line views/auth.qtpl:87 +//line views/auth.qtpl:86 qw422016.N().S(`
    `) -//line views/auth.qtpl:91 +//line views/auth.qtpl:90 if can { -//line views/auth.qtpl:91 +//line views/auth.qtpl:90 qw422016.N().S(`

    Log out?

    Confirm

    Cancel

    `) -//line views/auth.qtpl:95 +//line views/auth.qtpl:94 } else { -//line views/auth.qtpl:95 +//line views/auth.qtpl:94 qw422016.N().S(`

    You cannot log out because you are not logged in.

    Login

    ← Home

    `) -//line views/auth.qtpl:99 +//line views/auth.qtpl:98 } -//line views/auth.qtpl:99 +//line views/auth.qtpl:98 qw422016.N().S(`
    `) -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 } -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) { -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 StreamLogoutHTML(qw422016, can) -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 } -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 func LogoutHTML(can bool) string { -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 WriteLogoutHTML(qb422016, can) -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 qs422016 := string(qb422016.B) -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 return qs422016 -//line views/auth.qtpl:103 +//line views/auth.qtpl:102 } From 77d1cf500998e7408eeb190f9c082bb579a3d120 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sun, 16 May 2021 13:47:44 +0500 Subject: [PATCH 23/41] Add the registration link to the top bar --- assets/assets.qtpl.go | 2 +- assets/default.css | 2 +- views/nav.qtpl | 20 ++-- views/nav.qtpl.go | 250 ++++++++++++++++++++++-------------------- 4 files changed, 148 insertions(+), 126 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 0c97fe2..2503ba3 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -143,7 +143,7 @@ header { width: 100%; margin-bottom: 1rem; } .header-links__entry, .hypha-tabs__tab { list-style-type: none; } .header-links__entry { margin-right: .5rem; } -.header-links__entry_user { font-style:italic; } +.header-links__entry_user, .header-links__entry_register { font-style:italic; } .header-links__link { display: inline-block; padding: .25rem; text-decoration: none; } .hypha-tabs { padding: 0; margin: 0; } diff --git a/assets/default.css b/assets/default.css index c9950ea..ab9534a 100644 --- a/assets/default.css +++ b/assets/default.css @@ -28,7 +28,7 @@ header { width: 100%; margin-bottom: 1rem; } .header-links__entry, .hypha-tabs__tab { list-style-type: none; } .header-links__entry { margin-right: .5rem; } -.header-links__entry_user { font-style:italic; } +.header-links__entry_user, .header-links__entry_register { font-style:italic; } .header-links__link { display: inline-block; padding: .25rem; text-decoration: none; } .hypha-tabs { padding: 0; margin: 0; } diff --git a/views/nav.qtpl b/views/nav.qtpl index 0f8e0b7..eaad97e 100644 --- a/views/nav.qtpl +++ b/views/nav.qtpl @@ -2,6 +2,7 @@ {% import "strings" %} {% import "github.com/bouncepaw/mycorrhiza/cfg" %} {% import "github.com/bouncepaw/mycorrhiza/user" %} +{% import "github.com/bouncepaw/mycorrhiza/util" %} This is the
    +{%= editScripts() %} {% endfunc %} {% func PreviewHTML(rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) %} @@ -104,4 +107,11 @@ {%s= Toolbar(user.FromRequest(rq)) %} +{%= editScripts() %} {% endfunc %} + +{% func editScripts() %} +{% for _, scriptPath := range cfg.EditScripts %} + +{% endfor %} +{% endfunc %} \ No newline at end of file diff --git a/views/mutators.qtpl.go b/views/mutators.qtpl.go index 0629b0c..035dbc8 100644 --- a/views/mutators.qtpl.go +++ b/views/mutators.qtpl.go @@ -7,34 +7,37 @@ package views //line views/mutators.qtpl:1 import "net/http" -//line views/mutators.qtpl:2 +//line views/mutators.qtpl:3 +import "github.com/bouncepaw/mycorrhiza/cfg" + +//line views/mutators.qtpl:4 import "github.com/bouncepaw/mycorrhiza/util" -//line views/mutators.qtpl:3 +//line views/mutators.qtpl:5 import "github.com/bouncepaw/mycorrhiza/user" -//line views/mutators.qtpl:5 +//line views/mutators.qtpl:7 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/mutators.qtpl:5 +//line views/mutators.qtpl:7 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/mutators.qtpl:5 +//line views/mutators.qtpl:7 func StreamToolbar(qw422016 *qt422016.Writer, u *user.User) { -//line views/mutators.qtpl:5 +//line views/mutators.qtpl:7 qw422016.N().S(` `) -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 } -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 func WriteToolbar(qq422016 qtio422016.Writer, u *user.User) { -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 StreamToolbar(qw422016, u) -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 qt422016.ReleaseWriter(qw422016) -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 } -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 func Toolbar(u *user.User) string { -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 qb422016 := qt422016.AcquireByteBuffer() -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 WriteToolbar(qb422016, u) -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 qs422016 := string(qb422016.B) -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 qt422016.ReleaseByteBuffer(qb422016) -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 return qs422016 -//line views/mutators.qtpl:67 +//line views/mutators.qtpl:69 } -//line views/mutators.qtpl:69 +//line views/mutators.qtpl:71 func StreamEditHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string) { -//line views/mutators.qtpl:69 +//line views/mutators.qtpl:71 qw422016.N().S(` `) -//line views/mutators.qtpl:70 +//line views/mutators.qtpl:72 qw422016.N().S(NavHTML(rq, hyphaName, "edit")) -//line views/mutators.qtpl:70 +//line views/mutators.qtpl:72 qw422016.N().S(`

    Edit `) -//line views/mutators.qtpl:73 +//line views/mutators.qtpl:75 qw422016.E().S(util.BeautifulName(hyphaName)) -//line views/mutators.qtpl:73 +//line views/mutators.qtpl:75 qw422016.N().S(`

    `) -//line views/mutators.qtpl:74 +//line views/mutators.qtpl:76 qw422016.N().S(warning) -//line views/mutators.qtpl:74 +//line views/mutators.qtpl:76 qw422016.N().S(`

    Cancel
    `) -//line views/mutators.qtpl:84 +//line views/mutators.qtpl:86 qw422016.N().S(Toolbar(user.FromRequest(rq))) -//line views/mutators.qtpl:84 +//line views/mutators.qtpl:86 qw422016.N().S(`
    `) -//line views/mutators.qtpl:86 -} - -//line views/mutators.qtpl:86 -func WriteEditHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string) { -//line views/mutators.qtpl:86 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/mutators.qtpl:86 - StreamEditHTML(qw422016, rq, hyphaName, textAreaFill, warning) -//line views/mutators.qtpl:86 - qt422016.ReleaseWriter(qw422016) -//line views/mutators.qtpl:86 -} - -//line views/mutators.qtpl:86 -func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) string { -//line views/mutators.qtpl:86 - qb422016 := qt422016.AcquireByteBuffer() -//line views/mutators.qtpl:86 - WriteEditHTML(qb422016, rq, hyphaName, textAreaFill, warning) -//line views/mutators.qtpl:86 - qs422016 := string(qb422016.B) -//line views/mutators.qtpl:86 - qt422016.ReleaseByteBuffer(qb422016) -//line views/mutators.qtpl:86 - return qs422016 -//line views/mutators.qtpl:86 -} - //line views/mutators.qtpl:88 -func StreamPreviewHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) { + streameditScripts(qw422016) //line views/mutators.qtpl:88 qw422016.N().S(` `) //line views/mutators.qtpl:89 - qw422016.N().S(NavHTML(rq, hyphaName, "edit")) +} + //line views/mutators.qtpl:89 +func WriteEditHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string) { +//line views/mutators.qtpl:89 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/mutators.qtpl:89 + StreamEditHTML(qw422016, rq, hyphaName, textAreaFill, warning) +//line views/mutators.qtpl:89 + qt422016.ReleaseWriter(qw422016) +//line views/mutators.qtpl:89 +} + +//line views/mutators.qtpl:89 +func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) string { +//line views/mutators.qtpl:89 + qb422016 := qt422016.AcquireByteBuffer() +//line views/mutators.qtpl:89 + WriteEditHTML(qb422016, rq, hyphaName, textAreaFill, warning) +//line views/mutators.qtpl:89 + qs422016 := string(qb422016.B) +//line views/mutators.qtpl:89 + qt422016.ReleaseByteBuffer(qb422016) +//line views/mutators.qtpl:89 + return qs422016 +//line views/mutators.qtpl:89 +} + +//line views/mutators.qtpl:91 +func StreamPreviewHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) { +//line views/mutators.qtpl:91 + qw422016.N().S(` +`) +//line views/mutators.qtpl:92 + qw422016.N().S(NavHTML(rq, hyphaName, "edit")) +//line views/mutators.qtpl:92 qw422016.N().S(`

    Edit `) -//line views/mutators.qtpl:92 +//line views/mutators.qtpl:95 qw422016.E().S(util.BeautifulName(hyphaName)) -//line views/mutators.qtpl:92 +//line views/mutators.qtpl:95 qw422016.N().S(` (preview)

    `) -//line views/mutators.qtpl:93 +//line views/mutators.qtpl:96 qw422016.N().S(warning) -//line views/mutators.qtpl:93 +//line views/mutators.qtpl:96 qw422016.N().S(`

    Cancel

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

    `) -//line views/mutators.qtpl:103 +//line views/mutators.qtpl:106 qw422016.N().S(renderedPage) -//line views/mutators.qtpl:103 +//line views/mutators.qtpl:106 qw422016.N().S(`
    `) -//line views/mutators.qtpl:105 +//line views/mutators.qtpl:108 qw422016.N().S(Toolbar(user.FromRequest(rq))) -//line views/mutators.qtpl:105 +//line views/mutators.qtpl:108 qw422016.N().S(`
    `) -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:110 + streameditScripts(qw422016) +//line views/mutators.qtpl:110 + qw422016.N().S(` +`) +//line views/mutators.qtpl:111 } -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 func WritePreviewHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) { -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 StreamPreviewHTML(qw422016, rq, hyphaName, textAreaFill, warning, renderedPage) -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 qt422016.ReleaseWriter(qw422016) -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 } -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 func PreviewHTML(rq *http.Request, hyphaName, textAreaFill, warning string, renderedPage string) string { -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 qb422016 := qt422016.AcquireByteBuffer() -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 WritePreviewHTML(qb422016, rq, hyphaName, textAreaFill, warning, renderedPage) -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 qs422016 := string(qb422016.B) -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 qt422016.ReleaseByteBuffer(qb422016) -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 return qs422016 -//line views/mutators.qtpl:107 +//line views/mutators.qtpl:111 +} + +//line views/mutators.qtpl:113 +func streameditScripts(qw422016 *qt422016.Writer) { +//line views/mutators.qtpl:113 + qw422016.N().S(` +`) +//line views/mutators.qtpl:114 + for _, scriptPath := range cfg.EditScripts { +//line views/mutators.qtpl:114 + qw422016.N().S(` + +`) +//line views/mutators.qtpl:116 + } +//line views/mutators.qtpl:116 + qw422016.N().S(` +`) +//line views/mutators.qtpl:117 +} + +//line views/mutators.qtpl:117 +func writeeditScripts(qq422016 qtio422016.Writer) { +//line views/mutators.qtpl:117 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/mutators.qtpl:117 + streameditScripts(qw422016) +//line views/mutators.qtpl:117 + qt422016.ReleaseWriter(qw422016) +//line views/mutators.qtpl:117 +} + +//line views/mutators.qtpl:117 +func editScripts() string { +//line views/mutators.qtpl:117 + qb422016 := qt422016.AcquireByteBuffer() +//line views/mutators.qtpl:117 + writeeditScripts(qb422016) +//line views/mutators.qtpl:117 + qs422016 := string(qb422016.B) +//line views/mutators.qtpl:117 + qt422016.ReleaseByteBuffer(qb422016) +//line views/mutators.qtpl:117 + return qs422016 +//line views/mutators.qtpl:117 } diff --git a/views/readers.qtpl b/views/readers.qtpl index 22c4ac8..34f861d 100644 --- a/views/readers.qtpl +++ b/views/readers.qtpl @@ -3,6 +3,7 @@ {% import "path" %} {% import "os" %} +{% import "github.com/bouncepaw/mycorrhiza/cfg" %} {% import "github.com/bouncepaw/mycorrhiza/hyphae" %} {% import "github.com/bouncepaw/mycorrhiza/mimetype" %} {% import "github.com/bouncepaw/mycorrhiza/tree" %} @@ -100,6 +101,7 @@ If `contents` == "", a helpful message is shown instead. {%= RelativeHyphaeHTML(relatives) %} +{%= viewScripts() %} {% endfunc %} {% func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) %} @@ -118,4 +120,11 @@ If `contents` == "", a helpful message is shown instead. {%= RelativeHyphaeHTML(relatives) %} +{%= viewScripts() %} {% endfunc %} + +{% func viewScripts() %} +{% for _, scriptPath := range cfg.ViewScripts %} + +{% endfor %} +{% endfunc %} \ No newline at end of file diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index bba5bba..10a98ed 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -17,139 +17,142 @@ import "path" import "os" //line views/readers.qtpl:6 -import "github.com/bouncepaw/mycorrhiza/hyphae" +import "github.com/bouncepaw/mycorrhiza/cfg" //line views/readers.qtpl:7 -import "github.com/bouncepaw/mycorrhiza/mimetype" +import "github.com/bouncepaw/mycorrhiza/hyphae" //line views/readers.qtpl:8 -import "github.com/bouncepaw/mycorrhiza/tree" +import "github.com/bouncepaw/mycorrhiza/mimetype" //line views/readers.qtpl:9 -import "github.com/bouncepaw/mycorrhiza/user" +import "github.com/bouncepaw/mycorrhiza/tree" //line views/readers.qtpl:10 +import "github.com/bouncepaw/mycorrhiza/user" + +//line views/readers.qtpl:11 import "github.com/bouncepaw/mycorrhiza/util" -//line views/readers.qtpl:12 +//line views/readers.qtpl:13 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/readers.qtpl:12 +//line views/readers.qtpl:13 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/readers.qtpl:12 +//line views/readers.qtpl:13 func StreamAttachmentMenuHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User) { -//line views/readers.qtpl:12 +//line views/readers.qtpl:13 qw422016.N().S(` `) -//line views/readers.qtpl:13 +//line views/readers.qtpl:14 StreamNavHTML(qw422016, rq, h.Name, "attachment") -//line views/readers.qtpl:13 +//line views/readers.qtpl:14 qw422016.N().S(`

    Attachment of `) -//line views/readers.qtpl:16 +//line views/readers.qtpl:17 qw422016.E().S(util.BeautifulName(h.Name)) -//line views/readers.qtpl:16 +//line views/readers.qtpl:17 qw422016.N().S(`

    `) -//line views/readers.qtpl:17 +//line views/readers.qtpl:18 if h.BinaryPath == "" { -//line views/readers.qtpl:17 +//line views/readers.qtpl:18 qw422016.N().S(`

    This hypha has no attachment, you can upload it here.

    `) -//line views/readers.qtpl:19 +//line views/readers.qtpl:20 } else { -//line views/readers.qtpl:19 +//line views/readers.qtpl:20 qw422016.N().S(`

    You can manage the hypha's attachment on this page.

    `) -//line views/readers.qtpl:21 +//line views/readers.qtpl:22 } -//line views/readers.qtpl:21 +//line views/readers.qtpl:22 qw422016.N().S(`
    `) -//line views/readers.qtpl:25 +//line views/readers.qtpl:26 if h.BinaryPath != "" { -//line views/readers.qtpl:25 +//line views/readers.qtpl:26 qw422016.N().S(` `) -//line views/readers.qtpl:27 +//line views/readers.qtpl:28 mime := mimetype.FromExtension(path.Ext(h.BinaryPath)) fileinfo, err := os.Stat(h.BinaryPath) -//line views/readers.qtpl:28 +//line views/readers.qtpl:29 qw422016.N().S(` `) -//line views/readers.qtpl:29 +//line views/readers.qtpl:30 if err == nil { -//line views/readers.qtpl:29 +//line views/readers.qtpl:30 qw422016.N().S(`
    Stat

    MIME type: `) -//line views/readers.qtpl:33 +//line views/readers.qtpl:34 qw422016.E().S(mime) -//line views/readers.qtpl:33 +//line views/readers.qtpl:34 qw422016.N().S(`

    `) -//line views/readers.qtpl:35 +//line views/readers.qtpl:36 } -//line views/readers.qtpl:35 +//line views/readers.qtpl:36 qw422016.N().S(` `) -//line views/readers.qtpl:37 +//line views/readers.qtpl:38 if strings.HasPrefix(mime, "image/") { -//line views/readers.qtpl:37 +//line views/readers.qtpl:38 qw422016.N().S(`
    Include
    img { `)
    -//line views/readers.qtpl:41
    +//line views/readers.qtpl:42
     			qw422016.E().S(h.Name)
    -//line views/readers.qtpl:41
    +//line views/readers.qtpl:42
     			qw422016.N().S(` }
    `) -//line views/readers.qtpl:43 +//line views/readers.qtpl:44 } -//line views/readers.qtpl:43 +//line views/readers.qtpl:44 qw422016.N().S(` `) -//line views/readers.qtpl:44 +//line views/readers.qtpl:45 } -//line views/readers.qtpl:44 +//line views/readers.qtpl:45 qw422016.N().S(` `) -//line views/readers.qtpl:46 +//line views/readers.qtpl:47 if u.CanProceed("upload-binary") { -//line views/readers.qtpl:46 +//line views/readers.qtpl:47 qw422016.N().S(` `) -//line views/readers.qtpl:57 +//line views/readers.qtpl:58 } -//line views/readers.qtpl:57 +//line views/readers.qtpl:58 qw422016.N().S(` `) -//line views/readers.qtpl:59 +//line views/readers.qtpl:60 if h.BinaryPath != "" && u.CanProceed("unattach-confirm") { -//line views/readers.qtpl:59 +//line views/readers.qtpl:60 qw422016.N().S(` `) -//line views/readers.qtpl:67 +//line views/readers.qtpl:68 } -//line views/readers.qtpl:67 +//line views/readers.qtpl:68 qw422016.N().S(`
    `) -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 } -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 func WriteAttachmentMenuHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User) { -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 StreamAttachmentMenuHTML(qw422016, rq, h, u) -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 } -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 func AttachmentMenuHTML(rq *http.Request, h *hyphae.Hypha, u *user.User) string { -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 WriteAttachmentMenuHTML(qb422016, rq, h, u) -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 qs422016 := string(qb422016.B) -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 return qs422016 -//line views/readers.qtpl:72 +//line views/readers.qtpl:73 } // If `contents` == "", a helpful message is shown instead. -//line views/readers.qtpl:75 +//line views/readers.qtpl:76 func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:75 +//line views/readers.qtpl:76 qw422016.N().S(` `) -//line views/readers.qtpl:77 +//line views/readers.qtpl:78 relatives, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name) u := user.FromRequest(rq) -//line views/readers.qtpl:79 +//line views/readers.qtpl:80 qw422016.N().S(` `) -//line views/readers.qtpl:80 +//line views/readers.qtpl:81 StreamNavHTML(qw422016, rq, h.Name, "page") -//line views/readers.qtpl:80 +//line views/readers.qtpl:81 qw422016.N().S(`
    `) -//line views/readers.qtpl:84 +//line views/readers.qtpl:85 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:84 +//line views/readers.qtpl:85 qw422016.N().S(` `) -//line views/readers.qtpl:85 +//line views/readers.qtpl:86 if h.Exists { -//line views/readers.qtpl:85 +//line views/readers.qtpl:86 qw422016.N().S(` `) -//line views/readers.qtpl:86 +//line views/readers.qtpl:87 qw422016.N().S(contents) -//line views/readers.qtpl:86 +//line views/readers.qtpl:87 qw422016.N().S(` `) -//line views/readers.qtpl:87 +//line views/readers.qtpl:88 } else { -//line views/readers.qtpl:87 +//line views/readers.qtpl:88 qw422016.N().S(` `) -//line views/readers.qtpl:88 +//line views/readers.qtpl:89 streamnonExistentHyphaNotice(qw422016, h, u) -//line views/readers.qtpl:88 +//line views/readers.qtpl:89 qw422016.N().S(` `) -//line views/readers.qtpl:89 +//line views/readers.qtpl:90 } -//line views/readers.qtpl:89 +//line views/readers.qtpl:90 qw422016.N().S(`
    `) -//line views/readers.qtpl:92 +//line views/readers.qtpl:93 if prevHyphaName != "" { -//line views/readers.qtpl:92 +//line views/readers.qtpl:93 qw422016.N().S(` `) -//line views/readers.qtpl:94 +//line views/readers.qtpl:95 } -//line views/readers.qtpl:94 +//line views/readers.qtpl:95 qw422016.N().S(` `) -//line views/readers.qtpl:95 +//line views/readers.qtpl:96 if nextHyphaName != "" { -//line views/readers.qtpl:95 +//line views/readers.qtpl:96 qw422016.N().S(` `) -//line views/readers.qtpl:97 +//line views/readers.qtpl:98 } -//line views/readers.qtpl:97 +//line views/readers.qtpl:98 qw422016.N().S(`
    `) -//line views/readers.qtpl:99 +//line views/readers.qtpl:100 StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:99 +//line views/readers.qtpl:100 qw422016.N().S(`
    `) -//line views/readers.qtpl:101 +//line views/readers.qtpl:102 StreamRelativeHyphaeHTML(qw422016, relatives) -//line views/readers.qtpl:101 +//line views/readers.qtpl:102 qw422016.N().S(`
    `) -//line views/readers.qtpl:103 -} - -//line views/readers.qtpl:103 -func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:103 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:103 - StreamHyphaHTML(qw422016, rq, h, contents) -//line views/readers.qtpl:103 - qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:103 -} - -//line views/readers.qtpl:103 -func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) string { -//line views/readers.qtpl:103 - qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:103 - WriteHyphaHTML(qb422016, rq, h, contents) -//line views/readers.qtpl:103 - qs422016 := string(qb422016.B) -//line views/readers.qtpl:103 - qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:103 - return qs422016 -//line views/readers.qtpl:103 -} - -//line views/readers.qtpl:105 -func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:105 +//line views/readers.qtpl:104 + streamviewScripts(qw422016) +//line views/readers.qtpl:104 qw422016.N().S(` `) +//line views/readers.qtpl:105 +} + +//line views/readers.qtpl:105 +func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { +//line views/readers.qtpl:105 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/readers.qtpl:105 + StreamHyphaHTML(qw422016, rq, h, contents) +//line views/readers.qtpl:105 + qt422016.ReleaseWriter(qw422016) +//line views/readers.qtpl:105 +} + +//line views/readers.qtpl:105 +func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) string { +//line views/readers.qtpl:105 + qb422016 := qt422016.AcquireByteBuffer() +//line views/readers.qtpl:105 + WriteHyphaHTML(qb422016, rq, h, contents) +//line views/readers.qtpl:105 + qs422016 := string(qb422016.B) +//line views/readers.qtpl:105 + qt422016.ReleaseByteBuffer(qb422016) +//line views/readers.qtpl:105 + return qs422016 +//line views/readers.qtpl:105 +} + //line views/readers.qtpl:107 +func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { +//line views/readers.qtpl:107 + qw422016.N().S(` +`) +//line views/readers.qtpl:109 relatives, subhyphae, _, _ := tree.Tree(h.Name) -//line views/readers.qtpl:108 +//line views/readers.qtpl:110 qw422016.N().S(` `) -//line views/readers.qtpl:109 +//line views/readers.qtpl:111 StreamNavHTML(qw422016, rq, h.Name, "revision", revHash) -//line views/readers.qtpl:109 +//line views/readers.qtpl:111 qw422016.N().S(`

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

    `) -//line views/readers.qtpl:114 +//line views/readers.qtpl:116 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:114 +//line views/readers.qtpl:116 qw422016.N().S(` `) -//line views/readers.qtpl:115 +//line views/readers.qtpl:117 qw422016.N().S(contents) -//line views/readers.qtpl:115 +//line views/readers.qtpl:117 qw422016.N().S(`
    `) -//line views/readers.qtpl:117 +//line views/readers.qtpl:119 StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:117 +//line views/readers.qtpl:119 qw422016.N().S(`
    `) -//line views/readers.qtpl:119 +//line views/readers.qtpl:121 StreamRelativeHyphaeHTML(qw422016, relatives) -//line views/readers.qtpl:119 +//line views/readers.qtpl:121 qw422016.N().S(`
    `) -//line views/readers.qtpl:121 +//line views/readers.qtpl:123 + streamviewScripts(qw422016) +//line views/readers.qtpl:123 + qw422016.N().S(` +`) +//line views/readers.qtpl:124 } -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 StreamRevisionHTML(qw422016, rq, h, contents, revHash) -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 } -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) string { -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 WriteRevisionHTML(qb422016, rq, h, contents, revHash) -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 qs422016 := string(qb422016.B) -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 return qs422016 -//line views/readers.qtpl:121 +//line views/readers.qtpl:124 +} + +//line views/readers.qtpl:126 +func streamviewScripts(qw422016 *qt422016.Writer) { +//line views/readers.qtpl:126 + qw422016.N().S(` +`) +//line views/readers.qtpl:127 + for _, scriptPath := range cfg.ViewScripts { +//line views/readers.qtpl:127 + qw422016.N().S(` + +`) +//line views/readers.qtpl:129 + } +//line views/readers.qtpl:129 + qw422016.N().S(` +`) +//line views/readers.qtpl:130 +} + +//line views/readers.qtpl:130 +func writeviewScripts(qq422016 qtio422016.Writer) { +//line views/readers.qtpl:130 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/readers.qtpl:130 + streamviewScripts(qw422016) +//line views/readers.qtpl:130 + qt422016.ReleaseWriter(qw422016) +//line views/readers.qtpl:130 +} + +//line views/readers.qtpl:130 +func viewScripts() string { +//line views/readers.qtpl:130 + qb422016 := qt422016.AcquireByteBuffer() +//line views/readers.qtpl:130 + writeviewScripts(qb422016) +//line views/readers.qtpl:130 + qs422016 := string(qb422016.B) +//line views/readers.qtpl:130 + qt422016.ReleaseByteBuffer(qb422016) +//line views/readers.qtpl:130 + return qs422016 +//line views/readers.qtpl:130 } diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 21c2f8a..68d29a5 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -26,6 +26,7 @@ {%s= body %} + {%= omnipresentScripts() %} {% endfunc %} @@ -152,3 +153,9 @@ for u := range user.YieldUsers() { {% endfunc %} + +{% func omnipresentScripts() %} +{% for _, scriptPath := range cfg.OmnipresentScripts %} + +{% endfor %} +{% endfunc %} \ No newline at end of file diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 9344f8e..5c96841 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -90,48 +90,53 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User, //line views/stuff.qtpl:28 qw422016.N().S(body) //line views/stuff.qtpl:28 + qw422016.N().S(` + `) +//line views/stuff.qtpl:29 + streamomnipresentScripts(qw422016) +//line views/stuff.qtpl:29 qw422016.N().S(` `) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 } -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 func WriteBaseHTML(qq422016 qtio422016.Writer, title, body string, u *user.User, headElements ...string) { -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 StreamBaseHTML(qw422016, title, body, u, headElements...) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 } -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 func BaseHTML(title, body string, u *user.User, headElements ...string) string { -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 WriteBaseHTML(qb422016, title, body, u, headElements...) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 return qs422016 -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:32 } -//line views/stuff.qtpl:33 +//line views/stuff.qtpl:34 func StreamUserListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:33 +//line views/stuff.qtpl:34 qw422016.N().S(`

    List of users

    `) -//line views/stuff.qtpl:38 +//line views/stuff.qtpl:39 var ( admins = make([]string, 0) moderators = make([]string, 0) @@ -148,303 +153,303 @@ func StreamUserListHTML(qw422016 *qt422016.Writer) { } } -//line views/stuff.qtpl:53 +//line views/stuff.qtpl:54 qw422016.N().S(`

    Admins

      `) -//line views/stuff.qtpl:56 +//line views/stuff.qtpl:57 for _, name := range admins { -//line views/stuff.qtpl:56 +//line views/stuff.qtpl:57 qw422016.N().S(`
    1. `) -//line views/stuff.qtpl:57 +//line views/stuff.qtpl:58 qw422016.E().S(name) -//line views/stuff.qtpl:57 +//line views/stuff.qtpl:58 qw422016.N().S(`
    2. `) -//line views/stuff.qtpl:58 +//line views/stuff.qtpl:59 } -//line views/stuff.qtpl:58 +//line views/stuff.qtpl:59 qw422016.N().S(`

    Moderators

      `) -//line views/stuff.qtpl:62 +//line views/stuff.qtpl:63 for _, name := range moderators { -//line views/stuff.qtpl:62 +//line views/stuff.qtpl:63 qw422016.N().S(`
    1. `) -//line views/stuff.qtpl:63 +//line views/stuff.qtpl:64 qw422016.E().S(name) -//line views/stuff.qtpl:63 +//line views/stuff.qtpl:64 qw422016.N().S(`
    2. `) -//line views/stuff.qtpl:64 +//line views/stuff.qtpl:65 } -//line views/stuff.qtpl:64 +//line views/stuff.qtpl:65 qw422016.N().S(`

    Editors

      `) -//line views/stuff.qtpl:68 +//line views/stuff.qtpl:69 for _, name := range editors { -//line views/stuff.qtpl:68 +//line views/stuff.qtpl:69 qw422016.N().S(`
    1. `) -//line views/stuff.qtpl:69 +//line views/stuff.qtpl:70 qw422016.E().S(name) -//line views/stuff.qtpl:69 +//line views/stuff.qtpl:70 qw422016.N().S(`
    2. `) -//line views/stuff.qtpl:70 +//line views/stuff.qtpl:71 } -//line views/stuff.qtpl:70 +//line views/stuff.qtpl:71 qw422016.N().S(`
    `) -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 } -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 func WriteUserListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 StreamUserListHTML(qw422016) -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 } -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 func UserListHTML() string { -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 WriteUserListHTML(qb422016) -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 return qs422016 -//line views/stuff.qtpl:74 +//line views/stuff.qtpl:75 } -//line views/stuff.qtpl:76 +//line views/stuff.qtpl:77 func StreamHyphaListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:76 +//line views/stuff.qtpl:77 qw422016.N().S(`

    List of hyphae

    This wiki has `) -//line views/stuff.qtpl:80 +//line views/stuff.qtpl:81 qw422016.N().D(hyphae.Count()) -//line views/stuff.qtpl:80 +//line views/stuff.qtpl:81 qw422016.N().S(` hyphae.

      `) -//line views/stuff.qtpl:82 +//line views/stuff.qtpl:83 for h := range hyphae.YieldExistingHyphae() { -//line views/stuff.qtpl:82 +//line views/stuff.qtpl:83 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:84 +//line views/stuff.qtpl:85 qw422016.E().S(util.BeautifulName(h.Name)) -//line views/stuff.qtpl:84 +//line views/stuff.qtpl:85 qw422016.N().S(` `) -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:86 if h.BinaryPath != "" { -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:86 qw422016.N().S(` `) -//line views/stuff.qtpl:86 +//line views/stuff.qtpl:87 qw422016.E().S(filepath.Ext(h.BinaryPath)[1:]) -//line views/stuff.qtpl:86 +//line views/stuff.qtpl:87 qw422016.N().S(` `) -//line views/stuff.qtpl:87 +//line views/stuff.qtpl:88 } -//line views/stuff.qtpl:87 +//line views/stuff.qtpl:88 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:90 } -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:90 qw422016.N().S(`
    `) -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 } -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 func WriteHyphaListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 StreamHyphaListHTML(qw422016) -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 } -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 func HyphaListHTML() string { -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 WriteHyphaListHTML(qb422016) -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 return qs422016 -//line views/stuff.qtpl:93 +//line views/stuff.qtpl:94 } -//line views/stuff.qtpl:95 +//line views/stuff.qtpl:96 func StreamAboutHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:95 +//line views/stuff.qtpl:96 qw422016.N().S(`

    About `) -//line views/stuff.qtpl:99 +//line views/stuff.qtpl:100 qw422016.E().S(cfg.WikiName) -//line views/stuff.qtpl:99 +//line views/stuff.qtpl:100 qw422016.N().S(`

    See /list for information about hyphae on this wiki.

    `) -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 } -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 func WriteAboutHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 StreamAboutHTML(qw422016) -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 } -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 func AboutHTML() string { -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 WriteAboutHTML(qb422016) -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 return qs422016 -//line views/stuff.qtpl:117 +//line views/stuff.qtpl:118 } -//line views/stuff.qtpl:119 +//line views/stuff.qtpl:120 func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:119 +//line views/stuff.qtpl:120 qw422016.N().S(`
    @@ -481,31 +486,80 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
    `) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 } -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 func WriteAdminPanelHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 StreamAdminPanelHTML(qw422016) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 } -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 func AdminPanelHTML() string { -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 WriteAdminPanelHTML(qb422016) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 return qs422016 -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 +} + +//line views/stuff.qtpl:157 +func streamomnipresentScripts(qw422016 *qt422016.Writer) { +//line views/stuff.qtpl:157 + qw422016.N().S(` +`) +//line views/stuff.qtpl:158 + for _, scriptPath := range cfg.OmnipresentScripts { +//line views/stuff.qtpl:158 + qw422016.N().S(` + +`) +//line views/stuff.qtpl:160 + } +//line views/stuff.qtpl:160 + qw422016.N().S(` +`) +//line views/stuff.qtpl:161 +} + +//line views/stuff.qtpl:161 +func writeomnipresentScripts(qq422016 qtio422016.Writer) { +//line views/stuff.qtpl:161 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/stuff.qtpl:161 + streamomnipresentScripts(qw422016) +//line views/stuff.qtpl:161 + qt422016.ReleaseWriter(qw422016) +//line views/stuff.qtpl:161 +} + +//line views/stuff.qtpl:161 +func omnipresentScripts() string { +//line views/stuff.qtpl:161 + qb422016 := qt422016.AcquireByteBuffer() +//line views/stuff.qtpl:161 + writeomnipresentScripts(qb422016) +//line views/stuff.qtpl:161 + qs422016 := string(qb422016.B) +//line views/stuff.qtpl:161 + qt422016.ReleaseByteBuffer(qb422016) +//line views/stuff.qtpl:161 + return qs422016 +//line views/stuff.qtpl:161 } From fcd4b9b8530a326f1dc8ae7454afd72c4c3e1f8d Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Sat, 22 May 2021 23:10:32 +0500 Subject: [PATCH 26/41] Change URLs for static assets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /static/... → /assets/... --- views/mutators.qtpl | 2 +- views/mutators.qtpl.go | 2 +- views/stuff.qtpl | 2 +- views/stuff.qtpl.go | 2 +- web/web.go | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/views/mutators.qtpl b/views/mutators.qtpl index c1d5182..828cac1 100644 --- a/views/mutators.qtpl +++ b/views/mutators.qtpl @@ -65,7 +65,7 @@ {% endif %} - + {% endfunc %} {% func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) %} diff --git a/views/mutators.qtpl.go b/views/mutators.qtpl.go index 035dbc8..eaf6f10 100644 --- a/views/mutators.qtpl.go +++ b/views/mutators.qtpl.go @@ -141,7 +141,7 @@ func StreamToolbar(qw422016 *qt422016.Writer, u *user.User) { qw422016.N().S(` - + `) //line views/mutators.qtpl:69 } diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 68d29a5..26117af 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -10,7 +10,7 @@ - + {%s title %} {% for _, el := range headElements %}{%s= el %}{% endfor %} diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 5c96841..9079a25 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -41,7 +41,7 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User, - + `) //line views/stuff.qtpl:14 qw422016.E().S(title) diff --git a/web/web.go b/web/web.go index 1a9df12..95b3c44 100644 --- a/web/web.go +++ b/web/web.go @@ -41,13 +41,13 @@ func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) { func handlerStyle(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) - if _, err := os.Stat(cfg.WikiDir + "/static/common.css"); err == nil { - http.ServeFile(w, rq, cfg.WikiDir+"/static/common.css") + if _, err := os.Stat(cfg.WikiDir + "/assets/common.css"); err == nil { + http.ServeFile(w, rq, cfg.WikiDir+"/assets/common.css") } else { w.Header().Set("Content-Type", "text/css;charset=utf-8") w.Write([]byte(assets.DefaultCSS())) } - if bytes, err := ioutil.ReadFile(cfg.WikiDir + "/static/custom.css"); err == nil { + if bytes, err := ioutil.ReadFile(cfg.WikiDir + "/assets/custom.css"); err == nil { w.Write(bytes) } } @@ -118,8 +118,8 @@ func Init() { http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { http.ServeFile(w, rq, cfg.WikiDir+"/static/favicon.ico") }) - http.HandleFunc("/static/common.css", handlerStyle) - http.HandleFunc("/static/toolbar.js", handlerToolbar) + http.HandleFunc("/assets/common.css", handlerStyle) + http.HandleFunc("/assets/toolbar.js", handlerToolbar) http.HandleFunc("/assets/icon/", handlerIcon) http.HandleFunc("/robots.txt", handlerRobotsTxt) http.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) { From 4fcf5abb37e51467d9e5f0936fac61789a436a23 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Mon, 24 May 2021 14:33:57 +0500 Subject: [PATCH 27/41] Migrate to mycomarkup v0.3.0 Break a lot of things as well: * OpenGraph is temporarily removed * Link coloring is broken * RocketLink display text is lost for some reason * List nesting is lost? Some things got fixed though: * External link icons are back And new features: * Multiline list entries (tasty) --- cfg/header_links.go | 8 +++++--- go.mod | 2 +- go.sum | 4 ++-- shroom/view.go | 4 +--- web/readers.go | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cfg/header_links.go b/cfg/header_links.go index 7afb3f6..b6add82 100644 --- a/cfg/header_links.go +++ b/cfg/header_links.go @@ -2,6 +2,7 @@ package cfg // See https://mycorrhiza.lesarbr.es/hypha/configuration/header import ( + "github.com/bouncepaw/mycomarkup/blocks" "strings" ) @@ -18,8 +19,8 @@ func SetDefaultHeaderLinks() { } } -// ParseHeaderLinks extracts all rocketlinks from the given text and saves them as header links. rocketlinkλ must be set to markup.Rocketlink. You have to pass it like that to avoid cyclical dependency. -func ParseHeaderLinks(text string, rocketlinkλ func(string, string) (string, string, string)) { +// ParseHeaderLinks extracts all rocketlinks from the given text and saves them as header links. +func ParseHeaderLinks(text string) { HeaderLinks = []HeaderLink{} for _, line := range strings.Split(text, "\n") { // There is a false positive when parsing markup like that: @@ -30,7 +31,8 @@ func ParseHeaderLinks(text string, rocketlinkλ func(string, string) (string, st // // I do not really care. if strings.HasPrefix(line, "=>") { - href, display, _ := rocketlinkλ(line, HeaderLinksHypha) + rl := blocks.MakeRocketLink(line, HeaderLinksHypha) + href, display := rl.Href(), rl.Display() HeaderLinks = append(HeaderLinks, HeaderLink{ Href: href, Display: display, diff --git a/go.mod b/go.mod index 778bbb1..ed833b5 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.1.0 + github.com/bouncepaw/mycomarkup v0.3.1 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index 37c9e73..d74a34a 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ git.sr.ht/~adnano/go-gemini v0.1.13/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3V github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= 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/bouncepaw/mycomarkup v0.1.0 h1:WsvWe1+ygGXexjjLo1Gq7Qxh7INkLZ9YCjj4SjZOUk4= -github.com/bouncepaw/mycomarkup v0.1.0/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= +github.com/bouncepaw/mycomarkup v0.3.1 h1:5uh7PJYjTNqrA2ibZAvA50nImKECq5AWtlzTEOO32sM= +github.com/bouncepaw/mycomarkup v0.3.1/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= 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= diff --git a/shroom/view.go b/shroom/view.go index 444db3b..ce7a8f4 100644 --- a/shroom/view.go +++ b/shroom/view.go @@ -6,8 +6,6 @@ import ( "github.com/bouncepaw/mycorrhiza/cfg" "github.com/bouncepaw/mycorrhiza/hyphae" - - "github.com/bouncepaw/mycomarkup/blocks" ) // FetchTextPart tries to read text file of the given hypha. If there is no file, empty string is returned. @@ -33,7 +31,7 @@ func SetHeaderLinks() { cfg.SetDefaultHeaderLinks() } else { text := string(contents) - cfg.ParseHeaderLinks(text, blocks.Rocketlink) + cfg.ParseHeaderLinks(text) } } } diff --git a/web/readers.go b/web/readers.go index ecc2e5d..0e04e11 100644 --- a/web/readers.go +++ b/web/readers.go @@ -83,7 +83,7 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { ) w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) - w.Write([]byte(views.BaseHTML(util.BeautifulName(hyphaName), page, u))) + _, _ = fmt.Fprint(w, views.BaseHTML(util.BeautifulName(hyphaName), page, u)) } // handlerText serves raw source text of the hypha. @@ -124,7 +124,7 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { if errT == nil { md := doc.Doc(hyphaName, string(fileContentsT)) contents = md.AsHTML() - openGraph = md.OpenGraphHTML() + //openGraph = md.OpenGraphHTML() } if !os.IsNotExist(errB) { contents = views.AttachmentHTML(h) + contents From ec1eafc0e4a104c20f5e2c66dac3111cc8918f99 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Mon, 24 May 2021 23:19:05 +0500 Subject: [PATCH 28/41] Migrate to mycomarkup v0.3.3 Some things got fixed: * OpenGraph is (mostly) back * RocketLink display text is back But: * All links are blue, but only some of they should be --- go.mod | 2 +- go.sum | 4 ++-- web/readers.go | 8 ++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index ed833b5..6ee2068 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.3.1 + github.com/bouncepaw/mycomarkup v0.3.3 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index d74a34a..385cb76 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ git.sr.ht/~adnano/go-gemini v0.1.13/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3V github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= 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/bouncepaw/mycomarkup v0.3.1 h1:5uh7PJYjTNqrA2ibZAvA50nImKECq5AWtlzTEOO32sM= -github.com/bouncepaw/mycomarkup v0.3.1/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= +github.com/bouncepaw/mycomarkup v0.3.3 h1:Mw26iJsxtIgGR0yuMrgyHEj14VchetCdDvqGlj+m4OE= +github.com/bouncepaw/mycomarkup v0.3.3/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= 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= diff --git a/web/readers.go b/web/readers.go index 0e04e11..5fb97bd 100644 --- a/web/readers.go +++ b/web/readers.go @@ -2,7 +2,9 @@ package web import ( "fmt" + "github.com/bouncepaw/mycomarkup" "github.com/bouncepaw/mycomarkup/doc" + "github.com/bouncepaw/mycomarkup/parser" "io/ioutil" "log" "net/http" @@ -122,9 +124,11 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { fileContentsT, errT := ioutil.ReadFile(h.TextPath) _, errB := os.Stat(h.BinaryPath) if errT == nil { + ctx, _ := parser.ContextFromStringInput(hyphaName, "") // FIXME: md := doc.Doc(hyphaName, string(fileContentsT)) - contents = md.AsHTML() - //openGraph = md.OpenGraphHTML() + ast := md.Lex() + contents = doc.GenerateHTML(ast, 0) + openGraph = mycomarkup.OpenGraphHTML(ctx, ast) } if !os.IsNotExist(errB) { contents = views.AttachmentHTML(h) + contents From b95729df3909a2d0359e6115f0a5bfc78bc3f899 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Tue, 25 May 2021 12:11:16 +0500 Subject: [PATCH 29/41] Migrate to mycomarkup v0.4.0 --- assets/devconfig.ini | 2 +- gemini.go | 5 +---- go.mod | 2 +- go.sum | 2 ++ metarrhiza | 2 +- web/mutators.go | 7 +++++-- web/readers.go | 16 ++++++++-------- 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/assets/devconfig.ini b/assets/devconfig.ini index 8321181..dba810d 100644 --- a/assets/devconfig.ini +++ b/assets/devconfig.ini @@ -2,7 +2,7 @@ WikiName = Mycorrhiza (dev) NaviTitleIcon = 🧑‍💻 [Hyphae] -HomeHypha = home +HomeHypha = mycorrhiza_wiki UserHypha = u HeaderLinksHypha = header-links diff --git a/gemini.go b/gemini.go index 91fa479..ba50649 100644 --- a/gemini.go +++ b/gemini.go @@ -21,8 +21,6 @@ import ( "github.com/bouncepaw/mycorrhiza/cfg" "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/util" - - "github.com/bouncepaw/mycomarkup/doc" ) func geminiHomeHypha(w *gemini.ResponseWriter, rq *gemini.Request) { @@ -46,8 +44,7 @@ func geminiHypha(w *gemini.ResponseWriter, rq *gemini.Request) { if h.Exists { fileContentsT, errT := ioutil.ReadFile(h.TextPath) if errT == nil { - md := doc.Doc(hyphaName, string(fileContentsT)) - contents = md.AsGemtext() + contents = string(fileContentsT) } } if hasAmnt { diff --git a/go.mod b/go.mod index 6ee2068..a9f0134 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.3.3 + github.com/bouncepaw/mycomarkup v0.4.0 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index 385cb76..8076aec 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/bouncepaw/mycomarkup v0.3.3 h1:Mw26iJsxtIgGR0yuMrgyHEj14VchetCdDvqGlj+m4OE= github.com/bouncepaw/mycomarkup v0.3.3/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= +github.com/bouncepaw/mycomarkup v0.4.0 h1:c61uxVTzeozIIErM7RQSdjgyMTOtEDhK/0fJp0vDygo= +github.com/bouncepaw/mycomarkup v0.4.0/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= 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= diff --git a/metarrhiza b/metarrhiza index 515634c..6758d40 160000 --- a/metarrhiza +++ b/metarrhiza @@ -1 +1 @@ -Subproject commit 515634c88a51a616f486dfefc2a7b9e6ca692689 +Subproject commit 6758d40d32b1ba2c793b6d5e8279983bee9392c0 diff --git a/web/mutators.go b/web/mutators.go index 8c9cc05..dfda455 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -2,7 +2,8 @@ package web import ( "fmt" - "github.com/bouncepaw/mycomarkup/doc" + "github.com/bouncepaw/mycomarkup" + "github.com/bouncepaw/mycomarkup/mycocontext" "log" "net/http" @@ -188,6 +189,8 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { } if action == "Preview" { + ctx, _ := mycocontext.ContextFromStringInput(hyphaName, textData) + util.HTTP200Page( w, views.BaseHTML( @@ -197,7 +200,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { hyphaName, textData, "", - doc.Doc(hyphaName, textData).AsHTML()), + mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx))), u)) } else { http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther) diff --git a/web/readers.go b/web/readers.go index 5fb97bd..7054c9d 100644 --- a/web/readers.go +++ b/web/readers.go @@ -2,9 +2,7 @@ package web import ( "fmt" - "github.com/bouncepaw/mycomarkup" - "github.com/bouncepaw/mycomarkup/doc" - "github.com/bouncepaw/mycomarkup/parser" + "github.com/bouncepaw/mycomarkup/mycocontext" "io/ioutil" "log" "net/http" @@ -18,6 +16,8 @@ import ( "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/views" + + "github.com/bouncepaw/mycomarkup" ) func initReaders() { @@ -75,7 +75,8 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { u = user.FromRequest(rq) ) if err == nil { - contents = doc.Doc(hyphaName, textContents).AsHTML() + ctx, _ := mycocontext.ContextFromStringInput(hyphaName, textContents) + contents = mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx)) } page := views.RevisionHTML( rq, @@ -124,10 +125,9 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { fileContentsT, errT := ioutil.ReadFile(h.TextPath) _, errB := os.Stat(h.BinaryPath) if errT == nil { - ctx, _ := parser.ContextFromStringInput(hyphaName, "") // FIXME: - md := doc.Doc(hyphaName, string(fileContentsT)) - ast := md.Lex() - contents = doc.GenerateHTML(ast, 0) + ctx, _ := mycocontext.ContextFromStringInput(hyphaName, string(fileContentsT)) + ast := mycomarkup.BlockTree(ctx) + contents = mycomarkup.BlocksToHTML(ctx, ast) openGraph = mycomarkup.OpenGraphHTML(ctx, ast) } if !os.IsNotExist(errB) { From 48034fc25b6b38e6fb881d22632f8bd66d25e0ea Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Tue, 25 May 2021 12:34:04 +0500 Subject: [PATCH 30/41] Make some visual design changes --- assets/assets.qtpl.go | 9 +- assets/default.css | 9 +- views/modal.qtpl | 4 +- views/modal.qtpl.go | 4 +- views/readers.qtpl | 12 +- views/readers.qtpl.go | 260 +++++++++++++++++++++--------------------- 6 files changed, 148 insertions(+), 150 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 7969c74..509609b 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -125,9 +125,6 @@ func StreamDefaultCSS(qw422016 *qt422016.Writer) { .modal__title { font-size: 2rem; } .modal__title_small { font-size: 1.5rem; } .modal__confirmation-msg { margin: 0 0 .5rem 0; } -.modal__action { display: inline-block; font-size: 1rem; padding: .25rem; border-radius: .25rem; } -.modal__submit { border: 1px #999 solid; } -.modal__cancel { border: 1px #999 dashed; text-decoration: none; } .hypha-list { padding-left: 0; } .hypha-list__entry { list-style-type: none; } @@ -253,7 +250,7 @@ main h1, main h2, main h3, main h4, main h5, main h6 { margin: 1.5rem 0 0 0; } .heading__link:hover::after, .heading__link:active::after { color: #999; } article p { margin: .5rem 0; } article ul, ol { padding-left: 1.5rem; margin: .5rem 0; } -article code { padding: .1rem .3rem; border-radius: .25rem; font-size: 90%; } +article code { padding: .1rem .3rem; border-radius: .25rem; font-size: 90%; font-family: 'Menlo', 'PT Mono', monospace; } article pre.codeblock { padding:.5rem; white-space: pre-wrap; border-radius: .25rem;} .codeblock code {padding:0; font-size:15px;} .transclusion { border-radius: .25rem; } @@ -354,10 +351,10 @@ table { background-color: #eee; } .layout-card { border-radius: .25rem; background-color: white; } .layout-card__title { font-size: 1rem; margin: 0; padding: .25rem .5rem; border-radius: .25rem .25rem 0 0; } -.layout-card__title { background-color: #eee; } +.layout-card__title { border-bottom: 1px solid #eee; } /* Other stuff */ -html { background-color: #ddd; +html { background-color: #eee; } header { background-color: #eee; } .header-links__link { color: black; } diff --git a/assets/default.css b/assets/default.css index c83733b..cc1cd00 100644 --- a/assets/default.css +++ b/assets/default.css @@ -10,9 +10,6 @@ .modal__title { font-size: 2rem; } .modal__title_small { font-size: 1.5rem; } .modal__confirmation-msg { margin: 0 0 .5rem 0; } -.modal__action { display: inline-block; font-size: 1rem; padding: .25rem; border-radius: .25rem; } -.modal__submit { border: 1px #999 solid; } -.modal__cancel { border: 1px #999 dashed; text-decoration: none; } .hypha-list { padding-left: 0; } .hypha-list__entry { list-style-type: none; } @@ -138,7 +135,7 @@ main h1, main h2, main h3, main h4, main h5, main h6 { margin: 1.5rem 0 0 0; } .heading__link:hover::after, .heading__link:active::after { color: #999; } article p { margin: .5rem 0; } article ul, ol { padding-left: 1.5rem; margin: .5rem 0; } -article code { padding: .1rem .3rem; border-radius: .25rem; font-size: 90%; } +article code { padding: .1rem .3rem; border-radius: .25rem; font-size: 90%; font-family: 'Menlo', 'PT Mono', monospace; } article pre.codeblock { padding:.5rem; white-space: pre-wrap; border-radius: .25rem;} .codeblock code {padding:0; font-size:15px;} .transclusion { border-radius: .25rem; } @@ -239,10 +236,10 @@ table { background-color: #eee; } .layout-card { border-radius: .25rem; background-color: white; } .layout-card__title { font-size: 1rem; margin: 0; padding: .25rem .5rem; border-radius: .25rem .25rem 0 0; } -.layout-card__title { background-color: #eee; } +.layout-card__title { border-bottom: 1px solid #eee; } /* Other stuff */ -html { background-color: #ddd; +html { background-color: #eee; } header { background-color: #eee; } .header-links__link { color: black; } diff --git a/views/modal.qtpl b/views/modal.qtpl index bb1a559..45c9dd3 100644 --- a/views/modal.qtpl +++ b/views/modal.qtpl @@ -54,8 +54,8 @@ {% endfunc %} {% func modalEnd(hyphaName string, shouldFocusOnConfirm bool) %} - <input type="submit" value="Confirm" class="modal__action modal__submit" {% if shouldFocusOnConfirm %}autofocus{% endif %}> - <a href="/hypha/{%s hyphaName %}" class="modal__action modal__cancel">Cancel</a> + <input type="submit" value="Confirm" class="btn" {% if shouldFocusOnConfirm %}autofocus{% endif %}> + <a href="/hypha/{%s hyphaName %}" class="btn btn_weak">Cancel</a> </fieldset> </form> </main> diff --git a/views/modal.qtpl.go b/views/modal.qtpl.go index 3efb837..5dfba56 100644 --- a/views/modal.qtpl.go +++ b/views/modal.qtpl.go @@ -306,7 +306,7 @@ func modalBegin(path, hyphaName, formAttrs, legend string) string { func streammodalEnd(qw422016 *qt422016.Writer, hyphaName string, shouldFocusOnConfirm bool) { //line views/modal.qtpl:56 qw422016.N().S(` - <input type="submit" value="Confirm" class="modal__action modal__submit" `) + <input type="submit" value="Confirm" class="btn" `) //line views/modal.qtpl:57 if shouldFocusOnConfirm { //line views/modal.qtpl:57 @@ -319,7 +319,7 @@ func streammodalEnd(qw422016 *qt422016.Writer, hyphaName string, shouldFocusOnCo //line views/modal.qtpl:58 qw422016.E().S(hyphaName) //line views/modal.qtpl:58 - qw422016.N().S(`" class="modal__action modal__cancel">Cancel</a> + qw422016.N().S(`" class="btn btn_weak">Cancel</a> </fieldset> </form> </main> diff --git a/views/readers.qtpl b/views/readers.qtpl index 34f861d..7d22dda 100644 --- a/views/readers.qtpl +++ b/views/readers.qtpl @@ -47,12 +47,14 @@ {% if u.CanProceed("upload-binary") %} <form action="/upload-binary/{%s h.Name %}" method="post" enctype="multipart/form-data" - class="modal amnt-menu-block"> - <fieldset class="modal__fieldset upload-binary"> + class="upload-binary modal amnt-menu-block"> + <fieldset class="modal__fieldset"> <legend class="modal__title modal__title_small">Attach</legend> <p class="modal__confirmation-msg">You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.</p> - <input type="file" class="upload-binary__input" name="binary"> - <input type="submit" class="modal__action modal__submit"> + <label for="upload-binary__input"></label> + <input type="file" id="upload-binary__input" name="binary"> + + <input type="submit" class="btn stick-to-bottom" value="Upload"> </fieldset> </form> {% endif %} @@ -62,7 +64,7 @@ <fieldset class="modal__fieldset"> <legend class="modal__title modal__title_small">Unattach</legend> <p class="modal__confirmation-msg">Please note that you don't have to unattach before uploading a new attachment.</p> - <input type="submit" class="modal__action modal__submit"> + <input type="submit" class="btn" value="Unattach"> </fieldset> </form> {% endif %} diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index 10a98ed..fd58941 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -155,336 +155,338 @@ func StreamAttachmentMenuHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hy //line views/readers.qtpl:48 qw422016.N().S(`" method="post" enctype="multipart/form-data" - class="modal amnt-menu-block"> - <fieldset class="modal__fieldset upload-binary"> + class="upload-binary modal amnt-menu-block"> + <fieldset class="modal__fieldset"> <legend class="modal__title modal__title_small">Attach</legend> <p class="modal__confirmation-msg">You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.</p> - <input type="file" class="upload-binary__input" name="binary"> - <input type="submit" class="modal__action modal__submit"> + <label for="upload-binary__input"></label> + <input type="file" id="upload-binary__input" name="binary"> + + <input type="submit" class="btn stick-to-bottom" value="Upload"> </fieldset> </form> `) -//line views/readers.qtpl:58 +//line views/readers.qtpl:60 } -//line views/readers.qtpl:58 +//line views/readers.qtpl:60 qw422016.N().S(` `) -//line views/readers.qtpl:60 +//line views/readers.qtpl:62 if h.BinaryPath != "" && u.CanProceed("unattach-confirm") { -//line views/readers.qtpl:60 +//line views/readers.qtpl:62 qw422016.N().S(` <form action="/unattach-confirm/`) -//line views/readers.qtpl:61 +//line views/readers.qtpl:63 qw422016.E().S(h.Name) -//line views/readers.qtpl:61 +//line views/readers.qtpl:63 qw422016.N().S(`" method="post" class="modal amnt-menu-block"> <fieldset class="modal__fieldset"> <legend class="modal__title modal__title_small">Unattach</legend> <p class="modal__confirmation-msg">Please note that you don't have to unattach before uploading a new attachment.</p> - <input type="submit" class="modal__action modal__submit"> + <input type="submit" class="btn" value="Unattach"> </fieldset> </form> `) -//line views/readers.qtpl:68 +//line views/readers.qtpl:70 } -//line views/readers.qtpl:68 +//line views/readers.qtpl:70 qw422016.N().S(` </section> </main> </div> `) -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 } -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 func WriteAttachmentMenuHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User) { -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 StreamAttachmentMenuHTML(qw422016, rq, h, u) -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 } -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 func AttachmentMenuHTML(rq *http.Request, h *hyphae.Hypha, u *user.User) string { -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 WriteAttachmentMenuHTML(qb422016, rq, h, u) -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 qs422016 := string(qb422016.B) -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 return qs422016 -//line views/readers.qtpl:73 +//line views/readers.qtpl:75 } // If `contents` == "", a helpful message is shown instead. -//line views/readers.qtpl:76 +//line views/readers.qtpl:78 func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:76 +//line views/readers.qtpl:78 qw422016.N().S(` `) -//line views/readers.qtpl:78 +//line views/readers.qtpl:80 relatives, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name) u := user.FromRequest(rq) -//line views/readers.qtpl:80 +//line views/readers.qtpl:82 qw422016.N().S(` `) -//line views/readers.qtpl:81 +//line views/readers.qtpl:83 StreamNavHTML(qw422016, rq, h.Name, "page") -//line views/readers.qtpl:81 +//line views/readers.qtpl:83 qw422016.N().S(` <div class="layout"> <main class="main-width"> <article> `) -//line views/readers.qtpl:85 +//line views/readers.qtpl:87 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:85 +//line views/readers.qtpl:87 qw422016.N().S(` `) -//line views/readers.qtpl:86 +//line views/readers.qtpl:88 if h.Exists { -//line views/readers.qtpl:86 +//line views/readers.qtpl:88 qw422016.N().S(` `) -//line views/readers.qtpl:87 +//line views/readers.qtpl:89 qw422016.N().S(contents) -//line views/readers.qtpl:87 +//line views/readers.qtpl:89 qw422016.N().S(` `) -//line views/readers.qtpl:88 +//line views/readers.qtpl:90 } else { -//line views/readers.qtpl:88 +//line views/readers.qtpl:90 qw422016.N().S(` `) -//line views/readers.qtpl:89 +//line views/readers.qtpl:91 streamnonExistentHyphaNotice(qw422016, h, u) -//line views/readers.qtpl:89 +//line views/readers.qtpl:91 qw422016.N().S(` `) -//line views/readers.qtpl:90 +//line views/readers.qtpl:92 } -//line views/readers.qtpl:90 +//line views/readers.qtpl:92 qw422016.N().S(` </article> <section class="prevnext"> `) -//line views/readers.qtpl:93 +//line views/readers.qtpl:95 if prevHyphaName != "" { -//line views/readers.qtpl:93 +//line views/readers.qtpl:95 qw422016.N().S(` <a class="prevnext__el prevnext__prev" href="/hypha/`) -//line views/readers.qtpl:94 +//line views/readers.qtpl:96 qw422016.E().S(prevHyphaName) -//line views/readers.qtpl:94 +//line views/readers.qtpl:96 qw422016.N().S(`" rel="prev">← `) -//line views/readers.qtpl:94 +//line views/readers.qtpl:96 qw422016.E().S(util.BeautifulName(path.Base(prevHyphaName))) -//line views/readers.qtpl:94 +//line views/readers.qtpl:96 qw422016.N().S(`</a> `) -//line views/readers.qtpl:95 +//line views/readers.qtpl:97 } -//line views/readers.qtpl:95 +//line views/readers.qtpl:97 qw422016.N().S(` `) -//line views/readers.qtpl:96 +//line views/readers.qtpl:98 if nextHyphaName != "" { -//line views/readers.qtpl:96 +//line views/readers.qtpl:98 qw422016.N().S(` <a class="prevnext__el prevnext__next" href="/hypha/`) -//line views/readers.qtpl:97 +//line views/readers.qtpl:99 qw422016.E().S(nextHyphaName) -//line views/readers.qtpl:97 +//line views/readers.qtpl:99 qw422016.N().S(`" rel="next">`) -//line views/readers.qtpl:97 +//line views/readers.qtpl:99 qw422016.E().S(util.BeautifulName(path.Base(nextHyphaName))) -//line views/readers.qtpl:97 +//line views/readers.qtpl:99 qw422016.N().S(` →</a> `) -//line views/readers.qtpl:98 +//line views/readers.qtpl:100 } -//line views/readers.qtpl:98 +//line views/readers.qtpl:100 qw422016.N().S(` </section> `) -//line views/readers.qtpl:100 +//line views/readers.qtpl:102 StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:100 +//line views/readers.qtpl:102 qw422016.N().S(` </main> `) -//line views/readers.qtpl:102 +//line views/readers.qtpl:104 StreamRelativeHyphaeHTML(qw422016, relatives) -//line views/readers.qtpl:102 +//line views/readers.qtpl:104 qw422016.N().S(` </div> `) -//line views/readers.qtpl:104 +//line views/readers.qtpl:106 streamviewScripts(qw422016) -//line views/readers.qtpl:104 +//line views/readers.qtpl:106 qw422016.N().S(` `) -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 } -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 StreamHyphaHTML(qw422016, rq, h, contents) -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 } -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) string { -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 WriteHyphaHTML(qb422016, rq, h, contents) -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 qs422016 := string(qb422016.B) -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 return qs422016 -//line views/readers.qtpl:105 +//line views/readers.qtpl:107 } -//line views/readers.qtpl:107 +//line views/readers.qtpl:109 func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:107 +//line views/readers.qtpl:109 qw422016.N().S(` `) -//line views/readers.qtpl:109 +//line views/readers.qtpl:111 relatives, subhyphae, _, _ := tree.Tree(h.Name) -//line views/readers.qtpl:110 +//line views/readers.qtpl:112 qw422016.N().S(` `) -//line views/readers.qtpl:111 +//line views/readers.qtpl:113 StreamNavHTML(qw422016, rq, h.Name, "revision", revHash) -//line views/readers.qtpl:111 +//line views/readers.qtpl:113 qw422016.N().S(` <div class="layout"> <main class="main-width"> <article> <p>Please note that viewing binary parts of hyphae is not supported in history for now.</p> `) -//line views/readers.qtpl:116 +//line views/readers.qtpl:118 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:116 +//line views/readers.qtpl:118 qw422016.N().S(` `) -//line views/readers.qtpl:117 +//line views/readers.qtpl:119 qw422016.N().S(contents) -//line views/readers.qtpl:117 +//line views/readers.qtpl:119 qw422016.N().S(` </article> `) -//line views/readers.qtpl:119 +//line views/readers.qtpl:121 StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:119 +//line views/readers.qtpl:121 qw422016.N().S(` </main> `) -//line views/readers.qtpl:121 +//line views/readers.qtpl:123 StreamRelativeHyphaeHTML(qw422016, relatives) -//line views/readers.qtpl:121 +//line views/readers.qtpl:123 qw422016.N().S(` </div> `) -//line views/readers.qtpl:123 +//line views/readers.qtpl:125 streamviewScripts(qw422016) -//line views/readers.qtpl:123 +//line views/readers.qtpl:125 qw422016.N().S(` `) -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 } -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 StreamRevisionHTML(qw422016, rq, h, contents, revHash) -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 } -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) string { -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 WriteRevisionHTML(qb422016, rq, h, contents, revHash) -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 qs422016 := string(qb422016.B) -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 return qs422016 -//line views/readers.qtpl:124 +//line views/readers.qtpl:126 } -//line views/readers.qtpl:126 +//line views/readers.qtpl:128 func streamviewScripts(qw422016 *qt422016.Writer) { -//line views/readers.qtpl:126 +//line views/readers.qtpl:128 qw422016.N().S(` `) -//line views/readers.qtpl:127 +//line views/readers.qtpl:129 for _, scriptPath := range cfg.ViewScripts { -//line views/readers.qtpl:127 +//line views/readers.qtpl:129 qw422016.N().S(` <script src="`) -//line views/readers.qtpl:128 +//line views/readers.qtpl:130 qw422016.E().S(scriptPath) -//line views/readers.qtpl:128 +//line views/readers.qtpl:130 qw422016.N().S(`"></script> `) -//line views/readers.qtpl:129 +//line views/readers.qtpl:131 } -//line views/readers.qtpl:129 +//line views/readers.qtpl:131 qw422016.N().S(` `) -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 } -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 func writeviewScripts(qq422016 qtio422016.Writer) { -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 streamviewScripts(qw422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 } -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 func viewScripts() string { -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 writeviewScripts(qb422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 qs422016 := string(qb422016.B) -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 return qs422016 -//line views/readers.qtpl:130 +//line views/readers.qtpl:132 } From 94225997d88e52c049571cec50885814cd53736c Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Tue, 25 May 2021 12:35:41 +0500 Subject: [PATCH 31/41] No longer include metarrhiza --- .gitignore | 2 ++ README.md | 10 +--------- metarrhiza | 1 - 3 files changed, 3 insertions(+), 10 deletions(-) delete mode 160000 metarrhiza diff --git a/.gitignore b/.gitignore index 4c3450f..160d81e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ mycorrhiza +metarrhiza +example-wiki # VScode and IDEA folders .vscode/ diff --git a/README.md b/README.md index 6cdca9b..5a7b52a 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,7 @@ A wiki engine. [Main wiki](https://mycorrhiza.lesarbr.es) ## Building -Also see [detailed instructions](https://mycorrhiza.lesarbr.es/hypha/deploy) on wiki. -```sh -git clone --recurse-submodules https://github.com/bouncepaw/mycorrhiza -cd mycorrhiza -make -# That make will: -# * run the default wiki. You can edit it right away. -# * create an executable called `mycorrhiza`. Run it with path to your wiki. -``` +See [the guide](https://mycorrhiza.lesarbr.es/hypha/guide/deployment) on the wiki. ## Usage ``` diff --git a/metarrhiza b/metarrhiza deleted file mode 160000 index 6758d40..0000000 --- a/metarrhiza +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6758d40d32b1ba2c793b6d5e8279983bee9392c0 From 6ce1dc04697bda67221e81edaf8b84727b16bc78 Mon Sep 17 00:00:00 2001 From: handlerug <umar@handlerug.me> Date: Thu, 27 May 2021 11:41:36 +0700 Subject: [PATCH 32/41] Disallow registration with anon username --- util/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/util.go b/util/util.go index 0cd0ca0..4117b63 100644 --- a/util/util.go +++ b/util/util.go @@ -98,7 +98,7 @@ func IsCanonicalName(name string) bool { } func IsPossibleUsername(username string) bool { - return UsernamePattern.MatchString(strings.TrimSpace(username)) + return username != "anon" && UsernamePattern.MatchString(strings.TrimSpace(username)) } // HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". From 78854911efa3dfa80ee24b2690b18e201f84aec5 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Thu, 27 May 2021 15:17:42 +0500 Subject: [PATCH 33/41] Migrate to mycomarkup v0.4.2 --- Makefile | 8 +++++--- go.mod | 2 +- go.sum | 6 ++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 2bacbea..59b3044 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,13 @@ +WIKI=~/src/example-wiki + run: build - ./mycorrhiza metarrhiza + ./mycorrhiza ${WIKI} config_run: build - ./mycorrhiza -config-path "assets/config.ini" metarrhiza + ./mycorrhiza -config-path "assets/config.ini" ${WIKI} devconfig_run: build - ./mycorrhiza -config-path "assets/devconfig.ini" metarrhiza + ./mycorrhiza -config-path "assets/devconfig.ini" ${WIKI} build: go generate diff --git a/go.mod b/go.mod index a9f0134..1e66e26 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.4.0 + github.com/bouncepaw/mycomarkup v0.4.2 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index 8076aec..8c09866 100644 --- a/go.sum +++ b/go.sum @@ -3,10 +3,8 @@ git.sr.ht/~adnano/go-gemini v0.1.13/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3V github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= 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/bouncepaw/mycomarkup v0.3.3 h1:Mw26iJsxtIgGR0yuMrgyHEj14VchetCdDvqGlj+m4OE= -github.com/bouncepaw/mycomarkup v0.3.3/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= -github.com/bouncepaw/mycomarkup v0.4.0 h1:c61uxVTzeozIIErM7RQSdjgyMTOtEDhK/0fJp0vDygo= -github.com/bouncepaw/mycomarkup v0.4.0/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= +github.com/bouncepaw/mycomarkup v0.4.2 h1:8/28n3DKhdtEdaZNGwPxFg0IuDKqr7XKHIYN+silXOI= +github.com/bouncepaw/mycomarkup v0.4.2/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= 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= From d90fb0ba4ad1e4e018fd385bd121c39bb0ab6ab5 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Fri, 28 May 2021 01:43:45 +0500 Subject: [PATCH 34/41] Migrate to Mycomarkup v0.4.4 * New supertext syntax * Nested quotes --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1e66e26..5b93f38 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.4.2 + github.com/bouncepaw/mycomarkup v0.4.4 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index 8c09866..b5f01a9 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ git.sr.ht/~adnano/go-gemini v0.1.13/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3V github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= 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/bouncepaw/mycomarkup v0.4.2 h1:8/28n3DKhdtEdaZNGwPxFg0IuDKqr7XKHIYN+silXOI= -github.com/bouncepaw/mycomarkup v0.4.2/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= +github.com/bouncepaw/mycomarkup v0.4.4 h1:nMgOOuEbPmjHud8XYETsZEvOu5xNXFz1S726582UoKU= +github.com/bouncepaw/mycomarkup v0.4.4/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= 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= From 01e280fbdbe50060ceab837b2cac58372a9a79ee Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Fri, 28 May 2021 01:46:41 +0500 Subject: [PATCH 35/41] Add the new supertext syntax to the toolbar --- assets/assets.qtpl.go | 2 +- assets/toolbar.js | 2 +- views/mutators.qtpl | 2 +- views/mutators.qtpl.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 509609b..0167847 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -507,7 +507,7 @@ const wrapBold = selectionWrapper(2, '**'), //line assets/assets.qtpl:14 qw422016.N().S(`'), wrapHighlighted = selectionWrapper(2, '!!'), - wrapLifted = selectionWrapper(1, '^'), + wrapLifted = selectionWrapper(2, '^^'), wrapLowered = selectionWrapper(2, ',,'), wrapStrikethrough = selectionWrapper(2, '~~'), wrapLink = selectionWrapper(2, '[[', ']]') diff --git a/assets/toolbar.js b/assets/toolbar.js index 36eae4f..affed6b 100644 --- a/assets/toolbar.js +++ b/assets/toolbar.js @@ -42,7 +42,7 @@ const wrapBold = selectionWrapper(2, '**'), wrapItalic = selectionWrapper(2, '//'), wrapMonospace = selectionWrapper(1, '`'), wrapHighlighted = selectionWrapper(2, '!!'), - wrapLifted = selectionWrapper(1, '^'), + wrapLifted = selectionWrapper(2, '^^'), wrapLowered = selectionWrapper(2, ',,'), wrapStrikethrough = selectionWrapper(2, '~~'), wrapLink = selectionWrapper(2, '[[', ']]') diff --git a/views/mutators.qtpl b/views/mutators.qtpl index 828cac1..5b1c321 100644 --- a/views/mutators.qtpl +++ b/views/mutators.qtpl @@ -20,7 +20,7 @@ {"italic", "wrapItalic()", "<i>//Italic//</i>"}, {"highlighted", "wrapHighlighted()", "<mark>!!Highlight!!</mark>"}, {"monospace", "wrapMonospace()", "<code>`Monospace`</code>"}, - {"lifted", "wrapLifted()", "<sup>^Lifted^</sup>"}, + {"lifted", "wrapLifted()", "<sup>^^Lifted^^</sup>"}, {"lowered", "wrapLowered()", "<sub>,,Lowered,,</sub>"}, {"strikethrough", "wrapStrikethrough()", "<strike>~~Strikethrough~~</strike>"}, {"rocket", "insertRocket()", "=> rocketlink"}, diff --git a/views/mutators.qtpl.go b/views/mutators.qtpl.go index eaf6f10..95ac60c 100644 --- a/views/mutators.qtpl.go +++ b/views/mutators.qtpl.go @@ -50,7 +50,7 @@ func StreamToolbar(qw422016 *qt422016.Writer, u *user.User) { {"italic", "wrapItalic()", "<i>//Italic//</i>"}, {"highlighted", "wrapHighlighted()", "<mark>!!Highlight!!</mark>"}, {"monospace", "wrapMonospace()", "<code>`Monospace`</code>"}, - {"lifted", "wrapLifted()", "<sup>^Lifted^</sup>"}, + {"lifted", "wrapLifted()", "<sup>^^Lifted^^</sup>"}, {"lowered", "wrapLowered()", "<sub>,,Lowered,,</sub>"}, {"strikethrough", "wrapStrikethrough()", "<strike>~~Strikethrough~~</strike>"}, {"rocket", "insertRocket()", "=> rocketlink"}, From f61a4c1168375a364834c5c4644bfc9655a94277 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Mon, 31 May 2021 21:57:12 +0500 Subject: [PATCH 36/41] Describe the Structure in Structure.md --- files/Structure.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 files/Structure.md diff --git a/files/Structure.md b/files/Structure.md new file mode 100644 index 0000000..63b563d --- /dev/null +++ b/files/Structure.md @@ -0,0 +1,31 @@ +# The Structure +Here I am, doing new stuff before finishing the old stuff. + +See https://github.com/bouncepaw/mycorrhiza/issues/57 for the discussion. + +## The idea +Instead of letting users figure everything out by themselves, we think of the best (in our opinion) file layout and force it onto the users and remove the possibility of configuring it. + +## What is inside the Structure +### Root +The whole wiki is inside one directory or inside one of its subdirectories. Only the Mycorrhiza binary itself and Git (and possible future runtime dependencies) might be outside that directory. That directory (called _root directory_) can have any name. + +### Subdirectories +* `wiki.git` is a valid Git repository. If it is not present or is not a valid Git repository, the engine shall fail to work. When the Wizard is implemented, the engine will offer to make the Git repository. +* `cache` contains temporary files such as user token caches. Wiki administrators can safely delete this directory and expect the wiki to continue working. In the future, stuff like pre-rendered HTML can be stored here. +* All other subdirectories are ignored. + +### User configuration +* `registered-users.json` contains a JSON array of all registered users. The engine will edit this file, and the administrators should not edit by themselves, unless they really want to. +* `fixed-users.json` contains a JSON array of all fixed users. Wiki administrators will edit this file by themselves. + +### Wiki configuration +* `config.ini` is the main configuration file. + +### Customisation +* `favicon.ico` is the Favicon as you know it. +* `common.css` redefines the built-in CSS, the Common style. +* `custom.css` is sent to the user after the Common style. + +### Meta +* `README.txt` contains a short description of the files that can be inside the Structure. A small reminder for the administrators. \ No newline at end of file From c677272c773c3a84dceaf2c368c0446c9e522fa3 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Wed, 2 Jun 2021 14:51:00 +0500 Subject: [PATCH 37/41] Migrate to mycomarkup v0.4.5 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5b93f38..e3fe75c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( git.sr.ht/~adnano/go-gemini v0.1.13 github.com/adrg/xdg v0.2.2 - github.com/bouncepaw/mycomarkup v0.4.4 + github.com/bouncepaw/mycomarkup v0.4.5 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/kr/pretty v0.2.1 // indirect diff --git a/go.sum b/go.sum index b5f01a9..3c1dd9e 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ git.sr.ht/~adnano/go-gemini v0.1.13/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3V github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= 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/bouncepaw/mycomarkup v0.4.4 h1:nMgOOuEbPmjHud8XYETsZEvOu5xNXFz1S726582UoKU= -github.com/bouncepaw/mycomarkup v0.4.4/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= +github.com/bouncepaw/mycomarkup v0.4.5 h1:QBLSGmqGsb3smjAmywosio2nVL7A8sR2KF5AB38GrXc= +github.com/bouncepaw/mycomarkup v0.4.5/go.mod h1:0n6thlGGgrx2Y/2NaaUH4qHW4v1xJ+EpW7yMFUxNRIg= 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= From 14dad46ffdcefa70f014625c54da3cf6faac5504 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Wed, 2 Jun 2021 15:03:40 +0500 Subject: [PATCH 38/41] Set a different size for attachment containers --- assets/assets.qtpl.go | 4 +++- assets/default.css | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 0167847..56ae318 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -261,9 +261,11 @@ article pre.codeblock { padding:.5rem; white-space: pre-wrap; border-radius: .25 /* Derived from https://commons.wikimedia.org/wiki/File:U%2B21D2.svg */ .launchpad__entry { list-style-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.0' width='25' height='12'%3E%3Cg transform='scale(0.7,0.8) translate(-613.21429,-421)'%3E%3Cpath fill='%23999' d='M 638.06773,429.49751 L 631.01022,436.87675 L 630.1898,436.02774 L 632.416,433.30375 L 613.46876,433.30375 L 613.46876,431.66382 L 633.82089,431.66382 L 635.57789,429.5261 L 633.79229,427.35979 L 613.46876,427.35979 L 613.46876,425.71985 L 632.416,425.71985 L 630.1898,422.99587 L 631.01022,422.08788 L 638.06773,429.49751 z '/%3E%3C/g%3E%3C/svg%3E"); } +.binary-container { width: 100%; } +.binary-container > a { display: flex; justify-content: center; } .binary-container_with-img img, .binary-container_with-video video, -.binary-container_with-audio audio {width: 100%} +.binary-container_with-audio audio {max-height: 30em; width: auto; } .subhyphae__title { padding-bottom: .5rem; clear: both; } .navi-title { padding-bottom: .5rem; margin: .25rem 0; } diff --git a/assets/default.css b/assets/default.css index cc1cd00..e93a6af 100644 --- a/assets/default.css +++ b/assets/default.css @@ -146,9 +146,11 @@ article pre.codeblock { padding:.5rem; white-space: pre-wrap; border-radius: .25 /* Derived from https://commons.wikimedia.org/wiki/File:U%2B21D2.svg */ .launchpad__entry { list-style-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.0' width='25' height='12'%3E%3Cg transform='scale(0.7,0.8) translate(-613.21429,-421)'%3E%3Cpath fill='%23999' d='M 638.06773,429.49751 L 631.01022,436.87675 L 630.1898,436.02774 L 632.416,433.30375 L 613.46876,433.30375 L 613.46876,431.66382 L 633.82089,431.66382 L 635.57789,429.5261 L 633.79229,427.35979 L 613.46876,427.35979 L 613.46876,425.71985 L 632.416,425.71985 L 630.1898,422.99587 L 631.01022,422.08788 L 638.06773,429.49751 z '/%3E%3C/g%3E%3C/svg%3E"); } +.binary-container { width: 100%; } +.binary-container > a { display: flex; justify-content: center; } .binary-container_with-img img, .binary-container_with-video video, -.binary-container_with-audio audio {width: 100%} +.binary-container_with-audio audio {max-height: 30em; width: auto; } .subhyphae__title { padding-bottom: .5rem; clear: both; } .navi-title { padding-bottom: .5rem; margin: .25rem 0; } From 6c49bd730824a9104c79cff9f6a047c9ddcbc8d8 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Thu, 3 Jun 2021 18:11:04 +0500 Subject: [PATCH 39/41] Change how blockquotes look a little --- assets/assets.qtpl.go | 5 ++--- assets/default.css | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go index 56ae318..a77f6f9 100644 --- a/assets/assets.qtpl.go +++ b/assets/assets.qtpl.go @@ -233,7 +233,7 @@ textarea {font-size:16px; font-family: 'PT Sans', 'Liberation Sans', sans-serif; .icon {margin-right: .25rem; vertical-align: bottom; } main h1:not(.navi-title) {font-size:1.7rem;} -blockquote { margin-left: 0; padding-left: 1rem; } +blockquote { margin: 0; padding-left: .75rem; } .wikilink_external::before { display: inline-block; width: 18px; height: 16px; vertical-align: sub; } /* .wikilink_external { padding-left: 16px; } */ .wikilink_gopher::before { content: url("/assets/icon/gopher"); } @@ -363,7 +363,7 @@ header { background-color: #eee; } .header-links__link:hover { background-color: #ddd; } main { background-color: white; } -blockquote { border-left: 4px black solid; } +blockquote { border-left: 2px #999 solid; } .wikilink_new {color:#a55858;} .transclusion code, .transclusion .codeblock {background-color:#ddd;} .transclusion__link { color: black; } @@ -391,7 +391,6 @@ a:visited, .wikilink_external:visited { color: #ffb86c; } .hypha-tabs__tab a, .hypha-tabs__tab { color: #ddd; background-color: #232323; border: 0; } .layout-card__title, .hypha-tabs__tab_active { background-color: #343434; } -blockquote { border-left: 4px #ddd solid; } .transclusion .transclusion__link { color: #ddd; } diff --git a/assets/default.css b/assets/default.css index e93a6af..3b7d41d 100644 --- a/assets/default.css +++ b/assets/default.css @@ -118,7 +118,7 @@ textarea {font-size:16px; font-family: 'PT Sans', 'Liberation Sans', sans-serif; .icon {margin-right: .25rem; vertical-align: bottom; } main h1:not(.navi-title) {font-size:1.7rem;} -blockquote { margin-left: 0; padding-left: 1rem; } +blockquote { margin: 0; padding-left: .75rem; } .wikilink_external::before { display: inline-block; width: 18px; height: 16px; vertical-align: sub; } /* .wikilink_external { padding-left: 16px; } */ .wikilink_gopher::before { content: url("/assets/icon/gopher"); } @@ -248,7 +248,7 @@ header { background-color: #eee; } .header-links__link:hover { background-color: #ddd; } main { background-color: white; } -blockquote { border-left: 4px black solid; } +blockquote { border-left: 2px #999 solid; } .wikilink_new {color:#a55858;} .transclusion code, .transclusion .codeblock {background-color:#ddd;} .transclusion__link { color: black; } @@ -276,7 +276,6 @@ a:visited, .wikilink_external:visited { color: #ffb86c; } .hypha-tabs__tab a, .hypha-tabs__tab { color: #ddd; background-color: #232323; border: 0; } .layout-card__title, .hypha-tabs__tab_active { background-color: #343434; } -blockquote { border-left: 4px #ddd solid; } .transclusion .transclusion__link { color: #ddd; } From 4e1115d60944d13b1866c0198cb5a22f9988b7b8 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Thu, 3 Jun 2021 18:16:15 +0500 Subject: [PATCH 40/41] Canonize user names when reading them --- user/files.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user/files.go b/user/files.go index a76f086..bb8465e 100644 --- a/user/files.go +++ b/user/files.go @@ -3,6 +3,7 @@ package user import ( "encoding/json" "github.com/bouncepaw/mycorrhiza/cfg" + "github.com/bouncepaw/mycorrhiza/util" "io/ioutil" "log" "os" @@ -44,6 +45,7 @@ func usersFromFile(path string, source UserSource) (users []*User) { log.Fatal(err) } for _, u := range users { + u.Name = util.CanonicalName(u.Name) u.Source = source } return users From 6b01a09471c8cc9b82d48d1ed23f8edd7603354c Mon Sep 17 00:00:00 2001 From: Timur Ismagilov <bouncepaw2@ya.ru> Date: Fri, 4 Jun 2021 22:29:14 +0500 Subject: [PATCH 41/41] Limit prev/next links in size --- assets/default.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/default.css b/assets/default.css index 3b7d41d..4679850 100644 --- a/assets/default.css +++ b/assets/default.css @@ -176,7 +176,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: inline-block; 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; max-width: 49%; } .prevnext__prev { float: left; } .prevnext__next { float: right; text-align: right; }