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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

render.gno

3.96 Kb · 174 lines
  1package user
  2
  3import (
  4	"net/url"
  5	"strconv"
  6	"strings"
  7
  8	"gno.land/p/jeronimoalbi/pager/v0"
  9	"gno.land/r/akkadia/beta/admin"
 10)
 11
 12// Render handles RESTful routing and returns Markdown responses.
 13func Render(iUrl string) string {
 14	assertRenderURLLen(iUrl)
 15	u, err := url.Parse(iUrl)
 16	if err != nil {
 17		return "404\n"
 18	}
 19
 20	query := u.Query()
 21
 22	switch u.Path {
 23	case "":
 24		return renderHome()
 25	case "users":
 26		return renderUsersList(iUrl)
 27	case "user":
 28		addr := address(query.Get("address"))
 29		return renderUser(iUrl, addr)
 30	default:
 31		return renderError("Not found")
 32	}
 33}
 34
 35func renderHome() string {
 36	output := `# AKKADIA User
 37
 38## Introduction
 39
 40User realm stores address-keyed profiles for AKKADIA.
 41
 42- **created_at**: recorded when the user is created
 43- **properties**: admin-managed key/value attributes
 44
 45## Stats
 46
 47`
 48	output += "* **Total Users**: " + strconv.Itoa(GetTotalUserSize()) + "\n"
 49	output += `
 50## Quick Links
 51
 52* [Browse Users](./user:users)
 53
 54## User Lookup
 55
 56<gno-form path="user">
 57  <gno-input name="address" placeholder="Enter the address" />
 58</gno-form>
 59`
 60	return output
 61}
 62
 63func renderUsersList(iUrl string) string {
 64	output := "# Users\n\n"
 65	output += "[← Home](./user:)\n\n"
 66
 67	totalUsers := GetTotalUserSize()
 68	if totalUsers == 0 {
 69		output += "*No users registered yet.*\n"
 70		return output
 71	}
 72
 73	pages, err := pager.New(iUrl, totalUsers, pager.WithPageSize(20))
 74	if err != nil {
 75		return renderError("Invalid page")
 76	}
 77
 78	currentPage := pages.Page()
 79	addrStrs := ListUsers(currentPage, pages.PageSize())
 80	for _, addrStr := range addrStrs {
 81		nickname := ""
 82		listed := ListUsersByAddresses(address(addrStr))
 83		if len(listed) > 0 {
 84			nickname = listed[0]["nickname"]
 85		}
 86		if nickname != "" {
 87			output += "* [" + escapeMarkdown(nickname) + " (" + addrStr + ")](./user:user?address=" + addrStr + "&page=" + strconv.Itoa(currentPage) + ")\n"
 88		} else {
 89			output += "* [" + addrStr + "](./user:user?address=" + addrStr + "&page=" + strconv.Itoa(currentPage) + ")\n"
 90		}
 91	}
 92
 93	if pages.HasPages() {
 94		output += "\n" + pager.Picker(pages)
 95	}
 96
 97	return output
 98}
 99
100func renderUser(iUrl string, addr address) string {
101	if !addr.IsValid() {
102		return renderError("Invalid address")
103	}
104
105	u, _ := url.Parse(iUrl)
106	page := normalizeRenderPage(u.Query().Get("page"))
107
108	addrStr := addr.String()
109	if !HasUser(addr) {
110		return renderError("User not found")
111	}
112
113	users := ListUsersByAddresses(addr)
114
115	output := "# User Detail\n\n"
116	if page != "" {
117		output += "[← Back to List](./user:users?page=" + page + ")\n\n"
118	} else {
119		output += "[← Home](./user:)\n\n"
120	}
121	output += "* **Address**: " + addrStr + " [[View on Explorer](" + admin.GetExplorerURL() + "/m/explorer/player?address=" + addrStr + ")]\n\n"
122
123	if len(users) > 0 {
124		output += "## Properties\n\n"
125		for k, v := range users[0] {
126			if k == "address" {
127				continue
128			}
129			output += "* **" + escapeMarkdown(k) + "**: " + escapeMarkdown(v) + "\n"
130		}
131	}
132
133	return output
134}
135
136func normalizeRenderPage(rawPage string) string {
137	if rawPage == "" {
138		return ""
139	}
140	page, err := strconv.Atoi(rawPage)
141	if err != nil || page < 1 {
142		return ""
143	}
144	return strconv.Itoa(page)
145}
146
147func renderError(message string) string {
148	output := "# Error\n\n"
149	output += "> " + message + "\n\n"
150	output += "[← Back to Home](./user:)\n"
151	return output
152}
153
154func escapeMarkdown(s string) string {
155	s = strings.ReplaceAll(s, "\\", "\\\\")
156	s = strings.ReplaceAll(s, "\n", "\\n")
157	s = strings.ReplaceAll(s, "`", "\\`")
158	s = strings.ReplaceAll(s, "*", "\\*")
159	s = strings.ReplaceAll(s, "_", "\\_")
160	s = strings.ReplaceAll(s, "{", "\\{")
161	s = strings.ReplaceAll(s, "}", "\\}")
162	s = strings.ReplaceAll(s, "[", "\\[")
163	s = strings.ReplaceAll(s, "]", "\\]")
164	s = strings.ReplaceAll(s, "(", "\\(")
165	s = strings.ReplaceAll(s, ")", "\\)")
166	s = strings.ReplaceAll(s, "#", "\\#")
167	s = strings.ReplaceAll(s, "+", "\\+")
168	s = strings.ReplaceAll(s, "-", "\\-")
169	s = strings.ReplaceAll(s, ".", "\\.")
170	s = strings.ReplaceAll(s, "!", "\\!")
171	s = strings.ReplaceAll(s, "|", "\\|")
172	s = strings.ReplaceAll(s, ">", "\\>")
173	return s
174}