Skip to content

Commit

Permalink
Add recent changes
Browse files Browse the repository at this point in the history
Closes #51
  • Loading branch information
csmith committed Apr 4, 2021
1 parent a16ade2 commit d87f176
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 39 deletions.
1 change: 1 addition & 0 deletions content/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

* [List all pages](/wiki/index)
* [List all files](/wiki/files)
* [Recent changes](/wiki/changes)
* [Upload a file](/wiki/upload)
* [Change password](/wiki/account)
* [Manage users](/wiki/users)
90 changes: 80 additions & 10 deletions git.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"log"
"os"
"path"
"path/filepath"
"sort"
"strings"
Expand Down Expand Up @@ -62,25 +63,21 @@ func (g *GitBackend) PageExists(title string) bool {
return err == nil && !fi.IsDir()
}

func (g *GitBackend) PageHistory(title string, start string, end int) (*History, error) {
func (g *GitBackend) PageHistory(title string, start string, count int) (*History, error) {
g.mutex.RLock()
defer g.mutex.RUnlock()

var history []*LogEntry
_, gitPath, err := resolvePath(g.dir, fmt.Sprintf("%s.md", title))
if err != nil {
return nil, err
}
var revision *plumbing.Hash
var commitIter object.CommitIter
if start == "" {
start = "HEAD"
}
revision, err = g.repo.ResolveRevision(plumbing.Revision(start))

revision, err := g.resolveRevision(start)
if err != nil {
return nil, err
}
commitIter, err = g.repo.Log(&git.LogOptions{

commitIter, err := g.repo.Log(&git.LogOptions{
From: *revision,
PathFilter: func(s string) bool {
return s == gitPath
Expand All @@ -89,7 +86,9 @@ func (g *GitBackend) PageHistory(title string, start string, end int) (*History,
if err != nil {
return nil, err
}
for i := 0; i < end; i++ {

var history []*LogEntry
for i := 0; i < count; i++ {
commit, err := commitIter.Next()
if err != nil {
if err == io.EOF {
Expand All @@ -104,6 +103,7 @@ func (g *GitBackend) PageHistory(title string, start string, end int) (*History,
Message: commit.Message,
})
}

return &History{Entries: history}, nil
}

Expand Down Expand Up @@ -314,6 +314,9 @@ func (g *GitBackend) writeFile(filePath, gitPath string, content io.Reader, user
}

func (g *GitBackend) RenamePage(name string, newName string, message string, user string) error {
g.mutex.Lock()
defer g.mutex.Unlock()

_, gitPath, err := resolvePath(g.dir, fmt.Sprintf("%s.md", name))
if err != nil {
log.Printf("Unable to resolve old path: %s -> %s: %s", name, newName, err.Error())
Expand Down Expand Up @@ -345,6 +348,9 @@ func (g *GitBackend) RenamePage(name string, newName string, message string, use
}

func (g *GitBackend) DeletePage(name string, message string, user string) error {
g.mutex.Lock()
defer g.mutex.Unlock()

_, gitPath, err := resolvePath(g.dir, fmt.Sprintf("%s.md", name))
if err != nil {
return err
Expand All @@ -367,6 +373,70 @@ func (g *GitBackend) DeletePage(name string, message string, user string) error
return nil
}

func (g *GitBackend) RecentChanges(start string, count int) ([]*RecentChange, error) {
g.mutex.Lock()
defer g.mutex.Unlock()

revision, err := g.resolveRevision(start)
if err != nil {
return nil, err
}

commitIter, err := g.repo.Log(&git.LogOptions{From: *revision})
if err != nil {
return nil, err
}

var history []*RecentChange
for i := 0; i < count; i++ {
commit, err := commitIter.Next()
if err != nil {
if err == io.EOF {
break
}
return nil, err
}

stats, err := commit.Stats()
if err != nil {
return nil, err
}

entry := &RecentChange{
LogEntry: LogEntry{
ChangeId: commit.Hash.String(),
User: commit.Author.Name,
Time: commit.Author.When,
Message: commit.Message,
},
}

for j := range stats {
file := stats[j]
if filepath.Dir(file.Name) == ".wiki" {
entry.Config = strings.TrimSuffix(filepath.Base(file.Name), ".json.enc")
break
} else if path.Ext(file.Name) == ".md" {
entry.Page = strings.TrimSuffix(file.Name, ".md")
break
} else {
entry.File = file.Name
break
}
}

history = append(history, entry)
}
return history, nil
}

func (g *GitBackend) resolveRevision(rv string) (*plumbing.Hash, error) {
if rv == "" {
rv = "HEAD"
}
return g.repo.ResolveRevision(plumbing.Revision(rv))
}

func resolvePath(base, name string) (string, string, error) {
p := filepath.Clean(filepath.Join(base, name))
p = strings.ToLower(p)
Expand Down
59 changes: 40 additions & 19 deletions handlers_history.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type HistoryProvider interface {
}

func PageHistoryHandler(t *Templates, pp HistoryProvider) http.HandlerFunc {
const historySize = 20
const historySize = 50

return func(w http.ResponseWriter, r *http.Request) {
pageTitle := strings.TrimPrefix(r.URL.Path, "/history/")
Expand All @@ -32,28 +32,49 @@ func PageHistoryHandler(t *Templates, pp HistoryProvider) http.HandlerFunc {
return
}

var entries []*HistoryEntry
for i := range history.Entries {
c := history.Entries[i]
if c.ChangeId == start {
continue
}
entries = append(entries, &HistoryEntry{
Id: c.ChangeId,
User: c.User,
Time: c.Time,
Message: c.Message,
})
if len(entries) == historySize {
break
}
var next string
if len(history.Entries) == number {
next = history.Entries[number-1].ChangeId
} else {
number = len(history.Entries) + 1
}

t.RenderHistory(w, r, pageTitle, history.Entries[:number-1], next)
}
}

type RecentChangesProvider interface {
RecentChanges(start string, count int) ([]*RecentChange, error)
}

func RecentChangesHandler(t *Templates, rp RecentChangesProvider) http.HandlerFunc {
const historySize = 50

return func(w http.ResponseWriter, r *http.Request) {
var start string
var number = historySize + 1

q := r.URL.Query()["after"]
if q != nil {
// If the user is paginating, request 22 items so we get the start item, the 20 we want to show, then
// an extra one to tell if there's a next page or not.
start = q[0]
number = historySize + 2
}

history, err := rp.RecentChanges(start, number)
if err != nil {
http.NotFound(w, r)
return
}

var next string
if len(history.Entries) == number {
next = history.Entries[number-2].ChangeId
if len(history) == number {
next = history[number-1].ChangeId
} else {
number = len(history) + 1
}

t.RenderHistory(w, r, pageTitle, entries, next)
t.RenderRecentChanges(w, r, history[:number-1], next)
}
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func main() {
wikiRouter.Path("/wiki/account").Handler(auth(ModifyAccountHandler(userManager))).Methods(http.MethodPost)
wikiRouter.Path("/wiki/index").Handler(read(ListPagesHandler(templates, gitBackend))).Methods(http.MethodGet)
wikiRouter.Path("/wiki/files").Handler(read(ListFilesHandler(templates, gitBackend))).Methods(http.MethodGet)
wikiRouter.Path("/wiki/changes").Handler(read(RecentChangesHandler(templates, gitBackend))).Methods(http.MethodGet)
wikiRouter.Path("/wiki/login").Handler(LoginHandler(userManager)).Methods(http.MethodPost)
wikiRouter.Path("/wiki/logout").Handler(LogoutHandler()).Methods(http.MethodPost)
wikiRouter.Path("/wiki/upload").Handler(write(UploadFormHandler(templates))).Methods(http.MethodGet)
Expand Down
7 changes: 7 additions & 0 deletions model.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ package main

import "time"

type RecentChange struct {
Page string
File string
Config string
LogEntry
}

type LogEntry struct {
ChangeId string
User string
Expand Down
27 changes: 18 additions & 9 deletions templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,11 @@ func (t *Templates) RenderUploadForm(w http.ResponseWriter, r *http.Request) {

type HistoryPageArgs struct {
Common CommonArgs
History []*HistoryEntry
History []*LogEntry
Next string
}

type HistoryEntry struct {
Id string
User string
Time time.Time
Message string
}

func (t *Templates) RenderHistory(w http.ResponseWriter, r *http.Request, title string, entries []*HistoryEntry, next string) {
func (t *Templates) RenderHistory(w http.ResponseWriter, r *http.Request, title string, entries []*LogEntry, next string) {
t.render("history.gohtml", http.StatusOK, w, &HistoryPageArgs{
Common: t.populateArgs(w, r, CommonArgs{
PageTitle: title,
Expand All @@ -158,6 +151,22 @@ func (t *Templates) RenderHistory(w http.ResponseWriter, r *http.Request, title
})
}

type RecentChangesArgs struct {
Common CommonArgs
Changes []*RecentChange
Next string
}

func (t *Templates) RenderRecentChanges(w http.ResponseWriter, r *http.Request, entries []*RecentChange, next string) {
t.render("changes.gohtml", http.StatusOK, w, &RecentChangesArgs{
Common: t.populateArgs(w, r, CommonArgs{
PageTitle: "Recent changes",
}),
Changes: entries,
Next: next,
})
}

type ManageUsersArgs struct {
Common CommonArgs
Users []UserInfo
Expand Down
28 changes: 28 additions & 0 deletions templates/changes.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{- /*gotype: github.com/mdbot/wiki.RecentChangesArgs*/ -}}
{{template "header" .Common}}
<ul>
{{range .Changes}}
<li>
<span class="commitish">{{.LogEntry.ChangeId}}</span>
{{if .Page}}
<a href="/view/{{.Page}}" class="wikilink">{{.Page}}</a>
{{else if .File}}
<a href="/file/{{.File}}">{{.File}}</a>
{{else if .Config}}
{{.Config}} config
{{else}}
<em>[Unknown]</em>
{{end}}
changed by {{.LogEntry.User}} at {{.LogEntry.Time.Format "Jan 02, 2006 15:04:05 UTC"}}
{{if .LogEntry.Message}}
({{.LogEntry.Message}})
{{else}}
<em>[No message supplied]</em>
{{end}}
</li>
{{end}}
</ul>
{{if .Next}}
<p><a href="?after={{.Next}}">Next &raquo;</a></p>
{{end}}
{{template "footer" .Common}}
2 changes: 1 addition & 1 deletion templates/history.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<ul>
{{range .History}}
<li>
<span class="commitish">{{.Id}}</span>
<span class="commitish">{{.ChangeId}}</span>
changed by {{.User}} at {{.Time.Format "Jan 02, 2006 15:04:05 UTC"}}
{{if .Message}}
({{.Message}})
Expand Down

0 comments on commit d87f176

Please sign in to comment.