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