Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}