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

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}