Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}