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

app.gno

3.08 Kb · 112 lines
  1package home
  2
  3import (
  4	"chain"
  5	"chain/runtime/unsafe"
  6	"strings"
  7
  8	"gno.land/r/nym-alexiscolin000/gnoradio/catalog/v1"
  9	"gno.land/r/nym-alexiscolin000/gnoradio/data"
 10)
 11
 12// The site's two settings live in the data realm, "home/config", so a later
 13// home release keeps them: "app" is the GnoRadio app (dApp) that pages link
 14// to, "" hides the links; "contact" is an extra way to reach the moderator,
 15// shown with the notice path, "" hides the line (the on-chain Report needs
 16// none). Only the catalog admin sets them: home has no admin of its own.
 17const (
 18	cConfig    = "home/config"
 19	maxAppURL  = 100
 20	maxContact = 120
 21)
 22
 23// init makes home/config while this realm is the home writer (release 1 at
 24// deploy); a later release finds it made.
 25func init(cur realm) {
 26	if data.Writer("home") == cur.PkgPath() {
 27		data.Make(cross(cur), cConfig)
 28	}
 29}
 30
 31// Ready tells the data realm that this release is on chain (see
 32// data.Propose). Anyone may call it.
 33func Ready(cur realm) {
 34	noPayment()
 35	data.Ready(cross(cur))
 36}
 37
 38func noPayment() {
 39	if len(unsafe.OriginSend()) != 0 {
 40		panic("home: this action does not take coins")
 41	}
 42}
 43
 44func onlyCatalogAdmin(cur realm) {
 45	if !cur.Previous().IsUserCall() || cur.Previous().Address() != catalog.Admin() {
 46		panic("home: catalog admin only")
 47	}
 48	noPayment()
 49}
 50
 51// SetAppURL sets the app link shown on every page: an https URL of at most
 52// 100 characters from [A-Za-z0-9-._~/:%], or "" to remove it. Catalog admin only.
 53func SetAppURL(cur realm, url string) {
 54	onlyCatalogAdmin(cur)
 55	if url != "" && !validAppURL(url) {
 56		panic("home: app URL must be https://, at most 100 characters of A-Z a-z 0-9 - . _ ~ / : %")
 57	}
 58	data.Set(cross(cur), cConfig, "app", url)
 59	chain.Emit("AppURLSet", "url", url)
 60}
 61
 62// SetContact sets the contact line shown next to the notice path (a web form,
 63// a postal address…): one line of at most 120 characters, or "" to remove it.
 64// Catalog admin only.
 65func SetContact(cur realm, line string) {
 66	onlyCatalogAdmin(cur)
 67	line = strings.TrimSpace(line)
 68	if len(line) > maxContact || strings.ContainsAny(line, "\r\n") {
 69		panic("home: the contact is one line of at most 120 characters")
 70	}
 71	data.Set(cross(cur), cConfig, "contact", line)
 72	chain.Emit("ContactSet", "contact", line)
 73}
 74
 75func validAppURL(u string) bool {
 76	if !strings.HasPrefix(u, "https://") || len(u) <= len("https://") || len(u) > maxAppURL {
 77		return false
 78	}
 79	for _, c := range u {
 80		switch {
 81		case c >= 'a' && c <= 'z', c >= 'A' && c <= 'Z', c >= '0' && c <= '9':
 82		case strings.ContainsRune("-._~/:%", c):
 83		default:
 84			return false
 85		}
 86	}
 87	return true
 88}
 89
 90// appURL and contact read the settings.
 91// appURL is checked again when read: a later release may write it.
 92func appURL() string {
 93	if v, _ := data.Get(cConfig, "app"); validAppURL(v) {
 94		return v
 95	}
 96	return ""
 97}
 98
 99func contact() string {
100	v, _ := data.Get(cConfig, "contact")
101	return v
102}
103
104// inApp links an app route (e.g. "track/12", "" for the player), or returns
105// "" when no app URL is set.
106func inApp(route, label string) string {
107	u := appURL()
108	if u == "" {
109		return ""
110	}
111	return "[" + label + "](" + strings.TrimRight(u, "/") + "/" + route + ")"
112}