diff --git a/examples/gno.land/r/demo/boards2/admindao/admindao.gno b/examples/gno.land/r/demo/boards2/admindao/admindao.gno new file mode 100644 index 00000000000..b6fba578a1a --- /dev/null +++ b/examples/gno.land/r/demo/boards2/admindao/admindao.gno @@ -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") + } +} diff --git a/examples/gno.land/r/demo/boards2/admindao/gno.mod b/examples/gno.land/r/demo/boards2/admindao/gno.mod new file mode 100644 index 00000000000..620b8a40374 --- /dev/null +++ b/examples/gno.land/r/demo/boards2/admindao/gno.mod @@ -0,0 +1 @@ +module gno.land/r/demo/boards2/admindao diff --git a/examples/gno.land/r/demo/boards2/admindao/z_0_a_filetest.gno b/examples/gno.land/r/demo/boards2/admindao/z_0_a_filetest.gno new file mode 100644 index 00000000000..ef2e1f8ea9c --- /dev/null +++ b/examples/gno.land/r/demo/boards2/admindao/z_0_a_filetest.gno @@ -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 diff --git a/examples/gno.land/r/demo/boards2/v1/z_0_f_filetest.gno b/examples/gno.land/r/demo/boards2/admindao/z_0_b_filetest.gno similarity index 51% rename from examples/gno.land/r/demo/boards2/v1/z_0_f_filetest.gno rename to examples/gno.land/r/demo/boards2/admindao/z_0_b_filetest.gno index 92afa7f77c5..3a1186fc299 100644 --- a/examples/gno.land/r/demo/boards2/v1/z_0_f_filetest.gno +++ b/examples/gno.land/r/demo/boards2/admindao/z_0_b_filetest.gno @@ -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 @@ -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 diff --git a/examples/gno.land/r/demo/boards2/gno.mod b/examples/gno.land/r/demo/boards2/gno.mod deleted file mode 100644 index 4337a775e76..00000000000 --- a/examples/gno.land/r/demo/boards2/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/demo/boards2 diff --git a/examples/gno.land/r/demo/boards2/v1/board.gno b/examples/gno.land/r/demo/boards2/v1/board.gno index d6a5306860c..d0cd0feee2e 100644 --- a/examples/gno.land/r/demo/boards2/v1/board.gno +++ b/examples/gno.land/r/demo/boards2/v1/board.gno @@ -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 @@ -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), } } @@ -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 diff --git a/examples/gno.land/r/demo/boards2/v1/permission_default.gno b/examples/gno.land/r/demo/boards2/v1/permission_default.gno index a98b2fdb6f3..49f0c8c64da 100644 --- a/examples/gno.land/r/demo/boards2/v1/permission_default.gno +++ b/examples/gno.land/r/demo/boards2/v1/permission_default.gno @@ -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(), @@ -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 } @@ -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 diff --git a/examples/gno.land/r/demo/boards2/v1/public.gno b/examples/gno.land/r/demo/boards2/v1/public.gno index 7b673b1c36a..0e0f963bf00 100644 --- a/examples/gno.land/r/demo/boards2/v1/public.gno +++ b/examples/gno.land/r/demo/boards2/v1/public.gno @@ -15,7 +15,6 @@ func GetBoardIDFromName(name string) (BoardID, bool) { func CreateBoard(name string) BoardID { assertRealmIsNotFrozen() - assertIsUserCall() name = strings.TrimSpace(name) assertBoardNameIsNotEmpty(name) @@ -36,7 +35,6 @@ func CreateBoard(name string) BoardID { func RenameBoard(name, newName string) { assertRealmIsNotFrozen() - assertIsUserCall() newName = strings.TrimSpace(newName) assertBoardNameIsNotEmpty(newName) @@ -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() @@ -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() @@ -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() @@ -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) @@ -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) @@ -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) @@ -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) @@ -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} @@ -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) { @@ -249,8 +238,6 @@ 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) { @@ -258,12 +245,6 @@ func FreezeRealm(frozen bool) { }) } -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") diff --git a/examples/gno.land/r/demo/boards2/v1/z_0_a_filetest.gno b/examples/gno.land/r/demo/boards2/v1/z_0_a_filetest.gno index ef7f258b199..b2dc62eba5a 100644 --- a/examples/gno.land/r/demo/boards2/v1/z_0_a_filetest.gno +++ b/examples/gno.land/r/demo/boards2/v1/z_0_a_filetest.gno @@ -1,4 +1,5 @@ -package main +// PKGPATH: gno.land/r/demo/boards2/test +package test import ( "std" diff --git a/examples/gno.land/r/demo/boards2/v1/z_0_d_filetest.gno b/examples/gno.land/r/demo/boards2/v1/z_0_d_filetest.gno index 3015ddce104..e6dadea739a 100644 --- a/examples/gno.land/r/demo/boards2/v1/z_0_d_filetest.gno +++ b/examples/gno.land/r/demo/boards2/v1/z_0_d_filetest.gno @@ -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 diff --git a/examples/gno.land/r/demo/boards2/v1/z_0_e_filetest.gno b/examples/gno.land/r/demo/boards2/v1/z_0_e_filetest.gno index e6dadea739a..92afa7f77c5 100644 --- a/examples/gno.land/r/demo/boards2/v1/z_0_e_filetest.gno +++ b/examples/gno.land/r/demo/boards2/v1/z_0_e_filetest.gno @@ -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