1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-12 05:20:26 +00:00

Add recent changes page

This commit is contained in:
bouncepaw 2020-09-26 23:19:17 +05:00
parent 0e6c22080b
commit 4cf5937361
9 changed files with 303 additions and 10 deletions

View File

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

2
go.mod
View File

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

8
go.sum
View File

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

View File

@ -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 += `<span aria-hidden="true">, </span>`
}
html += fmt.Sprintf(`<a href="/rev/%[1]s/%[2]s">%[2]s</a>`, rev.Hash, hyphaName)
}
}
}
return html
}
func (rev Revision) RecentChangesEntry() (html string) {
return fmt.Sprintf(`
<li><time>%s</time></li>
<li>%s</li>
<li>%s</li>
<li>%s</li>
`, rev.TimeString(), rev.Hash, rev.HyphaeLinks(), rev.Message)
}
// Path to git executable. Set at init()
var gitpath string

View File

@ -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 {
<td><time>%s</time></td>
<td><a href="/rev/%s/%s">%s</a></td>
<td>%s</td>
</tr>`, rev.Time.Format(time.RFC822), rev.Hash, hyphaName, rev.Hash, rev.Message)
</tr>`, rev.TimeString(), rev.Hash, hyphaName, rev.Hash, rev.Message)
}
// See how the file with `filepath` looked at commit with `hash`.

17
main.go
View File

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

@ -1 +1 @@
Subproject commit bdaaab62574023487610d608d1e9f2f351707a7f
Subproject commit 2c0e43199ed28f7022a38463a0eec3af3ecb03c9

View File

@ -0,0 +1,40 @@
{% func RecentChangesHTML(changes []string, n int) %}
<main class="recent-changes">
<h1>Recent Changes</h1>
<nav class="recent-changes__count">
See
{% for _, m := range []int{20, 0, 50, 0, 100} %}
{% switch m %}
{% case 0 %}
<span aria-hidden="true">|</span>
{% case n %}
<b>{%d n %}</b>
{% default %}
<a href="/recent-changes/{%d m %}">{%d m %}</a>
{% endswitch %}
{% endfor %}
recent changes
</nav>
{% 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 %}
<section class="recent-changes__list" role="feed">
{% if len(changes) == 0 %}
<p>Could not find any recent changes.</p>
{% else %}
{% for i, entry := range changes %}
<ul class="recent-changes__entry" role="article"
aria-setsize="{%d n %}" aria-posinset="{%d i %}">
{%s= entry %}
</ul>
{% endfor %}
{% endif %}
</section>
</main>
{% endfunc %}

View File

@ -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(`
<main class="recent-changes">
<h1>Recent Changes</h1>
<nav class="recent-changes__count">
See
`)
//line templates/recent_changes.qtpl:7
for _, m := range []int{20, 0, 50, 0, 100} {
//line templates/recent_changes.qtpl:7
qw422016.N().S(`
`)
//line templates/recent_changes.qtpl:8
switch m {
//line templates/recent_changes.qtpl:9
case 0:
//line templates/recent_changes.qtpl:9
qw422016.N().S(`
<span aria-hidden="true">|</span>
`)
//line templates/recent_changes.qtpl:11
case n:
//line templates/recent_changes.qtpl:11
qw422016.N().S(`
<b>`)
//line templates/recent_changes.qtpl:12
qw422016.N().D(n)
//line templates/recent_changes.qtpl:12
qw422016.N().S(`</b>
`)
//line templates/recent_changes.qtpl:13
default:
//line templates/recent_changes.qtpl:13
qw422016.N().S(`
<a href="/recent-changes/`)
//line templates/recent_changes.qtpl:14
qw422016.N().D(m)
//line templates/recent_changes.qtpl:14
qw422016.N().S(`">`)
//line templates/recent_changes.qtpl:14
qw422016.N().D(m)
//line templates/recent_changes.qtpl:14
qw422016.N().S(`</a>
`)
//line templates/recent_changes.qtpl:15
}
//line templates/recent_changes.qtpl:15
qw422016.N().S(`
`)
//line templates/recent_changes.qtpl:16
}
//line templates/recent_changes.qtpl:16
qw422016.N().S(`
recent changes
</nav>
`)
//line templates/recent_changes.qtpl:25
qw422016.N().S(`
<section class="recent-changes__list" role="feed">
`)
//line templates/recent_changes.qtpl:28
if len(changes) == 0 {
//line templates/recent_changes.qtpl:28
qw422016.N().S(`
<p>Could not find any recent changes.</p>
`)
//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(`
<ul class="recent-changes__entry" role="article"
aria-setsize="`)
//line templates/recent_changes.qtpl:33
qw422016.N().D(n)
//line templates/recent_changes.qtpl:33
qw422016.N().S(`" aria-posinset="`)
//line templates/recent_changes.qtpl:33
qw422016.N().D(i)
//line templates/recent_changes.qtpl:33
qw422016.N().S(`">
`)
//line templates/recent_changes.qtpl:34
qw422016.N().S(entry)
//line templates/recent_changes.qtpl:34
qw422016.N().S(`
</ul>
`)
//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(`
</section>
</main>
`)
//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
}