Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

page.gno

3.27 Kb · 122 lines
  1package wiki
  2
  3import (
  4	"time"
  5
  6	"gno.land/p/nym-moultest123/ulist/v0"
  7)
  8
  9// Protection is a page's edit gate. The engine stores it and reports it; it
 10// never enforces it, because authority belongs to the realm that owns the
 11// wiki, not to a pure library. See Wiki.Edit.
 12type Protection uint8
 13
 14const (
 15	Open          Protection = iota // anyone the realm lets through
 16	SemiProtected                   // realm-defined trusted editors
 17	Locked                          // stewards only
 18)
 19
 20// String returns the protection level's display name.
 21func (p Protection) String() string {
 22	switch p {
 23	case SemiProtected:
 24		return "semi-protected"
 25	case Locked:
 26		return "locked"
 27	default:
 28		return "open"
 29	}
 30}
 31
 32// ParseProtection maps a user-supplied level name onto a Protection.
 33func ParseProtection(s string) (Protection, error) {
 34	switch s {
 35	case "open", "":
 36		return Open, nil
 37	case "semi", "semi-protected":
 38		return SemiProtected, nil
 39	case "locked":
 40		return Locked, nil
 41	}
 42	return Open, ErrBadProtection
 43}
 44
 45// Page is one title's history plus the indexes derived from its current
 46// revision. Revisions live in a ulist: append is O(1) and does not rewrite the
 47// existing entries, which matters when a popular page accumulates thousands of
 48// edits and every write would otherwise re-serialize the whole slice.
 49type Page struct {
 50	Title      Title
 51	Protection Protection
 52	Created    time.Time
 53	Blanked    bool // a steward blanked it; history is retained
 54
 55	revs *ulist.List // *Revision, oldest first
 56	head *Revision
 57
 58	redirect string   // target title, "" when this page is not a redirect
 59	links    []string // outgoing wikilink target keys of head
 60	cats     []string // category keys head belongs to
 61}
 62
 63// Head returns the current revision, or nil for a page with no revisions.
 64func (p *Page) Head() *Revision { return p.head }
 65
 66// NumRevisions returns how many revisions the page has.
 67func (p *Page) NumRevisions() int { return p.revs.Size() }
 68
 69// Redirect returns the title this page redirects to, or "" if it does not.
 70func (p *Page) Redirect() string { return p.redirect }
 71
 72// Body returns the current text and whether it is held on chain.
 73func (p *Page) Body() (string, bool) {
 74	if p.head == nil {
 75		return "", false
 76	}
 77	return p.head.Body()
 78}
 79
 80// Revision returns the revision with the given id, or nil.
 81func (p *Page) Revision(id uint64) *Revision {
 82	var found *Revision
 83	p.revs.Iterator(0, p.revs.Size()-1, func(_ int, v any) bool {
 84		r := v.(*Revision)
 85		if r.ID == id {
 86			found = r
 87			return true
 88		}
 89		return false
 90	})
 91	return found
 92}
 93
 94// History returns up to count revisions, newest first, skipping the newest
 95// offset of them.
 96func (p *Page) History(offset, count int) []*Revision {
 97	out := []*Revision{}
 98	if count <= 0 {
 99		return out
100	}
101	size := p.revs.Size()
102	// Walk backwards: index size-1 is the newest.
103	for i := size - 1 - offset; i >= 0 && len(out) < count; i-- {
104		out = append(out, p.revs.MustGet(i).(*Revision))
105	}
106	return out
107}
108
109// Contributors returns the distinct authors of the page, oldest edit first.
110func (p *Page) Contributors() []address {
111	seen := map[string]bool{}
112	out := []address{}
113	p.revs.Iterator(0, p.revs.Size()-1, func(_ int, v any) bool {
114		r := v.(*Revision)
115		if !seen[r.Author.String()] {
116			seen[r.Author.String()] = true
117			out = append(out, r.Author)
118		}
119		return false
120	})
121	return out
122}