history_reads.gno
6.08 Kb · 126 lines
1package memba_notes_v1
2
3import "strconv"
4
5func PublicHistoryInfoJSON(idHex string) string {
6 id := historyID(idHex)
7 h := historyGet(id)
8 if h == nil {
9 return "null"
10 }
11 n := h.Latest.State
12 return `{"schema":"memba.notes.public-history-info/v1","id":` + q(idHex) + `,"start_state_revision":` + u(h.StartRevision) + `,"start_body_revision":` + u(h.StartBodyRevision) + `,"head_seq":` + u(h.Head) + `,"latest_state_revision":` + u(n.Revision) + `,"retention":"public-moderator-redactable","coverage":"public-since-publication-v1","deleted":` + strconv.FormatBool(n.Deleted) + `,"moderator_hidden":` + strconv.FormatBool(n.ModeratorHidden) + `}`
13}
14func historyEntryFields(e *historyEntry) string {
15 proposal := "null"
16 if e.Proposal != 0 {
17 proposal = u(e.Proposal)
18 }
19 return `"seq":` + u(e.Seq) + `,"action":` + q(e.Action) + `,"height":` + q(strconv.FormatInt(e.Height, 10)) + `,"state_revision":` + u(e.Revision) + `,"actor":` + q(string(e.Actor)) + `,"executor":` + historyNullableText(string(e.Executor)) + `,"op_id":` + historyNullableID(e.Operation) + `,"proposal_id":` + proposal
20}
21func PublicHistoryJSON(idHex string, afterSeq, throughSeq uint64, limit int) string {
22 id := historyID(idHex)
23 if limit < 1 || limit > 20 {
24 panic("notes: history page limit")
25 }
26 h := historyGet(id)
27 if h == nil {
28 return "null"
29 }
30 if throughSeq == 0 {
31 if afterSeq != 0 {
32 panic("notes: history first page cursor")
33 }
34 throughSeq = h.Head
35 }
36 if afterSeq > throughSeq || throughSeq > h.Head {
37 panic("notes: history cursor")
38 }
39 items, next := "", "null"
40 last, count := afterSeq, 0
41 // Direct keys preserve contiguity without a scan or after+limit overflow.
42 for last < throughSeq && count < limit {
43 last++
44 v, ok := historyEntries.Get(historyKey(id, last))
45 if !ok {
46 panic("notes: history gap")
47 }
48 e := v.(*historyEntry)
49 if count > 0 {
50 items += ","
51 }
52 items += "{" + historyEntryFields(e) + `,"comment_id":` + historyNullableID(e.Comment) + "}"
53 count++
54 }
55 if last < throughSeq {
56 next = u(last)
57 }
58 return `{"schema":"memba.notes.public-history-page/v1","id":` + q(idHex) + `,"through_seq":` + u(throughSeq) + `,"items":[` + items + `],"next_cursor":` + next + `}`
59}
60func PublicHistoryEntryJSON(idHex string, seq uint64) string {
61 v, ok := historyEntries.Get(historyKey(historyID(idHex), seq))
62 if !ok {
63 return "null"
64 }
65 e := v.(*historyEntry)
66 return `{"schema":"memba.notes.public-history-entry/v1","id":` + q(idHex) + "," + historyEntryFields(e) + `,"governance_action":` + historyNullableText(e.GovernanceAction) + `,"detail":` + e.Detail + `}`
67}
68func PublicHistoryVersionJSON(idHex string, stateRevision uint64) string {
69 raw, ok := historyVersions.Get(historyKey(historyID(idHex), stateRevision))
70 if !ok {
71 return "null"
72 }
73 v := raw.(*historyVersion)
74 n := v.State
75 titleRevision, title, bodyRevision, bodyHash, bodyBytes := "null", "null", "null", "null", "0"
76 titleRedacted, bodyRedacted := false, false
77 if v.Title != nil {
78 titleRevision, titleRedacted = u(n.TitleRevision), v.Title.Redacted
79 if !titleRedacted {
80 title = blob(v.Title.Bytes)
81 }
82 }
83 if v.Body != nil {
84 bodyRevision, bodyHash, bodyBytes, bodyRedacted = u(n.BodyRevision), q(v.Body.Hash), strconv.Itoa(len(v.Body.Bytes)), v.Body.Redacted
85 }
86 writers := ""
87 for i, who := range n.Writers {
88 if i > 0 {
89 writers += ","
90 }
91 writers += q(string(who))
92 }
93 return `{"schema":"memba.notes.public-history-version/v1","id":` + q(idHex) + `,"state_revision":` + u(n.Revision) + `,"recorded_seq":` + u(v.Seq) + `,"owner":` + q(string(n.Owner)) + `,"pending_owner":` + historyNullableText(string(n.PendingOwner)) + `,"owner_is_realm":` + strconv.FormatBool(n.OwnerIsRealm) + `,"owner_generation":` + u(n.OwnerGeneration) + `,"mode":` + strconv.Itoa(int(n.Mode)) + `,"epoch":` + u(uint64(n.Epoch)) + `,"title_revision":` + titleRevision + `,"title_blob":` + title + `,"title_redacted":` + strconv.FormatBool(titleRedacted) + `,"body_revision":` + bodyRevision + `,"body_bytes":` + q(bodyBytes) + `,"body_sha256":` + bodyHash + `,"body_redacted":` + strconv.FormatBool(bodyRedacted) + `,"writers":[` + writers + `],"policies":{"read":` + q(n.Policies[0]) + `,"write":` + q(n.Policies[1]) + `,"comment":` + q(n.Policies[2]) + `},"gov_writers":` + strconv.FormatBool(n.GovWriters) + `,"allow_public_writes":` + strconv.FormatBool(v.PublicWrites) + `,"owner_listed":` + strconv.FormatBool(n.Listed) + `,"moderator_hidden":` + strconv.FormatBool(n.ModeratorHidden) + `,"deleted":` + strconv.FormatBool(n.Deleted) + `}`
94}
95func PublicHistoryBodyChunkJSON(idHex string, bodyRevision uint64, offset, limit int) string {
96 id := historyID(idHex)
97 if limit < 1 || limit > MaxBodyChunkBytes || offset < 0 {
98 panic("notes: history chunk bounds")
99 }
100 v, ok := historyBlobs.Get("body:" + historyKey(id, bodyRevision))
101 if !ok {
102 return "null"
103 }
104 b := v.(*historyBlob)
105 if b.Redacted {
106 return "null"
107 }
108 if offset > len(b.Bytes) {
109 panic("notes: history chunk bounds")
110 }
111 end := offset + limit
112 if end > len(b.Bytes) {
113 end = len(b.Bytes)
114 }
115 return `{"schema":"memba.notes.public-history-body/v1","id":` + q(idHex) + `,"body_revision":` + u(bodyRevision) + `,"sha256":` + q(b.Hash) + `,"offset":` + q(strconv.Itoa(offset)) + `,"total":` + q(strconv.Itoa(len(b.Bytes))) + `,"next_offset":` + q(strconv.Itoa(end)) + `,"chunk_blob":` + blob(b.Bytes[offset:end]) + `}`
116}
117func PublicHistoryCommentJSON(idHex, cidHex string) string {
118 id, cid := historyID(idHex), historyID(cidHex)
119 v, ok := historyComments.Get(commentKey(id, cid))
120 if !ok {
121 return "null"
122 }
123 h := v.(*historyComment)
124 c := h.Initial
125 return `{"schema":"memba.notes.public-history-comment/v1","id":` + q(idHex) + `,"comment_id":` + q(cidHex) + `,"content":{"author":` + q(string(c.Author)) + `,"created_height":` + q(strconv.FormatInt(c.CreatedHeight, 10)) + `,"epoch":` + u(uint64(c.Epoch)) + `,"anchor_blob":` + blob(c.Anchor) + `,"body_blob":` + blob(c.Body) + `,"reference":` + historyCommentDetail(&c, h) + `},"presentation":{"latest_seq":` + u(h.LatestSeq) + `,"deleted":` + strconv.FormatBool(h.Deleted) + `,"hidden":` + strconv.FormatBool(h.Hidden) + `,"resolved":` + strconv.FormatBool(h.Resolved) + `,"redacted":` + strconv.FormatBool(h.Redacted) + `}}`
126}