From c2eb0dbd4aac56ef6d56551d72cb03321d05a7f8 Mon Sep 17 00:00:00 2001 From: Ferran Date: Thu, 25 Aug 2022 04:41:29 +0200 Subject: [PATCH] Added groups and user repository permissions (#217) Co-authored-by: Ferran Tomas --- bitbucket.go | 14 ++ repository.go | 255 +++++++++++++++++++++++++++++++++ tests/repository_test.go | 296 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 565 insertions(+) diff --git a/bitbucket.go b/bitbucket.go index 64965d8..aae77e6 100644 --- a/bitbucket.go +++ b/bitbucket.go @@ -476,6 +476,20 @@ type RepositoryEnvironmentsOptions struct { RepoSlug string `json:"repo_slug"` } +type RepositoryGroupPermissionsOptions struct { + Owner string `json:"owner"` + RepoSlug string `json:"repo_slug"` + Group string `json:"group"` + Permission string `json:"permission"` +} + +type RepositoryUserPermissionsOptions struct { + Owner string `json:"owner"` + RepoSlug string `json:"repo_slug"` + User string `json:"user"` + Permission string `json:"permission"` +} + type RepositoryEnvironmentTypeOption int const ( diff --git a/repository.go b/repository.go index 0cc22f4..6fddd77 100644 --- a/repository.go +++ b/repository.go @@ -205,6 +205,51 @@ type DefaultReviewers struct { DefaultReviewers []DefaultReviewer } +type Group struct { + AccountPrivilege string `mapstructure:"account_privilege"` + DefaultPermission string `mapstructure:"default_permission"` + EmailForwardingDisabled bool `mapstructure:"email_forwarding_disabled"` + FullSlug string `mapstructure:"full_slug"` + Links map[string]map[string]string + Name string `mapstructure:"name"` + Slug string `mapstructure:"slug"` + Type string `mapstructure:"type"` + Workspace map[string]interface{} `mapstructure:"workspace"` + Owner map[string]interface{} +} + +type GroupPermission struct { + Type string + Group Group + Permission string + Links map[string]map[string]string +} + +type GroupPermissions struct { + Page int + Pagelen int + MaxDepth int + Size int + Next string + GroupPermissions []GroupPermission +} + +type UserPermission struct { + Type string + User User + Permission string + Links map[string]map[string]string +} + +type UserPermissions struct { + Page int + Pagelen int + MaxDepth int + Size int + Next string + UserPermissions []UserPermission +} + func (r *Repository) Create(ro *RepositoryOptions) (*Repository, error) { data, err := r.buildRepositoryBody(ro) if err != nil { @@ -834,6 +879,88 @@ func (r *Repository) UpdateDeploymentVariable(opt *RepositoryDeploymentVariableO return decodeDeploymentVariable(response) } +func (r *Repository) ListGroupPermissions(ro *RepositoryOptions) (*GroupPermissions, error) { + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/groups?pagelen=1", ro.Owner, ro.RepoSlug) + + res, err := r.c.executePaginated("GET", urlStr, "") + if err != nil { + return nil, err + } + return decodeGroupsPermissions(res) +} + +func (r *Repository) SetGroupPermissions(rgo *RepositoryGroupPermissionsOptions) (*GroupPermission, error) { + body, err := r.buildRepositoryGroupPermissionBody(rgo) + if err != nil { + return nil, err + } + + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/groups/%s", rgo.Owner, rgo.RepoSlug, rgo.Group) + + res, err := r.c.execute("PUT", urlStr, body) + if err != nil { + return nil, err + } + + return decodeGroupPermissions(res) +} + +func (r *Repository) DeleteGroupPermissions(rgo *RepositoryGroupPermissionsOptions) (interface{}, error) { + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/groups/%s", rgo.Owner, rgo.RepoSlug, rgo.Group) + return r.c.execute("DELETE", urlStr, "") +} + +func (r *Repository) GetGroupPermissions(rgo *RepositoryGroupPermissionsOptions) (*GroupPermission, error) { + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/groups/%s", rgo.Owner, rgo.RepoSlug, rgo.Group) + + res, err := r.c.executePaginated("GET", urlStr, "") + if err != nil { + return nil, err + } + return decodeGroupPermissions(res) +} + +func (r *Repository) ListUserPermissions(ro *RepositoryOptions) (*UserPermissions, error) { + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/users?pagelen=1", ro.Owner, ro.RepoSlug) + + res, err := r.c.executePaginated("GET", urlStr, "") + if err != nil { + return nil, err + } + return decodeUsersPermissions(res) +} + +func (r *Repository) SetUserPermissions(rgo *RepositoryUserPermissionsOptions) (*UserPermission, error) { + body, err := r.buildRepositoryUserPermissionBody(rgo) + if err != nil { + return nil, err + } + + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/users/%s", rgo.Owner, rgo.RepoSlug, rgo.User) + + res, err := r.c.execute("PUT", urlStr, body) + if err != nil { + return nil, err + } + + return decodeUserPermissions(res) +} + +func (r *Repository) DeleteUserPermissions(rgo *RepositoryUserPermissionsOptions) (interface{}, error) { + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/users/%s", rgo.Owner, rgo.RepoSlug, rgo.User) + return r.c.execute("DELETE", urlStr, "") +} + +func (r *Repository) GetUserPermissions(rgo *RepositoryUserPermissionsOptions) (*UserPermission, error) { + urlStr := r.c.requestUrl("/repositories/%s/%s/permissions-config/users/%s", rgo.Owner, rgo.RepoSlug, rgo.User) + + res, err := r.c.executePaginated("GET", urlStr, "") + if err != nil { + return nil, err + } + return decodeUserPermissions(res) +} + func (r *Repository) buildRepositoryBody(ro *RepositoryOptions) (string, error) { body := map[string]interface{}{} @@ -1019,6 +1146,22 @@ func (r *Repository) buildDeploymentVariableBody(opt *RepositoryDeploymentVariab return r.buildJsonBody(body) } +func (r *Repository) buildRepositoryGroupPermissionBody(rpo *RepositoryGroupPermissionsOptions) (string, error) { + body := map[string]interface{}{} + + body["permission"] = rpo.Permission + + return r.buildJsonBody(body) +} + +func (r *Repository) buildRepositoryUserPermissionBody(rpo *RepositoryUserPermissionsOptions) (string, error) { + body := map[string]interface{}{} + + body["permission"] = rpo.Permission + + return r.buildJsonBody(body) +} + func (r *Repository) buildJsonBody(body map[string]interface{}) (string, error) { data, err := json.Marshal(body) if err != nil { @@ -1591,3 +1734,115 @@ func decodeDefaultReviewers(response interface{}) (*DefaultReviewers, error) { } return &defaultReviewerVariables, nil } + +func decodeGroupPermissions(response interface{}) (*GroupPermission, error) { + var groupPermission GroupPermission + err := mapstructure.Decode(response, &groupPermission) + if err != nil { + return nil, err + } + return &groupPermission, nil +} + +func decodeGroupsPermissions(response interface{}) (*GroupPermissions, error) { + responseMap := response.(map[string]interface{}) + values := responseMap["values"].([]interface{}) + + var variables []GroupPermission + for _, variable := range values { + var groupPermission GroupPermission + err := mapstructure.Decode(variable, &groupPermission) + if err == nil { + variables = append(variables, groupPermission) + } + } + + page, ok := responseMap["page"].(float64) + if !ok { + page = 0 + } + + pagelen, ok := responseMap["pagelen"].(float64) + if !ok { + pagelen = 0 + } + max_depth, ok := responseMap["max_depth"].(float64) + if !ok { + max_depth = 0 + } + size, ok := responseMap["size"].(float64) + if !ok { + size = 0 + } + + next, ok := responseMap["next"].(string) + if !ok { + next = "" + } + + groupPermissions := GroupPermissions{ + Page: int(page), + Pagelen: int(pagelen), + MaxDepth: int(max_depth), + Size: int(size), + Next: next, + GroupPermissions: variables, + } + return &groupPermissions, nil +} + +func decodeUserPermissions(response interface{}) (*UserPermission, error) { + var userPermission UserPermission + err := mapstructure.Decode(response, &userPermission) + if err != nil { + return nil, err + } + return &userPermission, nil +} + +func decodeUsersPermissions(response interface{}) (*UserPermissions, error) { + responseMap := response.(map[string]interface{}) + values := responseMap["values"].([]interface{}) + + var variables []UserPermission + for _, variable := range values { + var userPermission UserPermission + err := mapstructure.Decode(variable, &userPermission) + if err == nil { + variables = append(variables, userPermission) + } + } + + page, ok := responseMap["page"].(float64) + if !ok { + page = 0 + } + + pagelen, ok := responseMap["pagelen"].(float64) + if !ok { + pagelen = 0 + } + max_depth, ok := responseMap["max_depth"].(float64) + if !ok { + max_depth = 0 + } + size, ok := responseMap["size"].(float64) + if !ok { + size = 0 + } + + next, ok := responseMap["next"].(string) + if !ok { + next = "" + } + + userPermissions := UserPermissions{ + Page: int(page), + Pagelen: int(pagelen), + MaxDepth: int(max_depth), + Size: int(size), + Next: next, + UserPermissions: variables, + } + return &userPermissions, nil +} diff --git a/tests/repository_test.go b/tests/repository_test.go index 00c298a..153fce2 100644 --- a/tests/repository_test.go +++ b/tests/repository_test.go @@ -441,3 +441,299 @@ func TestGetRepositoryRefs(t *testing.T) { t.Error("Could not list refs/branch that was created in test setup") } } + +func TestListRepositoryGroupPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryOptions{ + Owner: owner, + RepoSlug: repo, + } + + res, err := c.Repositories.Repository.ListGroupPermissions(opt) + + if err != nil { + t.Error(err) + } + if res == nil { + t.Error("Cannot list repository group permissions") + } + +} + +func TestSetRepositoryGroupPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryGroupPermissionsOptions{ + Owner: owner, + RepoSlug: repo, + Group: "developers", + Permission: "read", + } + + res, err := c.Repositories.Repository.SetGroupPermissions(opt) + if err != nil { + t.Error(err) + } + if res == nil { + t.Error("Cannot set repository group permissions") + } + +} + +func TestDeleteRepositoryGroupPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryGroupPermissionsOptions{ + Owner: owner, + RepoSlug: repo, + Group: "developers", + } + + _, err := c.Repositories.Repository.DeleteGroupPermissions(opt) + if err != nil { + t.Error(err) + } +} + +func TestGetRepositoryGroupPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryGroupPermissionsOptions{ + Owner: owner, + RepoSlug: repo, + Group: "developers", + } + + res, err := c.Repositories.Repository.GetGroupPermissions(opt) + if err != nil { + t.Error(err) + } + if res == nil { + t.Error("Cannot get repository group permissions") + } +} + +func TestListRepositoryUserPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryOptions{ + Owner: owner, + RepoSlug: repo, + } + + res, err := c.Repositories.Repository.ListUserPermissions(opt) + + if err != nil { + t.Error(err) + } + if res == nil { + t.Error("Cannot list repository user permissions") + } + +} +func TestGetRepositoryUserPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryUserPermissionsOptions{ + Owner: owner, + RepoSlug: repo, + User: "5db9ab0fa766000da47cd9e4", + } + + res, err := c.Repositories.Repository.GetUserPermissions(opt) + if err != nil { + t.Error(err) + } + t.Log(res) + if res == nil { + t.Error("Cannot get repository user permissions") + } +} + +func TestDeleteRepositoryUserPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryUserPermissionsOptions{ + Owner: owner, + RepoSlug: repo, + User: "5db9ab0fa766000da47cd9e4", + } + + _, err := c.Repositories.Repository.DeleteUserPermissions(opt) + if err != nil { + t.Error(err) + } +} + +func TestSetRepositoryUserPermissions(t *testing.T) { + + user := os.Getenv("BITBUCKET_TEST_USERNAME") + pass := os.Getenv("BITBUCKET_TEST_PASSWORD") + owner := os.Getenv("BITBUCKET_TEST_OWNER") + repo := os.Getenv("BITBUCKET_TEST_REPOSLUG") + + if user == "" { + t.Error("BITBUCKET_TEST_USERNAME is empty.") + } + if pass == "" { + t.Error("BITBUCKET_TEST_PASSWORD is empty.") + } + if owner == "" { + t.Error("BITBUCKET_TEST_OWNER is empty.") + } + if repo == "" { + t.Error("BITBUCKET_TEST_REPOSLUG is empty.") + } + + c := bitbucket.NewBasicAuth(user, pass) + + opt := &bitbucket.RepositoryUserPermissionsOptions{ + Owner: owner, + RepoSlug: repo, + User: "5e78617ce6f50f0c3a00e583", + Permission: "admin", + } + + res, err := c.Repositories.Repository.SetUserPermissions(opt) + if err != nil { + t.Error(err) + } + if res == nil { + t.Error("Cannot set repository user permissions") + } + +}