Skip to content

Commit

Permalink
feat: add admindao realm to store all AdminDAO instances
Browse files Browse the repository at this point in the history
IMPORTANT:
There is an issue saving the boards2 realm, saving it in the admindao
realm causes that board realms fail when being created/setted with the
following error: "cannot modify external-realm or non-realm object".

The only initial difference between realm and board DAOs is that the
realm DAO is created on deploy using the `init()` function.

The issue with setting the admin DAO must be figured out.
  • Loading branch information
jeronimoalbi committed Jan 16, 2025
1 parent 7b2f980 commit 83d0b93
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 42 deletions.
47 changes: 47 additions & 0 deletions examples/gno.land/r/demo/boards2/admindao/admindao.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package admindao

import (
"path"
"std"
"strings"

"gno.land/p/demo/avl"
"gno.land/p/demo/boards2/admindao"
)

var (
daos avl.Tree // string(name) -> *AdminDAO
boardsNS string
)

func init() {
boardsNS = path.Dir(std.CurrentRealm().PkgPath()) + "/"
}

func New(name string, options ...admindao.Option) *admindao.AdminDAO {
assertCallerIsBoardsRealm()

dao := admindao.New(options...)
daos.Set(name, dao)
return dao
}

func Get(name string) (_ *admindao.AdminDAO, found bool) {
assertCallerIsBoardsRealm()

v, found := daos.Get(name)
if !found {
return nil, false
}
return v.(*admindao.AdminDAO), true
}

func Exists(name string) bool {
return daos.Has(name)
}

func assertCallerIsBoardsRealm() {
if !strings.HasPrefix(std.PrevRealm().PkgPath(), boardsNS) {
panic("unauthorized")
}
}
1 change: 1 addition & 0 deletions examples/gno.land/r/demo/boards2/admindao/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/r/demo/boards2/admindao
37 changes: 37 additions & 0 deletions examples/gno.land/r/demo/boards2/admindao/z_0_a_filetest.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// PKGPATH: gno.land/r/demo/boards2/test
package test

import (
"std"

"gno.land/r/demo/boards2/admindao"
)

const (
owner = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // @test1
name = "test1"
)

func init() {
std.TestSetOrigCaller(owner)
}

func main() {
dao := admindao.New(name)
println("ok")

if admindao.Exists(name) {
println("exists")
}

if got, found := admindao.Get(name); found {
if got == dao {
print("found")
}
}
}

// Output:
// ok
// exists
// found
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package main
package main // <-- Caller realm is main instead of a realm within admindao parent namespace

import (
"std"

boards2 "gno.land/r/demo/boards2/v1"
"gno.land/r/demo/boards2/admindao"
)

const owner = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // @test1
Expand All @@ -13,8 +13,8 @@ func init() {
}

func main() {
boards2.CreateBoard("gnoland")
admindao.New("foo")
}

// Error:
// board name is a user name registered to a different user
// unauthorized
1 change: 0 additions & 1 deletion examples/gno.land/r/demo/boards2/gno.mod

This file was deleted.

11 changes: 7 additions & 4 deletions examples/gno.land/r/demo/boards2/v1/board.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"gno.land/p/demo/avl"
"gno.land/p/moul/txlink"

"gno.land/p/demo/boards2/admindao"
"gno.land/r/demo/boards2/admindao"
)

type BoardID uint64
Expand Down Expand Up @@ -42,7 +42,7 @@ func newBoard(id BoardID, name string, creator std.Address) *Board {
threads: avl.Tree{},
createdAt: time.Now(),
deleted: avl.Tree{},
perms: createDefaultBoardPermissions(creator),
perms: createDefaultBoardPermissions(name, creator),
}
}

Expand Down Expand Up @@ -132,9 +132,12 @@ func (board *Board) GetPostFormURL() string {
}

// TODO: This is a temporary implementation until the permissions and DAO mecahnics are defined
func createDefaultBoardPermissions(owner std.Address) *DefaultPermissions {
func createDefaultBoardPermissions(name string, owner std.Address) *DefaultPermissions {
dao := admindao.New(name)
dao.AddMember(owner)

return NewDefaultPermissions(
admindao.New(admindao.WithMember(owner)),
dao,
WithSuperRole(RoleOwner),
WithRole(RoleAdmin, PermissionMemberInvite, PermissionBoardRename),
// TODO: Finish assigning all roles and permissions
Expand Down
19 changes: 12 additions & 7 deletions examples/gno.land/r/demo/boards2/v1/permission_default.gno
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@ import (
"std"

"gno.land/p/demo/avl"
"gno.land/p/demo/boards2/admindao"
padmindao "gno.land/p/demo/boards2/admindao"

// "gno.land/r/demo/boards2/admindao"
"gno.land/r/demo/users"
)

// DefaultPermissions manages users, roles and permissions.
type DefaultPermissions struct {
superRole Role
dao *admindao.AdminDAO
dao *padmindao.AdminDAO
users *avl.Tree // string(std.Address) -> []Role
roles *avl.Tree // string(role) -> []Permission
}

// NewDefaultPermissions creates a new permissions type.
// This type is a default implementation to handle users, roles and permissions.
func NewDefaultPermissions(dao *admindao.AdminDAO, options ...DefaultPermissionsOption) *DefaultPermissions {
func NewDefaultPermissions(dao *padmindao.AdminDAO, options ...DefaultPermissionsOption) *DefaultPermissions {
dp := &DefaultPermissions{
dao: dao,
roles: avl.NewTree(),
Expand Down Expand Up @@ -127,7 +128,7 @@ func (dp *DefaultPermissions) RemoveUser(user std.Address) bool {

// GetDAO returns the underlying DAO.
// Returned value can be nil if the implementation doesn't have a DAO.
func (dp DefaultPermissions) GetDAO() *admindao.AdminDAO {
func (dp DefaultPermissions) GetDAO() *padmindao.AdminDAO {
return dp.dao
}

Expand Down Expand Up @@ -193,10 +194,14 @@ func (dp DefaultPermissions) handleMemberInvite(args Args, cb func(Args)) {
}

func createDefaultPermissions(owner std.Address) *DefaultPermissions {
// TODO: DAO should be a different realm or proposal and voting functions should be part of boards realm?
// Permissions and DAO mechanics should be discussed and improved. Add `GetDAO()` to `Permissions`??
// TODO: Creating the boards DAO makes following calls to New (avl.Tree.Set()) fail
// dao := admindao.New("boards")
// dao.AddMember(owner)
dao := padmindao.New()
dao.AddMember(owner)

return NewDefaultPermissions(
admindao.New(admindao.WithMember(owner)),
dao,
WithSuperRole(RoleOwner),
WithRole(RoleAdmin, PermissionBoardCreate, PermissionMemberInvite),
// TODO: Finish assigning all roles and permissions
Expand Down
19 changes: 0 additions & 19 deletions examples/gno.land/r/demo/boards2/v1/public.gno
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ func GetBoardIDFromName(name string) (BoardID, bool) {

func CreateBoard(name string) BoardID {
assertRealmIsNotFrozen()
assertIsUserCall()

name = strings.TrimSpace(name)
assertBoardNameIsNotEmpty(name)
Expand All @@ -36,7 +35,6 @@ func CreateBoard(name string) BoardID {

func RenameBoard(name, newName string) {
assertRealmIsNotFrozen()
assertIsUserCall()

newName = strings.TrimSpace(newName)
assertBoardNameIsNotEmpty(newName)
Expand Down Expand Up @@ -77,7 +75,6 @@ func FlagThread(bid BoardID, postID PostID, reason string) {

func CreateThread(bid BoardID, title, body string) PostID {
assertRealmIsNotFrozen()
assertIsUserCall()

// TODO: Assert that caller is a board member (when board type is invite only)
caller := std.GetOrigCaller()
Expand All @@ -91,7 +88,6 @@ func CreateThread(bid BoardID, title, body string) PostID {

func CreateReply(bid BoardID, threadID, replyID PostID, body string) PostID {
assertRealmIsNotFrozen()
assertIsUserCall()

// TODO: Assert that caller is a board member (when board type is invite only)
caller := std.GetOrigCaller()
Expand Down Expand Up @@ -134,7 +130,6 @@ func FlagReply(bid BoardID, threadID, replyID PostID, reason string) {

func CreateRepost(bid BoardID, threadID PostID, title, body string, dstBoardID BoardID) PostID {
assertRealmIsNotFrozen()
assertIsUserCall()

// TODO: Assert that caller is a board member (when board type is invite only)
caller := std.GetOrigCaller()
Expand All @@ -158,7 +153,6 @@ func CreateRepost(bid BoardID, threadID PostID, title, body string, dstBoardID B

func DeleteThread(bid BoardID, threadID PostID) {
assertRealmIsNotFrozen()
assertIsUserCall()

board := mustGetBoard(bid)
assertThreadExists(board, threadID)
Expand All @@ -173,7 +167,6 @@ func DeleteThread(bid BoardID, threadID PostID) {

func DeleteReply(bid BoardID, threadID, replyID PostID) {
assertRealmIsNotFrozen()
assertIsUserCall()

board := mustGetBoard(bid)
thread := mustGetThread(board, threadID)
Expand All @@ -193,7 +186,6 @@ func DeleteReply(bid BoardID, threadID, replyID PostID) {

func EditThread(bid BoardID, threadID PostID, title, body string) {
assertRealmIsNotFrozen()
assertIsUserCall()

board := mustGetBoard(bid)
assertThreadExists(board, threadID)
Expand All @@ -209,7 +201,6 @@ func EditThread(bid BoardID, threadID PostID, title, body string) {

func EditReply(bid BoardID, threadID, replyID PostID, title, body string) {
assertRealmIsNotFrozen()
assertIsUserCall()

board := mustGetBoard(bid)
thread := mustGetThread(board, threadID)
Expand All @@ -225,7 +216,6 @@ func EditReply(bid BoardID, threadID, replyID PostID, title, body string) {

func InviteMember(user std.Address, role Role) {
assertRealmIsNotFrozen()
assertIsUserCall()

caller := std.GetOrigCaller()
args := Args{user, role}
Expand All @@ -238,7 +228,6 @@ func InviteMember(user std.Address, role Role) {

func RemoveMember(user std.Address) {
assertRealmIsNotFrozen()
assertIsUserCall()

caller := std.GetOrigCaller()
gPerm.WithPermission(caller, PermissionMemberRemove, Args{user}, func(Args) {
Expand All @@ -249,21 +238,13 @@ func RemoveMember(user std.Address) {
}

func FreezeRealm(frozen bool) {
assertIsUserCall()

// TODO: Use a proposal to freeze the realm
caller := std.GetOrigCaller()
gPerm.WithPermission(caller, PermissionRealmFreeze, nil, func(Args) {
gFrozen = frozen
})
}

func assertIsUserCall() {
if !(std.IsOriginCall() || std.PrevRealm().IsUser()) {
panic("invalid non-user call")
}
}

func assertHasPermission(user std.Address, p Permission) {
if !gPerm.HasPermission(user, p) {
panic("unauthorized")
Expand Down
3 changes: 2 additions & 1 deletion examples/gno.land/r/demo/boards2/v1/z_0_a_filetest.gno
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package main
// PKGPATH: gno.land/r/demo/boards2/test
package test

import (
"std"
Expand Down
15 changes: 11 additions & 4 deletions examples/gno.land/r/demo/boards2/v1/z_0_d_filetest.gno
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
// PKGPATH: gno.land/r/demo/boards2/v1_test
package v1_test
package main

import (
"std"

boards2 "gno.land/r/demo/boards2/v1"
)

const owner = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // @test1

func init() {
std.TestSetOrigCaller(owner)
}

func main() {
boards2.CreateBoard("foo")
boards2.CreateBoard("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
}

// Error:
// invalid non-user call
// addresses are not allowed as board name
4 changes: 2 additions & 2 deletions examples/gno.land/r/demo/boards2/v1/z_0_e_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ func init() {
}

func main() {
boards2.CreateBoard("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
boards2.CreateBoard("gnoland")
}

// Error:
// addresses are not allowed as board name
// board name is a user name registered to a different user

0 comments on commit 83d0b93

Please sign in to comment.