Skip to content

Commit

Permalink
feat(orgs): split creation flows + add new kind of roles based organi…
Browse files Browse the repository at this point in the history
…zation (#1429)

Co-authored-by: n0izn0iz <[email protected]>
  • Loading branch information
MikaelVallenet and n0izn0iz authored Dec 5, 2024
1 parent 5529005 commit b843b86
Show file tree
Hide file tree
Showing 46 changed files with 2,373 additions and 803 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { connectWallet, resetChain } from "./lib";
import { connectWallet, resetChain } from "../lib";

describe("Create an organization flow", () => {
it("works", () => {
Expand Down Expand Up @@ -26,7 +26,7 @@ describe("Create an organization flow", () => {
cy.get('[data-testid="organization-description"]').type(description);

cy.contains("Next: Configure voting").click();
cy.contains("Next: Set tokens or members").click();
cy.contains("Next: Set members").click();
cy.get('[data-testid="member-settings-next"]').click();
cy.contains("Confirm & Launch the Organization").click();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
changeSelectedMilestoneStatus,
changeTestUser,
connectWallet,
} from "./lib";
} from "../lib";

describe("Contractor proposer full flow", () => {
it("works", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
changeSelectedMilestoneStatus,
changeTestUser,
connectWallet,
} from "./lib";
} from "../lib";

describe("Funder proposer full flow", () => {
it("works", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { changeTestUser, connectWallet, resetChain } from "./lib";
import { changeTestUser, connectWallet, resetChain } from "../lib";

const showUppForm = () => {
cy.contains("Edit profile").click();
Expand Down
44 changes: 44 additions & 0 deletions gno/p/dao_core/dao_core.gno
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"strconv"
"strings"

"gno.land/p/demo/json"
dao_interfaces "gno.land/p/teritori/dao_interfaces"
"gno.land/p/teritori/jsonutil"
)

// TODO: add wrapper message handler to handle multiple proposal modules messages
Expand All @@ -14,6 +16,7 @@ type daoCore struct {
dao_interfaces.IDAOCore

votingModule dao_interfaces.IVotingModule
rolesModule dao_interfaces.IRolesModule
proposalModules []dao_interfaces.ActivableProposalModule
activeProposalModuleCount int
realm std.Realm
Expand All @@ -22,13 +25,18 @@ type daoCore struct {

func NewDAOCore(
votingModuleFactory dao_interfaces.VotingModuleFactory,
rolesModuleFactory dao_interfaces.RolesModuleFactory,
proposalModulesFactories []dao_interfaces.ProposalModuleFactory,
messageHandlersFactories []dao_interfaces.MessageHandlerFactory,
) dao_interfaces.IDAOCore {
if votingModuleFactory == nil {
panic("Missing voting module factory")
}

if rolesModuleFactory == nil {
panic("Missing roles module factory")
}

if len(proposalModulesFactories) == 0 {
panic("No proposal modules factories")
}
Expand All @@ -45,6 +53,11 @@ func NewDAOCore(
panic("voting module factory returned nil")
}

core.rolesModule = rolesModuleFactory(core)
if core.rolesModule == nil {
panic("roles module factory returned nil")
}

for i, modFactory := range proposalModulesFactories {
mod := modFactory(core)
if mod == nil {
Expand Down Expand Up @@ -117,6 +130,32 @@ func (d *daoCore) VotingModule() dao_interfaces.IVotingModule {
return d.votingModule
}

func (d *daoCore) RolesModule() dao_interfaces.IRolesModule {
return d.rolesModule
}

func (d *daoCore) GetMembersJSON(start, end string, limit uint64, height int64) string {
vMembers := d.votingModule.GetMembersJSON(start, end, limit, height)
nodes, err := json.Unmarshal([]byte(vMembers))
if err != nil {
panic("failed to unmarshal voting module members")
}
vals := nodes.MustArray()
for i, val := range vals {
obj := val.MustObject()
addr := jsonutil.MustAddress(obj["address"])
roles := d.rolesModule.GetMemberRoles(addr)
rolesJSON := make([]*json.Node, len(roles))
for j, role := range roles {
rolesJSON[j] = json.StringNode("", role)
}
obj["roles"] = json.ArrayNode("", rolesJSON)
vals[i] = json.ObjectNode("", obj)

}
return json.ArrayNode("", vals).String()
}

func (d *daoCore) VotingPowerAtHeight(address std.Address, height int64) uint64 {
return d.VotingModule().VotingPowerAtHeight(address, height)
}
Expand All @@ -133,6 +172,11 @@ func (d *daoCore) Render(path string) string {
sb.WriteString(votingInfo.String())
sb.WriteRune('\n')
sb.WriteString(d.votingModule.Render(""))
rolesInfo := d.rolesModule.Info()
sb.WriteString("# Roles Module: ")
sb.WriteString(rolesInfo.String())
sb.WriteRune('\n')
sb.WriteString(d.rolesModule.Render(""))
sb.WriteString("## Supported Messages:\n")
sb.WriteString(d.registry.Render())

Expand Down
58 changes: 57 additions & 1 deletion gno/p/dao_core/dao_core_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,53 @@ func (vm *votingModule) TotalPowerAtHeight(height int64) uint64 {
return 0
}

type rolesModule struct {
core dao_interfaces.IDAOCore
}

func rolesModuleFactory(core dao_interfaces.IDAOCore) dao_interfaces.IRolesModule {
return &rolesModule{core: core}
}

func (rm *rolesModule) Info() dao_interfaces.ModuleInfo {
return dao_interfaces.ModuleInfo{
Kind: "TestRoles",
Version: "42.21",
}
}

func (rm *rolesModule) ConfigJSON() string {
return "{}"
}

func (rm *rolesModule) Render(path string) string {
return "# Test Roles Module"
}

func (rm *rolesModule) HasRole(address std.Address, role string) bool {
return false
}

func (rm *rolesModule) NewRole(roleName string) {
panic("not implemented")
}

func (rm *rolesModule) DeleteRole(roleName string) {
panic("not implemented")
}

func (rm *rolesModule) GrantRole(address std.Address, role string) {
panic("not implemented")
}

func (rm *rolesModule) RevokeRole(address std.Address, role string) {
panic("not implemented")
}

func (rm *rolesModule) GetMemberRoles(address std.Address) []string {
return []string{}
}

type proposalModule struct {
core dao_interfaces.IDAOCore
}
Expand Down Expand Up @@ -100,7 +147,7 @@ func TestDAOCore(t *testing.T) {
return handler
}

core := NewDAOCore(votingModuleFactory, []dao_interfaces.ProposalModuleFactory{proposalModuleFactory}, []dao_interfaces.MessageHandlerFactory{handlerFactory})
core := NewDAOCore(votingModuleFactory, rolesModuleFactory, []dao_interfaces.ProposalModuleFactory{proposalModuleFactory}, []dao_interfaces.MessageHandlerFactory{handlerFactory})
if core == nil {
t.Fatal("core is nil")
}
Expand All @@ -118,6 +165,15 @@ func TestDAOCore(t *testing.T) {
t.Fatal("voting module has wrong kind")
}

rolesMod := core.RolesModule()
if rolesMod == nil {
t.Fatal("roles module is nil")
}

if rolesMod.Info().Kind != "TestRoles" {
t.Fatal("roles module has wrong kind")
}

propMods := core.ProposalModules()
if len(propMods) != 1 {
t.Fatal("expected 1 proposal module")
Expand Down
1 change: 1 addition & 0 deletions gno/p/dao_core/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ module gno.land/p/teritori/dao_core
require (
gno.land/p/demo/json v0.0.0-latest
gno.land/p/teritori/dao_interfaces v0.0.0-latest
gno.land/p/teritori/jsonutil v0.0.0-latest
)
3 changes: 3 additions & 0 deletions gno/p/dao_interfaces/core.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ type IDAOCore interface {
Render(path string) string

VotingModule() IVotingModule
RolesModule() IRolesModule
ProposalModules() []ActivableProposalModule
ActiveProposalModuleCount() int
Registry() *MessagesRegistry

UpdateVotingModule(newVotingModule IVotingModule)
UpdateProposalModules(toAdd []IProposalModule, toDisable []int)

GetMembersJSON(start, end string, limit uint64, height int64) string
}
8 changes: 8 additions & 0 deletions gno/p/dao_interfaces/core_testing.gno
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ func (d *dummyCore) VotingModule() IVotingModule {
panic("not implemented")
}

func (d *dummyCore) RolesModule() IRolesModule {
panic("not implemented")
}

func (d *dummyCore) ProposalModules() []ActivableProposalModule {
panic("not implemented")
}
Expand All @@ -33,3 +37,7 @@ func (d *dummyCore) UpdateVotingModule(newVotingModule IVotingModule) {
func (d *dummyCore) UpdateProposalModules(toAdd []IProposalModule, toDisable []int) {
panic("not implemented")
}

func (d *dummyCore) GetMembersJSON(start, end string, limit uint64, height int64) string {
panic("not implemented")
}
14 changes: 14 additions & 0 deletions gno/p/dao_interfaces/modules.gno
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,17 @@ type IProposalModule interface {
}

type ProposalModuleFactory func(core IDAOCore) IProposalModule

type IRolesModule interface {
Info() ModuleInfo
ConfigJSON() string
Render(path string) string
GetMemberRoles(address std.Address) []string
HasRole(address std.Address, role string) bool
NewRole(roleName string)
DeleteRole(roleName string)
GrantRole(address std.Address, role string)
RevokeRole(address std.Address, role string)
}

type RolesModuleFactory func(core IDAOCore) IRolesModule
8 changes: 8 additions & 0 deletions gno/p/dao_roles_group/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module gno.land/p/teritori/dao_roles_group

require (
gno.land/p/demo/json v0.0.0-latest
gno.land/p/teritori/dao_interfaces v0.0.0-latest
gno.land/p/teritori/jsonutil v0.0.0-latest
gno.land/p/teritori/role_manager v0.0.0-latest
)
63 changes: 63 additions & 0 deletions gno/p/dao_roles_group/roles_group.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dao_roles_group

import (
"std"

"gno.land/p/demo/json"
dao_interfaces "gno.land/p/teritori/dao_interfaces"
"gno.land/p/teritori/jsonutil"
"gno.land/p/teritori/role_manager"
)

type RolesGroup struct {
dao_interfaces.IRolesModule

rm *role_manager.RoleManager
}

func NewRolesGroup() *RolesGroup {
return &RolesGroup{
rm: role_manager.NewWithAddress(std.PrevRealm().Addr()),
}
}

func (r *RolesGroup) Info() dao_interfaces.ModuleInfo {
return dao_interfaces.ModuleInfo{
Kind: "gno/p/teritori/dao_roles_group",
Version: "0.1.0",
}
}

func (r *RolesGroup) ConfigJSON() string {
return json.ObjectNode("", map[string]*json.Node{
"totalRoles": jsonutil.IntNode(r.rm.CountRoles()),
}).String()
}

func (r *RolesGroup) Render(path string) string {
return "Not implemented yet"
}

func (r *RolesGroup) HasRole(address std.Address, role string) bool {
return r.rm.HasRole(address, role)
}

func (r *RolesGroup) NewRole(roleName string) {
r.rm.CreateNewRole(roleName, []string{})
}

func (r *RolesGroup) DeleteRole(roleName string) {
r.rm.DeleteRole(roleName)
}

func (r *RolesGroup) GrantRole(address std.Address, role string) {
r.rm.AddRoleToUser(address, role)
}

func (r *RolesGroup) RevokeRole(address std.Address, role string) {
r.rm.RemoveRoleFromUser(address, role)
}

func (r *RolesGroup) GetMemberRoles(address std.Address) []string {
return r.rm.GetUserRoles(address)
}
24 changes: 24 additions & 0 deletions gno/p/role_manager/role_manager.gno
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,30 @@ func (rm *RoleManager) HasRole(user std.Address, roleName string) bool {
return userRoles.Has(roleName)
}

func (rm *RoleManager) IsRoleExist(roleName string) bool {
return rm.roles.Has(roleName)
}

func (rm *RoleManager) CountRoles() int {
return rm.roles.Size()
}

func (rm *RoleManager) GetUserRoles(user std.Address) []string {
userRoles, ok := rm.users.Get(user.String())
if !ok {
return []string{}
}
i := 0
roles := userRoles.(*avl.Tree)
res := make([]string, roles.Size())
roles.Iterate("", "", func(key string, value interface{}) bool {
res[i] = key
i++
return false
})
return res
}

func (rm *RoleManager) mustGetRole(roleName string) *Role {
role, ok := rm.roles.Get(roleName)
if !ok {
Expand Down
Loading

0 comments on commit b843b86

Please sign in to comment.