From 4cf5937361a7bec15f6dacc0605021ded3512097 Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Sat, 26 Sep 2020 23:19:17 +0500 Subject: [PATCH] Add recent changes page --- README.md | 10 +- go.mod | 2 +- go.sum | 8 +- history/history.go | 53 +++++++++++ history/information.go | 25 ++++- main.go | 17 ++++ metarrhiza | 2 +- templates/recent_changes.qtpl | 40 ++++++++ templates/recent_changes.qtpl.go | 156 +++++++++++++++++++++++++++++++ 9 files changed, 303 insertions(+), 10 deletions(-) create mode 100644 templates/recent_changes.qtpl create mode 100644 templates/recent_changes.qtpl.go diff --git a/README.md b/README.md index a733e95..e87ddfc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ -# 🍄 MycorrhizaWiki 0.8 +# 🍄 MycorrhizaWiki 0.9 A wiki engine. +## 0.9 +This is a development branch for 0.9 version. Features I want to implement in this release: +* [x] Recent changes page. +* [ ] Hypha deletion. +* [ ] Hypha renaming. +* [ ] Support async git ops. + ## Installation ```sh git clone --recurse-submodules https://github.com/bouncepaw/mycorrhiza @@ -31,5 +38,4 @@ Help is always needed. We have a [tg chat](https://t.me/mycorrhizadev) where som * Tagging system * Authorization * Better history viewing -* Recent changes page * More markups diff --git a/go.mod b/go.mod index 17f2ff6..e2ffb7c 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/bouncepaw/mycorrhiza go 1.14 -require github.com/valyala/quicktemplate v1.6.2 +require github.com/valyala/quicktemplate v1.6.3 diff --git a/go.sum b/go.sum index 344ceb3..a9a43a1 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,11 @@ github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.15.1/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= -github.com/valyala/quicktemplate v1.6.2 h1:k0vgK7zlmFzqAoIBIOrhrfmZ6JoTGJlLRPLbkPGr2/M= -github.com/valyala/quicktemplate v1.6.2/go.mod h1:mtEJpQtUiBV0SHhMX6RtiJtqxncgrfmjcUy5T68X8TM= +github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= +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= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= diff --git a/history/history.go b/history/history.go index 787b358..cbd689b 100644 --- a/history/history.go +++ b/history/history.go @@ -6,6 +6,7 @@ import ( "log" "os/exec" "strconv" + "strings" "time" "github.com/bouncepaw/mycorrhiza/util" @@ -31,6 +32,58 @@ type Revision struct { Message string } +// TimeString returns a human readable time representation. +func (rev Revision) TimeString() string { + return rev.Time.Format(time.RFC822) +} + +// HyphaeLinks returns a comma-separated list of hyphae that were affected by this revision as HTML string. +func (rev Revision) HyphaeLinks() (html string) { + // diff-tree --no-commit-id --name-only -r + var ( + // List of files affected by this revision, one per line. + out, err = gitsh("diff-tree", "--no-commit-id", "--name-only", "-r", rev.Hash) + // set is used to determine if a certain hypha has been already noted (hyphae are stored in 2 files at most). + set = make(map[string]bool) + isNewName = func(hyphaName string) bool { + if _, present := set[hyphaName]; present { + return false + } else { + set[hyphaName] = true + return true + } + } + ) + if err != nil { + return "" + } + for _, filename := range strings.Split(out.String(), "\n") { + // If filename has an ampersand: + if strings.IndexRune(filename, '&') >= 0 { + // Remove ampersanded suffix from filename: + ampersandPos := strings.LastIndexByte(filename, '&') + hyphaName := string([]byte(filename)[0:ampersandPos]) // is it safe? + if isNewName(hyphaName) { + // Entries are separated by commas + if len(set) > 1 { + html += `` + } + html += fmt.Sprintf(`%[2]s`, rev.Hash, hyphaName) + } + } + } + return html +} + +func (rev Revision) RecentChangesEntry() (html string) { + return fmt.Sprintf(` +
  • +
  • %s
  • +
  • %s
  • +
  • %s
  • +`, rev.TimeString(), rev.Hash, rev.HyphaeLinks(), rev.Message) +} + // Path to git executable. Set at init() var gitpath string diff --git a/history/information.go b/history/information.go index ff6e654..bb20e6a 100644 --- a/history/information.go +++ b/history/information.go @@ -6,9 +6,30 @@ import ( "fmt" "regexp" "strings" - "time" + + "github.com/bouncepaw/mycorrhiza/templates" ) +func RecentChanges(n int) string { + var ( + out, err = gitsh( + "log", "--oneline", "--no-merges", + "--pretty=format:\"%h\t%ce\t%ct\t%s\"", + ) + revs []Revision + ) + if err == nil { + for _, line := range strings.Split(out.String(), "\n") { + revs = append(revs, parseRevisionLine(line)) + } + } + entries := make([]string, len(revs)) + for i, rev := range revs { + entries[i] = rev.RecentChangesEntry() + } + return templates.RecentChangesHTML(entries, n) +} + // Revisions returns slice of revisions for the given hypha name. func Revisions(hyphaName string) ([]Revision, error) { var ( @@ -48,7 +69,7 @@ func (rev *Revision) AsHtmlTableRow(hyphaName string) string { %s %s -`, rev.Time.Format(time.RFC822), rev.Hash, hyphaName, rev.Hash, rev.Message) +`, rev.TimeString(), rev.Hash, hyphaName, rev.Hash, rev.Message) } // See how the file with `filepath` looked at commit with `hash`. diff --git a/main.go b/main.go index cb9588f..5ef555d 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,8 @@ import ( "os" "path/filepath" "regexp" + "strconv" + "strings" "github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/templates" @@ -83,6 +85,20 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) { http.Redirect(w, rq, "/page/"+randomHyphaName, http.StatusSeeOther) } +// Recent changes +func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) { + log.Println(rq.URL) + var ( + noPrefix = strings.TrimPrefix(rq.URL.String(), "/recent-changes/") + n, err = strconv.Atoi(noPrefix) + ) + if err == nil { + util.HTTP200Page(w, base(strconv.Itoa(n)+" recent changes", history.RecentChanges(n))) + } else { + http.Redirect(w, rq, "/recent-changes/20", http.StatusSeeOther) + } +} + func main() { log.Println("Running MycorrhizaWiki β") @@ -108,6 +124,7 @@ func main() { http.HandleFunc("/list", handlerList) http.HandleFunc("/reindex", handlerReindex) http.HandleFunc("/random", handlerRandom) + http.HandleFunc("/recent-changes/", handlerRecentChanges) http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { http.ServeFile(w, rq, WikiDir+"/static/favicon.ico") }) diff --git a/metarrhiza b/metarrhiza index bdaaab6..2c0e431 160000 --- a/metarrhiza +++ b/metarrhiza @@ -1 +1 @@ -Subproject commit bdaaab62574023487610d608d1e9f2f351707a7f +Subproject commit 2c0e43199ed28f7022a38463a0eec3af3ecb03c9 diff --git a/templates/recent_changes.qtpl b/templates/recent_changes.qtpl new file mode 100644 index 0000000..2f9f8c4 --- /dev/null +++ b/templates/recent_changes.qtpl @@ -0,0 +1,40 @@ +{% func RecentChangesHTML(changes []string, n int) %} +
    +

    Recent Changes

    + + + + {% comment %} + Here I am, willing to add some accesibility using ARIA. Turns out, + role="feed" is not supported in any screen reader as of September + 2020. At least web search says so. Even JAWS doesn't support it! + How come? I'll add the role anyway. -- bouncepaw + {% endcomment %} + +
    + {% if len(changes) == 0 %} +

    Could not find any recent changes.

    + {% else %} + {% for i, entry := range changes %} +
      + {%s= entry %} +
    + {% endfor %} + {% endif %} +
    +
    +{% endfunc %} diff --git a/templates/recent_changes.qtpl.go b/templates/recent_changes.qtpl.go new file mode 100644 index 0000000..3814504 --- /dev/null +++ b/templates/recent_changes.qtpl.go @@ -0,0 +1,156 @@ +// Code generated by qtc from "recent_changes.qtpl". DO NOT EDIT. +// See https://github.com/valyala/quicktemplate for details. + +//line templates/recent_changes.qtpl:1 +package templates + +//line templates/recent_changes.qtpl:1 +import ( + qtio422016 "io" + + qt422016 "github.com/valyala/quicktemplate" +) + +//line templates/recent_changes.qtpl:1 +var ( + _ = qtio422016.Copy + _ = qt422016.AcquireByteBuffer +) + +//line templates/recent_changes.qtpl:1 +func StreamRecentChangesHTML(qw422016 *qt422016.Writer, changes []string, n int) { +//line templates/recent_changes.qtpl:1 + qw422016.N().S(` +
    +

    Recent Changes

    + + + + `) +//line templates/recent_changes.qtpl:25 + qw422016.N().S(` + +
    + `) +//line templates/recent_changes.qtpl:28 + if len(changes) == 0 { +//line templates/recent_changes.qtpl:28 + qw422016.N().S(` +

    Could not find any recent changes.

    + `) +//line templates/recent_changes.qtpl:30 + } else { +//line templates/recent_changes.qtpl:30 + qw422016.N().S(` + `) +//line templates/recent_changes.qtpl:31 + for i, entry := range changes { +//line templates/recent_changes.qtpl:31 + qw422016.N().S(` +
      + `) +//line templates/recent_changes.qtpl:34 + qw422016.N().S(entry) +//line templates/recent_changes.qtpl:34 + qw422016.N().S(` +
    + `) +//line templates/recent_changes.qtpl:36 + } +//line templates/recent_changes.qtpl:36 + qw422016.N().S(` + `) +//line templates/recent_changes.qtpl:37 + } +//line templates/recent_changes.qtpl:37 + qw422016.N().S(` +
    +
    +`) +//line templates/recent_changes.qtpl:40 +} + +//line templates/recent_changes.qtpl:40 +func WriteRecentChangesHTML(qq422016 qtio422016.Writer, changes []string, n int) { +//line templates/recent_changes.qtpl:40 + qw422016 := qt422016.AcquireWriter(qq422016) +//line templates/recent_changes.qtpl:40 + StreamRecentChangesHTML(qw422016, changes, n) +//line templates/recent_changes.qtpl:40 + qt422016.ReleaseWriter(qw422016) +//line templates/recent_changes.qtpl:40 +} + +//line templates/recent_changes.qtpl:40 +func RecentChangesHTML(changes []string, n int) string { +//line templates/recent_changes.qtpl:40 + qb422016 := qt422016.AcquireByteBuffer() +//line templates/recent_changes.qtpl:40 + WriteRecentChangesHTML(qb422016, changes, n) +//line templates/recent_changes.qtpl:40 + qs422016 := string(qb422016.B) +//line templates/recent_changes.qtpl:40 + qt422016.ReleaseByteBuffer(qb422016) +//line templates/recent_changes.qtpl:40 + return qs422016 +//line templates/recent_changes.qtpl:40 +}