Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tracking r/sys/teams work #2957

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions examples/gno.land/r/sys/teams/teams.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package teams

import (
"errors"
"std"
"strings"

"gno.land/p/demo/avl"
"gno.land/p/demo/users"
)

var Teams *avl.Tree
var TeamNames *avl.Tree

func init() {
Teams = avl.NewTree()
TeamNames = avl.NewTree()
}

func CreateTeam(teamAddress std.Address, teamName string, owner std.Address) error {
if _, exists := Teams.Get(teamAddress.String()); exists {
return errors.New("team already exists")
}

if _, nameExists := TeamNames.Get(strings.ToLower(teamName)); nameExists {
return errors.New("team name already exists")
}

team := &Team{
Name: teamName,
Owners: []std.Address{owner},
}

Teams.Set(teamAddress.String(), team)
TeamNames.Set(strings.ToLower(teamName), teamAddress)
return nil
}

func AddMember(teamAddress std.Address, user users.User) error {
team, err := getTeam(teamAddress)
if err != nil {
return err
}

// Check if the user is already a member
for _, member := range team.Members {
if member.User.Address == user.Address {
return errors.New("user is already a member of the team")
}
}

team.Members = append(team.Members, TeamMember{User: user})
Teams.Set(teamAddress.String(), team)
return nil
}

func RemoveMember(teamAddress std.Address, userAddress std.Address) error {
team, err := getTeam(teamAddress)
if err != nil {
return err
}

for i, member := range team.Members {
if member.User.Address == userAddress {
team.Members = append(team.Members[:i], team.Members[i+1:]...)
Teams.Set(teamAddress.String(), team)
return nil
}
}

return errors.New("member not found")
}

func AddPermission(teamAddress std.Address, permission string) error {
team, err := getTeam(teamAddress)
if err != nil {
return err
}

for _, perm := range team.Permissions {
if strings.EqualFold(perm, permission) {
return errors.New("permission already exists in the team")
}
}

team.Permissions = append(team.Permissions, permission)
Teams.Set(teamAddress.String(), team)
return nil
}

func RemovePermission(teamAddress std.Address, permission string) error {
team, err := getTeam(teamAddress)
if err != nil {
return err
}

for i, perm := range team.Permissions {
if strings.EqualFold(perm, permission) {
team.Permissions = append(team.Permissions[:i], team.Permissions[i+1:]...)
break
}
}

for i, member := range team.Members {
for j, memberPerm := range member.Permissions {
if strings.EqualFold(memberPerm, permission) {
team.Members[i].Permissions = append(member.Permissions[:j], member.Permissions[j+1:]...)
break
}
}
}

Teams.Set(teamAddress.String(), team)
return nil
}

// AddMemberPermission adds a permission to a specific member of the team
func AddMemberPermission(teamAddress std.Address, userAddress std.Address, permission string) error {
team, err := getTeam(teamAddress)
if err != nil {
return err
}

// Check if the permission exists in the team's permissions
permissionExists := false
for _, perm := range team.Permissions {
if strings.EqualFold(perm, permission) {
permissionExists = true
break
}
}
if !permissionExists {
return errors.New("permission does not exist in the team")
}

// Find the member and add the permission if they don't already have it
for i, member := range team.Members {
if member.User.Address == userAddress {
for _, memberPerm := range member.Permissions {
if strings.EqualFold(memberPerm, permission) {
return errors.New("member already has the permission")
}
}
team.Members[i].Permissions = append(team.Members[i].Permissions, permission)
Teams.Set(teamAddress.String(), team)
return nil
}
}

return errors.New("member not found")
}

// RemoveMemberPermission removes a permission from a specific member of the team
func RemoveMemberPermission(teamAddress std.Address, userAddress std.Address, permission string) error {
team, err := getTeam(teamAddress)
if err != nil {
return err
}

// Find the member and remove the permission
for i, member := range team.Members {
if member.User.Address == userAddress {
for j, memberPerm := range member.Permissions {
if strings.EqualFold(memberPerm, permission) {
team.Members[i].Permissions = append(member.Permissions[:j], member.Permissions[j+1:]...)
Teams.Set(teamAddress.String(), team)
return nil
}
}
return errors.New("permission not found for the member")
}
}

return errors.New("member not found")
}

// helper function to retrieve a team by address
func getTeam(teamAddress std.Address) (*Team, error) {
team, exists := Teams.Get(teamAddress.String())
if !exists {
return nil, errors.New("team not found")
}
return team.(*Team), nil
}

// GetTeamByName retrieves a team by its name
func GetTeamByName(teamName string) (*Team, error) {
teamAddress, exists := TeamNames.Get(strings.ToLower(teamName))
if !exists {
return nil, errors.New("team not found")
}
return getTeam(teamAddress.(std.Address))
}
171 changes: 171 additions & 0 deletions examples/gno.land/r/sys/teams/teams_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package teams

import (
"testing"
"std"
"gno.land/p/demo/users"
"gno.land/r/sys/teams"
)

func TestCreateTeam(t *testing.T) {
teamAddress := std.Address("g1teamaddress")
teamName := "Test Team"
owner := std.Address("g1owneraddress")

err := teams.CreateTeam(teamAddress, teamName, owner)
if err != nil {
t.Errorf("Failed to create team: %v", err)
}

// Attempt to create a team with the same address, should fail
err = teams.CreateTeam(teamAddress, teamName, owner)
if err == nil {
t.Errorf("Expected error when creating a duplicate team, got nil")
}

// Attempt to create a team with the same name, should fail
newTeamAddress := std.Address("g1newteamaddress")
err = teams.CreateTeam(newTeamAddress, teamName, owner)
if err == nil {
t.Errorf("Expected error when creating a team with duplicate name, got nil")
}
}

func TestAddMember(t *testing.T) {
teamAddress := std.Address("g1teamaddress")
owner := std.Address("g1owneraddress")
_ = teams.CreateTeam(teamAddress, "Test Team", owner)

user := users.User{Name: "Test User", Address: std.Address("g1useraddress")}
err := teams.AddMember(teamAddress, user)
if err != nil {
t.Errorf("Failed to add member: %v", err)
}

// Attempt to add the same member again, should fail
err = teams.AddMember(teamAddress, user)
if err == nil {
t.Errorf("Expected error when adding a duplicate member, got nil")
}
}

func TestRemoveMember(t *testing.T) {
teamAddress := std.Address("g1teamaddress")
owner := std.Address("g1owneraddress")
_ = teams.CreateTeam(teamAddress, "Test Team", owner)

user := users.User{Name: "Test User", Address: std.Address("g1useraddress")}
_ = teams.AddMember(teamAddress, user)

err := teams.RemoveMember(teamAddress, user.Address)
if err != nil {
t.Errorf("Failed to remove member: %v", err)
}

// Attempt to remove a non-existing member, should fail
err = teams.RemoveMember(teamAddress, user.Address)
if err == nil {
t.Errorf("Expected error when removing a non-existing member, got nil")
}
}

func TestAddPermission(t *testing.T) {
teamAddress := std.Address("g1teamaddress")
owner := std.Address("g1owneraddress")
_ = teams.CreateTeam(teamAddress, "Test Team", owner)

permission := "manage_tasks"
err := teams.AddPermission(teamAddress, permission)
if err != nil {
t.Errorf("Failed to add permission: %v", err)
}

// Attempt to add the same permission again, should fail
err = teams.AddPermission(teamAddress, permission)
if err == nil {
t.Errorf("Expected error when adding a duplicate permission, got nil")
}
}

func TestRemovePermission(t *testing.T) {
teamAddress := std.Address("g1teamaddress")
owner := std.Address("g1owneraddress")
_ = teams.CreateTeam(teamAddress, "Test Team", owner)

permission := "manage_tasks"
_ = teams.AddPermission(teamAddress, permission)

err := teams.RemovePermission(teamAddress, permission)
if err != nil {
t.Errorf("Failed to remove permission: %v", err)
}

// Attempt to remove a non-existing permission, should not fail
err = teams.RemovePermission(teamAddress, permission)
if err != nil {
t.Errorf("Expected no error when removing a non-existing permission, got %v", err)
}
}

func TestAddMemberPermission(t *testing.T) {
teamAddress := std.Address("g1teamaddress")
owner := std.Address("g1owneraddress")
_ = teams.CreateTeam(teamAddress, "Test Team", owner)

user := users.User{Name: "Test User", Address: std.Address("g1useraddress")}
_ = teams.AddMember(teamAddress, user)

permission := "manage_tasks"
_ = teams.AddPermission(teamAddress, permission)

err := teams.AddMemberPermission(teamAddress, user.Address, permission)
if err != nil {
t.Errorf("Failed to add permission to member: %v", err)
}

// Attempt to add a permission that does not exist in the team, should fail
err = teams.AddMemberPermission(teamAddress, user.Address, "non_existing_permission")
if err == nil {
t.Errorf("Expected error when adding a non-existing permission to member, got nil")
}
}

func TestRemoveMemberPermission(t *testing.T) {
teamAddress := std.Address("g1teamaddress")
owner := std.Address("g1owneraddress")
_ = teams.CreateTeam(teamAddress, "Test Team2", owner)

user := users.User{Name: "Test User2", Address: std.Address("g1useraddress2")}
_ = teams.AddMember(teamAddress, user)

permission := "manage_tasks"
_ = teams.AddPermission(teamAddress, permission)
_ = teams.AddMemberPermission(teamAddress, user.Address, permission)

err := teams.RemoveMemberPermission(teamAddress, user.Address, permission)
if err != nil {
t.Errorf("Failed to remove permission from member: %v", err)
}
}

func TestGetTeamByName(t *testing.T) {
teamAddress := std.Address("g1teamaddressunique")
teamName := "Unique Team"
owner := std.Address("g1owneraddress")
_ = teams.CreateTeam(teamAddress, teamName, owner)

team, err := teams.GetTeamByName(teamName)
if err != nil {
t.Errorf("Failed to get team by name: %v", err)
}

if team.Name != teamName {
t.Errorf("Expected team name to be %v, got %v", teamName, team.Name)
}

// Attempt to get a non-existing team by name, should fail
_, err = teams.GetTeamByName("NonExistingTeam")
if err == nil {
t.Errorf("Expected error when getting a non-existing team by name, got nil")
}
}
20 changes: 20 additions & 0 deletions examples/gno.land/r/sys/teams/types.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package teams

import (
"std"
"strings"

"gno.land/p/demo/users"
)

type Team struct {
Name string
Owners []std.Address
Members []TeamMember
Permissions []string
}

type TeamMember struct {
User users.User
Permissions []string
}
Loading