permissions_validators_open.gno
4.54 Kb ยท 177 lines
1package boards2
2
3import (
4 "chain/banker"
5 "errors"
6
7 "gno.land/p/gnoland/boards"
8 "gno.land/p/nt/ufmt"
9
10 "gno.land/r/gnoland/boards2/v1/permissions"
11 "gno.land/r/sys/users"
12)
13
14// validateOpenBoardRename validates PermissionBoardRename.
15//
16// Expected `args` values:
17// 1. Caller address
18// 2. Board ID
19// 3. Current board name
20// 4. New board name
21func validateOpenBoardRename(_ boards.Permissions, args boards.Args) error {
22 caller, ok := args[0].(address)
23 if !ok {
24 return errors.New("expected a valid caller address")
25 }
26
27 newName, ok := args[3].(string)
28 if !ok {
29 return errors.New("expected new board name to be a string")
30 }
31
32 if err := checkBoardNameIsNotAddress(newName); err != nil {
33 return err
34 }
35
36 if err := checkBoardNameBelongsToAddress(caller, newName); err != nil {
37 return err
38 }
39 return nil
40}
41
42// validateOpenMemberInvite validates PermissionMemberInvite.
43//
44// Expected `args` values:
45// 1. Caller address
46// 2. Board ID
47// 3. Invites
48func validateOpenMemberInvite(perms boards.Permissions, args boards.Args) error {
49 caller, ok := args[0].(address)
50 if !ok {
51 return errors.New("expected a valid caller address")
52 }
53
54 invites, ok := args[2].([]Invite)
55 if !ok {
56 return errors.New("expected valid user invites")
57 }
58
59 // Make sure that only owners invite other owners
60 callerIsOwner := perms.HasRole(caller, permissions.RoleOwner)
61 for _, v := range invites {
62 if v.Role == permissions.RoleOwner && !callerIsOwner {
63 return errors.New("only owners are allowed to invite other owners")
64 }
65 }
66 return nil
67}
68
69// validateOpenRoleChange validates PermissionRoleChange.
70//
71// Expected `args` values:
72// 1. Caller address
73// 2. Board ID
74// 3. Member address
75// 4. Role
76func validateOpenRoleChange(perms boards.Permissions, args boards.Args) error {
77 caller, ok := args[0].(address)
78 if !ok {
79 return errors.New("expected a valid caller address")
80 }
81
82 // Owners and Admins can change roles.
83 // Admins should not be able to assign or remove the Owner role from members.
84 if perms.HasRole(caller, permissions.RoleAdmin) {
85 role, ok := args[3].(boards.Role)
86 if !ok {
87 return errors.New("expected a valid member role")
88 }
89
90 if role == permissions.RoleOwner {
91 return errors.New("admins are not allowed to promote members to Owner")
92 } else {
93 member, ok := args[2].(address)
94 if !ok {
95 return errors.New("expected a valid member address")
96 }
97
98 if perms.HasRole(member, permissions.RoleOwner) {
99 return errors.New("admins are not allowed to remove the Owner role")
100 }
101 }
102 }
103 return nil
104}
105
106// validateOpenThreadCreate validates PermissionThreadCreate.
107//
108// Expected `args` values:
109// 1. Caller address
110// 2. Board ID
111// 3. Thread ID
112// 4. Title
113// 5. Body
114func validateOpenThreadCreate(perms boards.Permissions, args boards.Args) error {
115 caller, ok := args[0].(address)
116 if !ok {
117 return errors.New("expected a valid caller address")
118 }
119
120 // Owners and admins can create threads without a registered username
121 if perms.HasRole(caller, permissions.RoleOwner) || perms.HasRole(caller, permissions.RoleAdmin) {
122 return nil
123 }
124
125 // Require registered usernames to non members
126 if users.ResolveAddress(caller) == nil {
127 return errors.New("a registered username is required to create threads on open boards")
128 }
129
130 // Require non members to have some GNOT in their accounts
131 if err := checkAccountHasAmount(caller, gOpenAccountAmount); err != nil {
132 return ufmt.Errorf("caller is not allowed to create threads: %s", err)
133 }
134 return nil
135}
136
137// validateOpenReplyCreate validates PermissionReplyCreate.
138//
139// Expected `args` values:
140// 1. Caller address
141// 2. Board ID
142// 3. Thread ID
143// 4. Parent ID
144// 5. Reply ID
145// 6. Body
146func validateOpenReplyCreate(perms boards.Permissions, args boards.Args) error {
147 caller, ok := args[0].(address)
148 if !ok {
149 return errors.New("expected a valid caller address")
150 }
151
152 // All board members can reply
153 if perms.HasUser(caller) {
154 return nil
155 }
156
157 // Require registered usernames to non members
158 if users.ResolveAddress(caller) == nil {
159 return errors.New("a registered username is required to comment on open boards")
160 }
161
162 // Require non members to have some GNOT in their accounts
163 if err := checkAccountHasAmount(caller, gOpenAccountAmount); err != nil {
164 return ufmt.Errorf("caller is not allowed to comment: %s", err)
165 }
166 return nil
167}
168
169func checkAccountHasAmount(addr address, amount int64) error {
170 bnk := banker.NewBanker(banker.BankerTypeReadonly)
171 coins := bnk.GetCoins(addr)
172 if coins.AmountOf("ugnot") < gOpenAccountAmount {
173 amount = amount / 1_000_000 // ugnot -> GNOT
174 return ufmt.Errorf("account amount is lower than %d GNOT", amount)
175 }
176 return nil
177}