boardlegal.gno
4.92 Kb · 171 lines
1package kourt
2import "strconv"
3func boardActCode(verb string, rowID uint64, categoryCode string) string {
4 code := verb + "#" + strconv.FormatUint(rowID, 10)
5 if categoryCode != "" {
6 code += ":" + categoryCode
7 }
8 return code
9}
10const (
11 boardCodeSpam = "spam"
12 boardCodeOffTopic = "off-topic"
13 boardCodeAbuse = "abuse"
14 boardCodeImpersonation = "impersonation"
15 boardCodeIllegal = "illegal-referred"
16)
17func mustBoardCode(code string) {
18 switch code {
19 case boardCodeSpam, boardCodeOffTopic, boardCodeAbuse,
20 boardCodeImpersonation, boardCodeIllegal:
21 return
22 }
23 panic("kourtv2: a board moderation code is one of: spam, off-topic, abuse, " +
24 "impersonation, illegal-referred")
25}
26func BoardCodes() string {
27 return boardCodeSpam + "," + boardCodeOffTopic + "," + boardCodeAbuse + "," +
28 boardCodeImpersonation + "," + boardCodeIllegal
29}
30func GlobalHideRow(cur realm, courtSlug string, claimID, rowID uint64, categoryCode string) {
31 if !cur.IsCurrent() {
32 panic(errStaleRealm)
33 }
34 who := cur.Previous().Address()
35 if !isGlobalMod(who) {
36 panic("kourtv2: only a global DAO member may globally hide a comment")
37 }
38 checkReason(categoryCode)
39 c := mustCourt(courtSlug)
40 cs := mustClaim(c, claimID)
41 r := mustBoardRow(cs, rowID)
42 if r.purged {
43 panic("kourtv2: that comment was already destroyed; there is nothing to withhold")
44 }
45 now := heightNow()
46 if !r.global && r.globalClearedAt != 0 &&
47 reSetWindowOpen(r.globalClearedAtTime, r.globalClearedAt, now) {
48 d := ensureGlobalDAO()
49 fire, _ := approveAction(d.pending,
50 "boardreset:"+c.id+":"+strconv.FormatUint(claimID, 10)+":"+strconv.FormatUint(rowID, 10),
51 who, categoryCode, d.purgeM)
52 if !fire {
53 return
54 }
55 }
56 r.global = true
57 scoreIndexDrop(cs, r)
58 ensureClaimMod(c, ensureMod(c), claimID).
59 appendLog(who, boardActCode("board-global-hide", rowID, categoryCode), "")
60 emitGlobalAct(c.id, claimID, "board-global-hide", who)
61}
62func GlobalClearRow(cur realm, courtSlug string, claimID, rowID uint64) {
63 if !cur.IsCurrent() {
64 panic(errStaleRealm)
65 }
66 who := cur.Previous().Address()
67 if !isGlobalMod(who) {
68 panic("kourtv2: only a global DAO member may clear a global comment hide")
69 }
70 c := mustCourt(courtSlug)
71 cs := mustClaim(c, claimID)
72 r := mustBoardRow(cs, rowID)
73 if !r.global {
74 panic("kourtv2: that comment is not globally hidden")
75 }
76 r.global = false
77 r.globalClearedAt = heightNow()
78 r.globalClearedAtTime = nowTime()
79 scoreIndexPut(cs, r)
80 ensureClaimMod(c, ensureMod(c), claimID).
81 appendLog(who, boardActCode("board-global-clear", rowID, ""), "")
82 emitGlobalAct(c.id, claimID, "board-global-clear", who)
83}
84func PurgeBoardRow(cur realm, courtSlug string, claimID, rowID uint64, categoryCode string) {
85 if !cur.IsCurrent() {
86 panic(errStaleRealm)
87 }
88 who := cur.Previous().Address()
89 d := ensureGlobalDAO()
90 if !d.members.Has(who.String()) {
91 panic("kourtv2: only a global DAO member may purge")
92 }
93 mustCategoryCode(categoryCode)
94 c := mustCourt(courtSlug)
95 cs := mustClaim(c, claimID)
96 r := mustBoardRow(cs, rowID)
97 if r.purged {
98 return
99 }
100 fire, votedCode := approveAction(d.pending,
101 "boardpurge:"+c.id+":"+strconv.FormatUint(claimID, 10)+":"+strconv.FormatUint(rowID, 10),
102 who, categoryCode, d.purgeM)
103 if !fire {
104 return
105 }
106 r.purged = true
107 r.text = ""
108 scoreIndexDrop(cs, r)
109 ensureClaimMod(c, ensureMod(c), claimID).
110 appendLog(who, boardActCode("board-purge", rowID, votedCode), "")
111 emitPurge(c.id, claimID, "board-row", who)
112}
113func BoardRowState(courtSlug string, claimID uint64, rowID uint64) string {
114 return boardMark(mustBoardRow(mustClaim(mustCourt(courtSlug), claimID), rowID))
115}
116const maxBatchRows = 64
117func PurgeBoardRange(cur realm, courtSlug string, claimID, fromRowID uint64, categoryCode string) uint64 {
118 if !cur.IsCurrent() {
119 panic(errStaleRealm)
120 }
121 who := cur.Previous().Address()
122 d := ensureGlobalDAO()
123 if !d.members.Has(who.String()) {
124 panic("kourtv2: only a global DAO member may purge")
125 }
126 mustCategoryCode(categoryCode)
127 c := mustCourt(courtSlug)
128 cs := mustClaim(c, claimID)
129 cm := ensureMod(c)
130 clm := lookupClaimMod(cm, claimID)
131 if clm == nil || !clm.boardPurgeAll {
132 fire, _ := approveAction(d.pending,
133 "boardpurgeall:"+c.id+":"+strconv.FormatUint(claimID, 10),
134 who, categoryCode, d.purgeM)
135 if !fire {
136 return fromRowID
137 }
138 clm = ensureClaimMod(c, cm, claimID)
139 clm.boardPurgeAll = true
140 clm.appendLog(who, boardActCode("board-purge-all", 0, categoryCode), "")
141 emitPurge(c.id, claimID, "board-all", who)
142 }
143 if cs.board == nil {
144 return 0
145 }
146 n, next := 0, uint64(0)
147 cs.board.Iterate(beClaimKey(fromRowID), "", func(_ string, v any) bool {
148 r := v.(*boardRow)
149 if r.purged {
150 return false
151 }
152 if n >= maxBatchRows {
153 next = r.id
154 return true
155 }
156 r.purged = true
157 r.text = ""
158 scoreIndexDrop(cs, r)
159 n++
160 return false
161 })
162 return next
163}
164func BoardPurgeOrdered(courtSlug string, claimID uint64) bool {
165 c := mustCourt(courtSlug)
166 if c.mod == nil {
167 return false
168 }
169 clm := lookupClaimMod(c.mod, claimID)
170 return clm != nil && clm.boardPurgeAll
171}