members.gno
7.28 Kb ยท 341 lines
1package basedao
2
3import (
4 "chain"
5
6 "gno.land/p/nt/avl"
7 "gno.land/p/onbloc/json"
8)
9
10type MembersStore struct {
11 Roles *avl.Tree // role name -> *Role
12 Members *avl.Tree // string -> *avl.Tree [roles -> struct{}]
13}
14
15type Member struct {
16 Address string
17 Roles []string
18}
19
20type RoleInfo struct {
21 Name string
22 Description string
23}
24
25type Role struct {
26 Name string
27 Description string
28 Members *avl.Tree // string -> struct{}
29}
30
31const EventAddMember = "BaseDAOAddMember"
32const EventRemoveMember = "BaseDAORemoveMember"
33
34func NewMembersStore(initialRoles []RoleInfo, initialMembers []Member) *MembersStore {
35 res := &MembersStore{
36 Roles: avl.NewTree(),
37 Members: avl.NewTree(),
38 }
39 res.setRoles(initialRoles)
40 res.setMembers(initialMembers)
41 return res
42}
43
44func (m *MembersStore) HasRole(member string, role string) bool {
45 rolesRaw, ok := m.Members.Get(member)
46 if !ok {
47 return false
48 }
49 roles, ok := rolesRaw.(*avl.Tree)
50 if !ok {
51 return false
52 }
53 return roles.Has(role)
54}
55
56func (m *MembersStore) IsMember(member string) bool {
57 return m.Members.Has(member)
58}
59
60func (m *MembersStore) RoleInfo(role string) RoleInfo {
61 roleDataRaw, ok := m.Roles.Get(role)
62 if !ok {
63 panic("role does not exist")
64 }
65 roleData, ok := roleDataRaw.(*Role)
66 if !ok {
67 panic("a value of memberstore.roles is not a Role, should not happen")
68 }
69 return RoleInfo{
70 Name: roleData.Name,
71 Description: roleData.Description,
72 }
73}
74
75func (m *MembersStore) MembersCount() uint64 {
76 return uint64(m.Members.Size())
77}
78
79func (m *MembersStore) GetMembers() []string {
80 members := make([]string, 0, m.Members.Size())
81 m.Members.Iterate("", "", func(key string, value interface{}) bool {
82 members = append(members, key)
83 return false
84 })
85 return members
86}
87
88func (m *MembersStore) GetRoles() []string {
89 i := 0
90 res := make([]string, m.Roles.Size())
91 m.Roles.Iterate("", "", func(key string, value interface{}) bool {
92 res[i] = key
93 i++
94 return false
95 })
96 return res
97}
98
99func (m *MembersStore) GetMemberRoles(member string) []string {
100 rolesRaw, ok := m.Members.Get(member)
101 if !ok {
102 return []string{}
103 }
104 roles, ok := rolesRaw.(*avl.Tree)
105 if !ok {
106 return []string{}
107 }
108 i := 0
109 res := make([]string, roles.Size())
110 roles.Iterate("", "", func(key string, value interface{}) bool {
111 res[i] = key
112 i++
113 return false
114 })
115 return res
116}
117
118func (m *MembersStore) CountMemberRoles(member string) int {
119 rolesRaw, ok := m.Members.Get(member)
120 if !ok {
121 return 0
122 }
123 roles, ok := rolesRaw.(*avl.Tree)
124 if !ok {
125 return 0
126 }
127 return roles.Size()
128}
129
130func (m *MembersStore) GetMembersWithRole(role string) []string {
131 roleDataRaw, ok := m.Roles.Get(role)
132 if !ok {
133 return []string{}
134 }
135 roleData, ok := roleDataRaw.(*Role)
136 if !ok {
137 return []string{}
138 }
139 i := 0
140 res := make([]string, roleData.Members.Size())
141 roleData.Members.Iterate("", "", func(key string, value interface{}) bool {
142 res[i] = key
143 i++
144 return false
145 })
146 return res
147}
148
149func (m *MembersStore) CountMembersWithRole(role string) uint32 {
150 return uint32(len(m.GetMembersWithRole(role)))
151}
152
153func (m *MembersStore) setRoles(roles []RoleInfo) {
154 for _, role := range roles {
155 m.AddRole(role)
156 }
157}
158
159func (m *MembersStore) setMembers(members []Member) {
160 for _, member := range members {
161 m.AddMember(member.Address, member.Roles)
162 }
163}
164
165func (m *MembersStore) AddMember(member string, roles []string) {
166 if m.IsMember(member) {
167 panic("member already exists")
168 }
169
170 membersRoles := avl.NewTree()
171 for _, role := range roles {
172 if !m.Roles.Has(role) {
173 panic("role: " + role + " does not exist")
174 }
175 membersRoles.Set(role, struct{}{})
176 }
177 m.Members.Set(member, membersRoles)
178
179 chain.Emit(EventAddMember,
180 "address", member,
181 )
182}
183
184func (m *MembersStore) RemoveMember(member string) {
185 if !m.IsMember(member) {
186 panic("member does not exist")
187 }
188
189 memberRolesRaw, ok := m.Members.Get(member)
190 if !ok {
191 panic("should not happen")
192 }
193 memberRoles, ok := memberRolesRaw.(*avl.Tree)
194 if !ok {
195 panic("a value of memberstore.members is not an avl.Tree, should not happen")
196 }
197
198 memberRoles.Iterate("", "", func(key string, value interface{}) bool {
199 roleRaw, ok := m.Roles.Get(key)
200 if !ok {
201 return false
202 }
203 role, ok := roleRaw.(*Role)
204 if !ok {
205 panic("a value of memberstore.roles is not a Role, should not happen")
206 }
207 role.Members.Remove(role.Name)
208 return false
209 })
210 m.Members.Remove(member)
211
212 chain.Emit(EventRemoveMember,
213 "address", member,
214 )
215}
216
217func (m *MembersStore) AddRole(role RoleInfo) {
218 if m.Roles.Has(role.Name) {
219 panic("role already exists")
220 }
221
222 roleData := &Role{
223 Name: role.Name,
224 Description: role.Description,
225 Members: avl.NewTree(),
226 }
227
228 m.Roles.Set(role.Name, roleData)
229}
230
231func (m *MembersStore) RemoveRole(role string) {
232 roleDataRaw, ok := m.Roles.Get(role)
233 if !ok {
234 panic("role does not exist")
235 }
236 roleData, ok := roleDataRaw.(*Role)
237 if !ok {
238 panic("a value of memberstore.roles is not a Role, should not happen")
239 }
240
241 roleData.Members.Iterate("", "", func(key string, value interface{}) bool {
242 memberRaw, ok := m.Members.Get(key)
243 if !ok {
244 return false
245 }
246 member, ok := memberRaw.(*avl.Tree)
247 if !ok {
248 panic("a value of memberstore.members is not an avl.Tree, should not happen")
249 }
250 member.Remove(role)
251 return false
252 })
253 m.Roles.Remove(role)
254}
255
256func (m *MembersStore) AddRoleToMember(member string, role string) {
257 if !m.IsMember(member) {
258 panic("member does not exist")
259 }
260 if !m.Roles.Has(role) {
261 panic("role " + role + " does not exist")
262 }
263 if m.HasRole(member, role) {
264 panic("member already has the role")
265 }
266
267 memberRolesRaw, ok := m.Members.Get(member)
268 if !ok {
269 panic("should not happen")
270 }
271 memberRoles, ok := memberRolesRaw.(*avl.Tree)
272 if !ok {
273 panic("a value of memberstore.members is not an avl.Tree, should not happen")
274 }
275
276 roleDataRaw, ok := m.Roles.Get(role)
277 if !ok {
278 panic("should not happen")
279 }
280 roleData, ok := roleDataRaw.(*Role)
281 if !ok {
282 panic("a value of memberstore.roles is not a Role, should not happen")
283 }
284
285 roleData.Members.Set(member, struct{}{})
286 memberRoles.Set(role, struct{}{})
287}
288
289func (m *MembersStore) RemoveRoleFromMember(member string, role string) {
290 if !m.IsMember(member) {
291 panic("member does not exist")
292 }
293 if !m.Roles.Has(role) {
294 panic("role " + role + " does not exist")
295 }
296 if !m.HasRole(member, role) {
297 panic("member does not have the role")
298 }
299
300 memberRolesRaw, ok := m.Members.Get(member)
301 if !ok {
302 panic("should not happen")
303 }
304 memberRoles, ok := memberRolesRaw.(*avl.Tree)
305 if !ok {
306 panic("a value of memberstore.members is not an avl.Tree, should not happen")
307 }
308
309 roleDataRaw, ok := m.Roles.Get(role)
310 if !ok {
311 panic("should not happen")
312 }
313 roleData, ok := roleDataRaw.(*Role)
314 if !ok {
315 panic("a value of memberstore.roles is not a Role, should not happen")
316 }
317
318 memberRoles.Remove(role)
319 roleData.Members.Remove(member)
320}
321
322func (m *MembersStore) GetMembersJSON() string {
323 // XXX: replace with protoc-gen-gno
324 members := []*json.Node{}
325 for _, memberID := range m.GetMembers() {
326 roles := []*json.Node{}
327 for _, role := range m.GetMemberRoles(memberID) {
328 roles = append(roles, json.StringNode("", role))
329 }
330 members = append(members, json.ObjectNode("", map[string]*json.Node{
331 "address": json.StringNode("", memberID),
332 "roles": json.ArrayNode("", roles),
333 }))
334 }
335 node := json.ArrayNode("", members)
336 bz, err := json.Marshal(node)
337 if err != nil {
338 panic(err)
339 }
340 return string(bz)
341}