Search Apps Documentation Source Content File Folder Download Copy Actions Download

render.gno

4.23 Kb ยท 169 lines
  1package impl
  2
  3import (
  4	"chain/runtime"
  5	"strconv"
  6	"strings"
  7
  8	"gno.land/p/moul/helplink"
  9	"gno.land/p/nt/avl/pager"
 10	"gno.land/p/nt/mux"
 11	"gno.land/p/nt/seqid"
 12	"gno.land/p/nt/ufmt"
 13	"gno.land/r/gov/dao"
 14	"gno.land/r/sys/users"
 15)
 16
 17type render struct {
 18	relativeRealmPath string
 19	router            *mux.Router
 20	pssPager          *pager.Pager
 21}
 22
 23func NewRender(d *GovDAO) *render {
 24	ren := &render{
 25		pssPager: pager.NewPager(d.pss.Tree, 5, true),
 26	}
 27
 28	r := mux.NewRouter()
 29
 30	r.HandleFunc("", func(rw *mux.ResponseWriter, req *mux.Request) {
 31		rw.Write(ren.renderActiveProposals(req.RawPath, d))
 32	})
 33
 34	r.HandleFunc("{pid}", func(rw *mux.ResponseWriter, req *mux.Request) {
 35		rw.Write(ren.renderProposalPage(req.GetVar("pid"), d))
 36	})
 37
 38	r.HandleFunc("{pid}/votes", func(rw *mux.ResponseWriter, req *mux.Request) {
 39		rw.Write(ren.renderVotesForProposal(req.GetVar("pid"), d))
 40	})
 41
 42	ren.router = r
 43
 44	return ren
 45}
 46
 47func (ren *render) Render(pkgPath string, path string) string {
 48	relativePath, found := strings.CutPrefix(pkgPath, runtime.ChainDomain())
 49	if !found {
 50		panic(ufmt.Sprintf(
 51			"realm package with unexpected name found: %v in chain domain %v",
 52			pkgPath, runtime.ChainDomain()))
 53	}
 54	ren.relativeRealmPath = relativePath
 55	return ren.router.Render(path)
 56}
 57
 58func (ren *render) renderActiveProposals(url string, d *GovDAO) string {
 59	out := "# GovDAO\n"
 60	out += "## Members\n"
 61	out += "[> Go to Memberstore <](/r/gov/dao/v3/memberstore)\n"
 62	out += "## Proposals\n"
 63	page := ren.pssPager.MustGetPageByPath(url)
 64	for _, item := range page.Items {
 65		seqpid, err := seqid.FromString(item.Key)
 66		if err != nil {
 67			panic(err.Error())
 68		}
 69		out += ren.renderProposalListItem(ufmt.Sprintf("%v", int64(seqpid)), d)
 70		out += "---\n\n"
 71	}
 72
 73	out += page.Picker("")
 74
 75	return out
 76}
 77
 78func (ren *render) renderProposalPage(sPid string, d *GovDAO) string {
 79	pid, err := strconv.ParseInt(sPid, 10, 64)
 80	if err != nil {
 81		panic(err.Error())
 82	}
 83	ps := d.pss.GetStatus(dao.ProposalID(pid))
 84	p := dao.MustGetProposal(cross, dao.ProposalID(pid))
 85	out := ufmt.Sprintf("## Prop #%v - %v\n", pid, p.Title())
 86	out += "Author: " + tryResolveAddr(p.Author()) + "\n\n"
 87
 88	out += p.Description()
 89	out += "\n\n"
 90
 91	out += "\n\n---\n\n"
 92	out += ps.String()
 93	out += "\n"
 94	out += ufmt.Sprintf("[Detailed voting list](%v:%v/votes)", ren.relativeRealmPath, pid)
 95	out += "\n\n---\n\n"
 96
 97	out += renderActionBar(ufmt.Sprintf("%v", pid))
 98
 99	return out
100}
101
102func (ren *render) renderProposalListItem(sPid string, d *GovDAO) string {
103	pid, err := strconv.ParseInt(sPid, 10, 64)
104	if err != nil {
105		panic(err.Error())
106	}
107	ps := d.pss.GetStatus(dao.ProposalID(pid))
108	p := dao.MustGetProposal(cross, dao.ProposalID(pid))
109	out := ufmt.Sprintf("### [Prop #%v - %v](%v:%v)\n", pid, p.Title(), ren.relativeRealmPath, pid)
110	out += ufmt.Sprintf("Author: %s\n\n", tryResolveAddr(p.Author()))
111
112	out += "Status: " + getPropStatus(ps)
113	out += "\n\n"
114
115	out += "Tiers eligible to vote: "
116	out += strings.Join(ps.TiersAllowedToVote, ", ")
117
118	out += "\n\n"
119	return out
120}
121
122func (ren *render) renderVotesForProposal(sPid string, d *GovDAO) string {
123	pid, err := strconv.ParseInt(sPid, 10, 64)
124	if err != nil {
125		panic(err.Error())
126	}
127	ps := d.pss.GetStatus(dao.ProposalID(pid))
128
129	out := ""
130	out += ufmt.Sprintf("# Proposal #%v - Vote List\n\n", pid)
131	out += StringifyVotes(ps)
132
133	return out
134}
135
136func isPropActive(ps *proposalStatus) bool {
137	return !ps.Accepted && !ps.Denied
138}
139
140func getPropStatus(ps *proposalStatus) string {
141	if ps.Accepted {
142		return "ACCEPTED"
143	} else if ps.Denied {
144		return "REJECTED"
145	}
146	return "ACTIVE"
147}
148
149func renderActionBar(sPid string) string {
150	out := "### Actions\n"
151
152	proxy := helplink.Realm("gno.land/r/gov/dao")
153	out += proxy.Func("Vote YES", "MustVoteOnProposalSimple", "pid", sPid, "option", "YES") + " | "
154	out += proxy.Func("Vote NO", "MustVoteOnProposalSimple", "pid", sPid, "option", "NO") + " | "
155	out += proxy.Func("Vote ABSTAIN", "MustVoteOnProposalSimple", "pid", sPid, "option", "ABSTAIN")
156
157	out += "\n\n"
158	out += "WARNING: Please double check transaction data before voting.\n\n"
159	out += "**New**: Members **must** have a namespace to vote to enforce simpler tracking."
160	return out
161}
162
163func tryResolveAddr(addr address) string {
164	userData := users.ResolveAddress(addr)
165	if userData == nil {
166		return addr.String()
167	}
168	return userData.RenderLink("")
169}