profile.gno
3.73 Kb · 155 lines
1package gnocial
2
3import (
4 "chain"
5 "chain/runtime"
6 "strconv"
7 "strings"
8)
9
10// Register opens a profile for the calling account.
11// handle is 3–16 chars of a-z, 0-9 and underscore. referrer may be empty
12// or the bech32 address of an existing member. A member can register once.
13func Register(cur realm, handle, name, bio, referrer string) {
14 who := caller(cur)
15 mustNoPay()
16 if profileByAddr(who) != nil {
17 panic("already registered")
18 }
19 handle = strings.ToLower(strings.TrimSpace(handle))
20 if !validHandle(handle) {
21 panic("bad handle")
22 }
23 if state.byHandle.Has(handle) {
24 panic("handle taken")
25 }
26 if name == "" {
27 name = handle
28 }
29 name = cleanLine(name, maxNameRunes, maxNameBytes, "name", false)
30 bio = cleanLine(bio, maxBioRunes, maxBioBytes, "bio", true)
31
32 var ref address
33 referrer = strings.TrimSpace(referrer)
34 if referrer != "" {
35 if len(referrer) > 60 {
36 panic("bad referrer")
37 }
38 ref = address(referrer)
39 if !ref.IsValid() {
40 panic("bad referrer")
41 }
42 if ref == who {
43 panic("self referral")
44 }
45 if profileByAddr(ref) == nil {
46 panic("referrer not registered")
47 }
48 }
49
50 p := &Profile{
51 Addr: who,
52 Handle: handle,
53 Name: name,
54 Bio: bio,
55 Referrer: ref,
56 Joined: runtime.ChainHeight(),
57 CreatorFee: CreatorFeeDefaultBps,
58 }
59 state.byAddr.Set(who.String(), p)
60 state.byHandle.Set(handle, p)
61 state.books.Set(who.String(), &book{})
62 chain.Emit(
63 "ArenaRegister",
64 "addr", who.String(),
65 "handle", handle,
66 "referrer", ref.String(),
67 )
68}
69
70// SetCreatorFee stores this member's share of each ticket trade, in basis points.
71// Only that member can change it. The trade total stays FeeCapBps.
72func SetCreatorFee(cur realm, points int64) {
73 who := caller(cur)
74 mustNoPay()
75 p := mustMember(who)
76 if points < CreatorFeeMinBps || points > CreatorFeeMaxBps {
77 panic("fee")
78 }
79 p.CreatorFee = points
80 chain.Emit(
81 "ArenaCreatorFee",
82 "addr", who.String(),
83 "handle", p.Handle,
84 "bps", strconv.FormatInt(points, 10),
85 )
86}
87
88// UpdateProfile replaces the display name and bio. The handle stays.
89func UpdateProfile(cur realm, name, bio string) {
90 who := caller(cur)
91 mustNoPay()
92 p := mustMember(who)
93 if strings.TrimSpace(name) == "" {
94 name = p.Handle
95 }
96 p.Name = cleanLine(name, maxNameRunes, maxNameBytes, "name", false)
97 p.Bio = cleanLine(bio, maxBioRunes, maxBioBytes, "bio", true)
98 chain.Emit("ArenaProfile", "addr", who.String(), "handle", p.Handle)
99}
100
101// Follow records that the caller follows handle.
102func Follow(cur realm, handle string) {
103 who := caller(cur)
104 mustNoPay()
105 self := mustMember(who)
106 target := lookup(handle)
107 if target == nil {
108 panic("unknown handle")
109 }
110 if target.Addr == who {
111 panic("cannot follow self")
112 }
113 k := followKey(who, target.Addr)
114 if state.follows.Has(k) {
115 panic("already following")
116 }
117 state.follows.Set(k, 1)
118 state.fans.Set(fanKey(target.Addr, who), 1)
119 self.Following++
120 target.Followers++
121 chain.Emit("ArenaFollow", "from", who.String(), "to", target.Addr.String(), "handle", target.Handle)
122}
123
124// Unfollow removes a follow.
125func Unfollow(cur realm, handle string) {
126 who := caller(cur)
127 mustNoPay()
128 self := mustMember(who)
129 target := lookup(handle)
130 if target == nil {
131 panic("unknown handle")
132 }
133 k := followKey(who, target.Addr)
134 if !state.follows.Has(k) {
135 panic("not following")
136 }
137 state.follows.Remove(k)
138 state.fans.Remove(fanKey(target.Addr, who))
139 if self.Following > 0 {
140 self.Following--
141 }
142 if target.Followers > 0 {
143 target.Followers--
144 }
145 chain.Emit("ArenaUnfollow", "from", who.String(), "to", target.Addr.String(), "handle", target.Handle)
146}
147
148// Following reports whether from follows the handle.
149func Following(from address, handle string) bool {
150 target := lookup(handle)
151 if target == nil {
152 return false
153 }
154 return state.follows.Has(followKey(from, target.Addr))
155}