1package blog23import (4 "chain/runtime/unsafe"5 "errors"6 "strings"78 "gno.land/p/nt/bptree/v0"9 "gno.land/p/nt/ufmt/v0"10 "gno.land/r/gov/dao"11)1213var (14 errNotAdmin = errors.New("access restricted: not admin")15 errNotModerator = errors.New("access restricted: not moderator")16 errNotCommenter = errors.New("access restricted: not commenter")17)1819var (20 adminAddr = address("g1skl80cuz8zq3lul9pgz5pc35l2pfzgxgfpsqkx") // govdao t1 multisig21 moderatorList = bptree.NewBPTree32()22 commenterList = bptree.NewBPTree32()23 inPause bool24)2526func AdminSetAdminAddr(_ realm, addr address) {27 assertIsAdmin()28 adminAddr = addr29}3031func AdminSetInPause(_ realm, state bool) {32 assertIsAdmin()33 inPause = state34}3536func AdminAddModerator(_ realm, addr address) {37 assertIsAdmin()38 moderatorList.Set(addr.String(), true)39}4041func AdminRemoveModerator(_ realm, addr address) {42 assertIsAdmin()43 moderatorList.Set(addr.String(), false) // entry kept as a revocation record; isModerator checks the value44}4546func NewPostProposalRequest(cur realm, slug, title, body, publicationDate, authors, tags string) dao.ProposalRequest {47 caller := cur.Previous().Address()48 e := dao.NewSimpleExecutor(0, cur,49 func(realm) error {50 addPost(caller, slug, title, body, publicationDate, authors, tags)5152 return nil53 },54 ufmt.Sprintf("- Post Title: %v\n- Post Publication Date: %v\n- Authors: %v\n- Tags: %v", title, publicationDate, authors, tags),55 )5657 return dao.NewProposalRequest(58 "Add new post to gnoland blog",59 "This propoposal is looking to add a new post to gnoland blog",60 e,61 )62}6364func ModAddPost(_ realm, slug, title, body, publicationDate, authors, tags string) {65 assertIsModerator()66 caller := unsafe.OriginCaller()67 addPost(caller, slug, title, body, publicationDate, authors, tags)68}6970func addPost(caller address, slug, title, body, publicationDate, authors, tags string) {71 var tagList []string72 if tags != "" {73 tagList = strings.Split(tags, ",")74 }75 var authorList []string76 if authors != "" {77 authorList = strings.Split(authors, ",")78 }7980 err := b.NewPost(caller, slug, title, body, publicationDate, authorList, tagList)8182 checkErr(err)83}8485func ModEditPost(_ realm, slug, title, body, publicationDate, authors, tags string) {86 assertIsModerator()87 tagList := strings.Split(tags, ",")88 authorList := strings.Split(authors, ",")8990 err := b.GetPost(slug).Update(title, body, publicationDate, authorList, tagList)91 checkErr(err)92}9394func ModRemovePost(_ realm, slug string) {95 assertIsModerator()96 b.RemovePost(slug)97}9899func ModAddCommenter(_ realm, addr address) {100 assertIsModerator()101 commenterList.Set(addr.String(), true)102}103104func ModDelCommenter(_ realm, addr address) {105 assertIsModerator()106 commenterList.Set(addr.String(), false) // entry kept as a revocation record; isCommenter checks the value107}108109func ModDelComment(_ realm, slug string, index int) {110 assertIsModerator()111 err := b.GetPost(slug).DeleteComment(index)112 checkErr(err)113}114115func isAdmin(addr address) bool {116 return addr == adminAddr117}118119func isModerator(addr address) bool {120 // Removed moderators stay in the list with a false value, so the121 // stored value must be checked, not just key presence.122 active, _ := moderatorList.Get(addr.String()).(bool)123 return active124}125126func isCommenter(addr address) bool {127 // Removed commenters stay in the list with a false value, so the128 // stored value must be checked, not just key presence.129 active, _ := commenterList.Get(addr.String()).(bool)130 return active131}132133func assertIsAdmin() {134 caller := unsafe.OriginCaller()135 if !isAdmin(caller) {136 panic(errNotAdmin.Error())137 }138}139140func assertIsModerator() {141 caller := unsafe.OriginCaller()142 if isAdmin(caller) || isModerator(caller) {143 return144 }145 panic(errNotModerator.Error())146}147148func assertIsCommenter() {149 caller := unsafe.OriginCaller()150 if isAdmin(caller) || isModerator(caller) || isCommenter(caller) {151 return152 }153 panic(errNotCommenter.Error())154}155156func assertNotInPause() {157 if inPause {158 panic("access restricted (pause)")159 }160}161AddComment(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, postSlug string, comment string)
AdminAddModerator(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string)
AdminRemoveModerator(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string)
AdminSetAdminAddr(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string)
AdminSetInPause(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, state bool)
ModAddCommenter(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string)
ModAddPost(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string, title string, body string, publicationDate string, authors string, tags string)
ModDelComment(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string, index int)
ModDelCommenter(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string)
ModEditPost(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string, title string, body string, publicationDate string, authors string, tags string)
ModRemovePost(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string)
NewPostProposalRequest(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string, title string, body string, publicationDate string, authors string, tags string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}
PostExists(slug string) bool
Render(path string) string
RenderLastPostsWidget(limit int) string
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.