Pure package detail
basedao
gno.land/p/samcrew/basedao
Indexed deployment identity with independently loaded latest RPC source. Functions and Render are realm-only RPC capabilities.
Indexed deployment
Identity
- Package path
- gno.land/p/samcrew/basedao
- Block
- 98962
- Deployed (UTC)
- Transaction
- vFRzo/FVwQsb8Cx+tKBmj8a88A034YhkhP+ftPai79c=
Latest RPC state
Source
package basedao
import (
"chain"
"gno.land/p/onbloc/json"
"gno.land/p/samcrew/avl"
)
type MembersStore struct {
Roles *avl.Tree // role name -> *Role
Members *avl.Tree // string -> *avl.Tree [roles -> struct{}]
}
type Member struct {
Address string
Roles []string
}
type RoleInfo struct {
Name string
Description string
Color string
}
type Role struct {
Name string
Description string
Color string
Members *avl.Tree // string -> struct{}
}
const EventAddMember = "BaseDAOAddMember"
const EventRemoveMember = "BaseDAORemoveMember"
func NewMembersStore(initialRoles []RoleInfo, initialMembers []Member) *MembersStore {
res := &MembersStore{
Roles: avl.NewTree(),
Members: avl.NewTree(),
}
res.setRoles(initialRoles)
res.setMembers(initialMembers)
return res
}
func (m *MembersStore) HasRole(member string, role string) bool {
rolesRaw, ok := m.Members.Get(member)
if !ok {
return false
}
roles, ok := rolesRaw.(*avl.Tree)
if !ok {
return false
}
return roles.Has(role)
}
func (m *MembersStore) IsMember(member string) bool {
return m.Members.Has(member)
}
func (m *MembersStore) RoleInfo(role string) RoleInfo {
roleDataRaw, ok := m.Roles.Get(role)
if !ok {
panic("role does not exist")
}
roleData, ok := roleDataRaw.(*Role)
if !ok {
panic("a value of memberstore.roles is not a Role, should not happen")
}
return RoleInfo{
Name: roleData.Name,
Description: roleData.Description,
Color: roleData.Color,
}
}
func (m *MembersStore) MembersCount() uint64 {
return uint64(m.Members.Size())
}
func (m *MembersStore) GetMembers() []string {
members := make([]string, 0, m.Members.Size())
m.Members.Iterate("", "", func(key string, value interface{}) bool {
members = append(members, key)
return false
})
return members
}
func (m *MembersStore) GetRoles() []string {
i := 0
res := make([]string, m.Roles.Size())
m.Roles.Iterate("", "", func(key string, value interface{}) bool {
res[i] = key
i++
return false
})
return res
}
func (m *MembersStore) GetMemberRoles(member string) []string {
rolesRaw, ok := m.Members.Get(member)
if !ok {
return []string{}
}
roles, ok := rolesRaw.(*avl.Tree)
if !ok {
return []string{}
}
i := 0
res := make([]string, roles.Size())
roles.Iterate("", "", func(key string, value interface{}) bool {
res[i] = key
i++
return false
})
return res
}
func (m *MembersStore) CountMemberRoles(member string) int {
rolesRaw, ok := m.Members.Get(member)
if !ok {
return 0
}
roles, ok := rolesRaw.(*avl.Tree)
if !ok {
return 0
}
return roles.Size()
}
func (m *MembersStore) GetMembersWithRole(role string) []string {
roleDataRaw, ok := m.Roles.Get(role)
if !ok {
return []string{}
}
roleData, ok := roleDataRaw.(*Role)
if !ok {
return []string{}
}
i := 0
res := make([]string, roleData.Members.Size())
roleData.Members.Iterate("", "", func(key string, value interface{}) bool {
res[i] = key
i++
return false
})
return res
}
func (m *MembersStore) CountMembersWithRole(role string) uint32 {
return uint32(len(m.GetMembersWithRole(role)))
}
func (m *MembersStore) GetMembersWithoutRole() []string {
var res []string
m.Members.Iterate("", "", func(key string, value interface{}) bool {
roles := m.GetMemberRoles(key)
if len(roles) == 0 {
res = append(res, key)
}
return false
})
return res
}
func (m *MembersStore) CountMembersWithoutRole() uint32 {
return uint32(len(m.GetMembersWithoutRole()))
}
func (m *MembersStore) setRoles(roles []RoleInfo) {
for _, role := range roles {
m.AddRole(role)
}
}
func (m *MembersStore) setMembers(members []Member) {
for _, member := range members {
m.AddMember(member.Address, member.Roles)
}
}
func (m *MembersStore) AddMember(member string, roles []string) {
// "" is what CallerID resolves to when it cannot name the caller.
if member == "" {
panic("member id must not be empty")
}
if m.IsMember(member) {
panic("member already exists")
}
membersRoles := avl.NewTree()
for _, role := range roles {
if !m.Roles.Has(role) {
panic("role: " + role + " does not exist")
}
membersRoles.Set(role, struct{}{})
roleDataRaw, _ := m.Roles.Get(role)
roleData := roleDataRaw.(*Role)
roleData.Members.Set(member, struct{}{})
}
m.Members.Set(member, membersRoles)
chain.Emit(EventAddMember,
"address", member,
)
}
func (m *MembersStore) RemoveMember(member string) {
if !m.IsMember(member) {
panic("member does not exist")
}
// A zero-member DAO is unrecoverable: assertCallerIsMember rejects every
// entry point, so not even AddMember can be proposed again.
if m.MembersCount() <= 1 {
panic("cannot remove the last member")
}
memberRolesRaw, ok := m.Members.Get(member)
if !ok {
panic("should not happen")
}
memberRoles, ok := memberRolesRaw.(*avl.Tree)
if !ok {
panic("a value of memberstore.members is not an avl.Tree, should not happen")
}
memberRoles.Iterate("", "", func(key string, value interface{}) bool {
roleRaw, ok := m.Roles.Get(key)
if !ok {
return false
}
role, ok := roleRaw.(*Role)
if !ok {
panic("a value of memberstore.roles is not a Role, should not happen")
}
role.Members.Remove(member)
return false
})
m.Members.Remove(member)
chain.Emit(EventRemoveMember,
"address", member,
)
}
func (m *MembersStore) AddRole(role RoleInfo) {
// An empty role name is not merely useless, it is destructive. Role names
// are substituted into rendered prose by RenderWithRolesLinks, and
// strings.ReplaceAll with an empty needle matches between every character:
// "hello world" comes back as 227 characters of repeated link. Once a DAO is
// published there is no way to remove the role from a render path.
if role.Name == "" {
panic("role name must not be empty")
}
if m.Roles.Has(role.Name) {
panic("role already exists")
}
roleData := &Role{
Name: role.Name,
Description: role.Description,
Color: role.Color,
Members: avl.NewTree(),
}
m.Roles.Set(role.Name, roleData)
}
func (m *MembersStore) RemoveRole(role string) {
roleDataRaw, ok := m.Roles.Get(role)
if !ok {
panic("role does not exist")
}
roleData, ok := roleDataRaw.(*Role)
if !ok {
panic("a value of memberstore.roles is not a Role, should not happen")
}
roleData.Members.Iterate("", "", func(key string, value interface{}) bool {
memberRaw, ok := m.Members.Get(key)
if !ok {
return false
}
member, ok := memberRaw.(*avl.Tree)
if !ok {
panic("a value of memberstore.members is not an avl.Tree, should not happen")
}
member.Remove(role)
return false
})
m.Roles.Remove(role)
}
func (m *MembersStore) AddRoleToMember(member string, role string) {
if !m.IsMember(member) {
panic("member does not exist")
}
if !m.Roles.Has(role) {
panic("role " + role + " does not exist")
}
if m.HasRole(member, role) {
panic("member already has the role")
}
memberRolesRaw, ok := m.Members.Get(member)
if !ok {
panic("should not happen")
}
memberRoles, ok := memberRolesRaw.(*avl.Tree)
if !ok {
panic("a value of memberstore.members is not an avl.Tree, should not happen")
}
roleDataRaw, ok := m.Roles.Get(role)
if !ok {
panic("should not happen")
}
roleData, ok := roleDataRaw.(*Role)
if !ok {
panic("a value of memberstore.roles is not a Role, should not happen")
}
roleData.Members.Set(member, struct{}{})
memberRoles.Set(role, struct{}{})
}
func (m *MembersStore) RemoveRoleFromMember(member string, role string) {
if !m.IsMember(member) {
panic("member does not exist")
}
if !m.Roles.Has(role) {
panic("role " + role + " does not exist")
}
if !m.HasRole(member, role) {
panic("member does not have the role")
}
memberRolesRaw, ok := m.Members.Get(member)
if !ok {
panic("should not happen")
}
memberRoles, ok := memberRolesRaw.(*avl.Tree)
if !ok {
panic("a value of memberstore.members is not an avl.Tree, should not happen")
}
roleDataRaw, ok := m.Roles.Get(role)
if !ok {
panic("should not happen")
}
roleData, ok := roleDataRaw.(*Role)
if !ok {
panic("a value of memberstore.roles is not a Role, should not happen")
}
memberRoles.Remove(role)
roleData.Members.Remove(member)
}
func (m *MembersStore) GetMembersJSON() string {
// XXX: replace with protoc-gen-gno
members := []*json.Node{}
for _, memberID := range m.GetMembers() {
roles := []*json.Node{}
for _, role := range m.GetMemberRoles(memberID) {
roles = append(roles, json.StringNode("", role))
}
members = append(members, json.ObjectNode("", map[string]*json.Node{
"address": json.StringNode("", memberID),
"roles": json.ArrayNode("", roles),
}))
}
node := json.ArrayNode("", members)
bz, err := json.Marshal(node)
if err != nil {
panic(err)
}
return string(bz)
}
The verified vm/qfuncs operation accepts realm paths only.
Pure packages expose source files but do not have Realm Render.