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.

sitelink.gno

2.92 Kb · 121 lines
  1package kourt
  2import (
  3	"chain"
  4	"strconv"
  5	"strings"
  6)
  7const maxSiteDomainLen = 100
  8var siteDomain string
  9func siteDomainFault(d string) string {
 10	if len(d) < 4 || len(d) > maxSiteDomainLen {
 11		return "a site domain is 4..100 characters"
 12	}
 13	if !strings.Contains(d, ".") {
 14		return "a site domain needs a dot — it is a hostname, not a word"
 15	}
 16	if d[0] == '.' || d[0] == '-' || d[len(d)-1] == '.' || d[len(d)-1] == '-' {
 17		return "a site domain may not begin or end with a dot or a hyphen"
 18	}
 19	for i := 0; i < len(d); i++ {
 20		c := d[i]
 21		ok := (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-'
 22		if !ok {
 23			return "a site domain is lowercase letters, digits, dots and " +
 24				"hyphens only — no scheme, no path, no port"
 25		}
 26	}
 27	if strings.Contains(d, "..") {
 28		return "a site domain may not contain an empty label"
 29	}
 30	return ""
 31}
 32func mustSiteDomain(d string) {
 33	if fault := siteDomainFault(d); fault != "" {
 34		panic("kourtv2: " + fault)
 35	}
 36}
 37func SetSiteDomain(cur realm, domain string) {
 38	if !cur.IsCurrent() {
 39		panic(errStaleRealm)
 40	}
 41	d := ensureGlobalDAO()
 42	if cur.Previous().Address() != d.admin {
 43		panic("kourtv2: only the global DAO admin sets the site domain")
 44	}
 45	mustSiteDomain(domain)
 46	siteDomain = domain
 47	chain.Emit(globalActEvent,
 48		"court", "*",
 49		"claim", "0",
 50		"act", "set-site-domain:"+domain,
 51		"by", cur.Previous().Address().String(),
 52		"height", eventHeight(),
 53	)
 54}
 55func ClearSiteDomain(cur realm) {
 56	if !cur.IsCurrent() {
 57		panic(errStaleRealm)
 58	}
 59	d := ensureGlobalDAO()
 60	if cur.Previous().Address() != d.admin {
 61		panic("kourtv2: only the global DAO admin clears the site domain")
 62	}
 63	if siteDomain == "" {
 64		panic("kourtv2: no site domain is set")
 65	}
 66	siteDomain = ""
 67	chain.Emit(globalActEvent,
 68		"court", "*",
 69		"claim", "0",
 70		"act", "clear-site-domain",
 71		"by", cur.Previous().Address().String(),
 72		"height", eventHeight(),
 73	)
 74}
 75func SiteDomain() string { return siteDomain }
 76func sitePath(path string) string {
 77	parts := strings.SplitN(path, "/", 4)
 78	if path == "" || parts[0] == "" {
 79		return "#/"
 80	}
 81	if len(parts) == 1 {
 82		if parts[0] == helpPath {
 83			return "#/"
 84		}
 85		if parts[0] == adminParamsPath {
 86			return "#/params"
 87		}
 88		return "#/c/" + parts[0]
 89	}
 90	switch parts[1] {
 91	case "me":
 92		return "#/me"
 93	case "mod":
 94		return "#/c/" + parts[0]
 95	}
 96	if _, err := strconv.ParseUint(parts[1], 10, 64); err != nil {
 97		return "#/c/" + parts[0]
 98	}
 99	return "#/c/" + parts[0] + "/" + parts[1]
100}
101func withSiteBanner(body, path string) string {
102	bar := siteBanner(path)
103	if bar == "" {
104		return body
105	}
106	if !strings.HasPrefix(body, "# ") {
107		return bar + body
108	}
109	i := strings.Index(body, "\n")
110	if i < 0 {
111		return body + "\n\n" + bar
112	}
113	return body[:i+1] + "\n" + bar + strings.TrimLeft(body[i+1:], "\n")
114}
115func siteBanner(path string) string {
116	if siteDomain == "" || siteDomainFault(siteDomain) != "" {
117		return ""
118	}
119	return "[Read this on " + siteDomain + " →](https://" + siteDomain + "/" +
120		sitePath(path) + ")\n\n"
121}