Skip to content

Commit

Permalink
Add basic CRUD operations for Group V2 API
Browse files Browse the repository at this point in the history
  • Loading branch information
danlo-orsted committed Apr 26, 2023
1 parent 0a8fe24 commit bd6250e
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 0 deletions.
146 changes: 146 additions & 0 deletions access/services/v2/groups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package v2

import (
"encoding/json"
"fmt"
"github.com/jfrog/jfrog-client-go/auth"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/httputils"
"net/http"
)

const groupsApi = "api/v2/groups"

type GroupParams struct {
GroupDetails
}

type GroupDetails struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
AutoJoin *bool `json:"auto_join,omitempty"`
AdminPrivileges *bool `json:"admin_privileges,omitempty"`
Realm string `json:"realm,omitempty"`
RealmAttributes string `json:"realm_attributes,omitempty"`
ExternalId string `json:"external_id,omitempty"`
Members []string `json:"members,omitempty"`
}

type GroupListItem struct {
GroupName string `json:"group_name"`
Uri string `json:"uri"`
}
type GroupList struct {
Cursor string `json:"cursor,omitempty"`
Groups []GroupListItem `json:"groups"`
}

func NewGroupParams() GroupParams {
return GroupParams{}
}

type GroupService struct {
client *jfroghttpclient.JfrogHttpClient
ServiceDetails auth.ServiceDetails
}

func NewGroupService(client *jfroghttpclient.JfrogHttpClient) *GroupService {
return &GroupService{client: client}
}

func (gs *GroupService) getBaseUrl() string {
return fmt.Sprintf("%s%s", gs.ServiceDetails.GetUrl(), groupsApi)
}
func (gs *GroupService) GetAll() ([]GroupListItem, error) {
httpDetails := gs.ServiceDetails.CreateHttpClientDetails()
url := gs.getBaseUrl()
resp, body, _, err := gs.client.SendGet(url, true, &httpDetails)
if err != nil {
return nil, err
}

if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil {
return nil, err
}
var groupList GroupList
err = json.Unmarshal(body, &groupList)
return groupList.Groups, errorutils.CheckError(err)
}

func (gs *GroupService) Get(name string) (u *GroupDetails, err error) {
httpDetails := gs.ServiceDetails.CreateHttpClientDetails()
url := fmt.Sprintf("%s/%s", gs.getBaseUrl(), name)
resp, body, _, err := gs.client.SendGet(url, true, &httpDetails)
if err != nil {
return nil, err
}

if resp.StatusCode == http.StatusNotFound {
return nil, nil
}
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil {
return nil, err
}
var group GroupDetails
err = json.Unmarshal(body, &group)
return &group, errorutils.CheckError(err)
}

func (gs *GroupService) Create(params GroupParams) error {
group, err := gs.Get(params.Name)
if err != nil {
return err
}
if group != nil {
return errorutils.CheckErrorf("group '%s' already exists", group.Name)
}
content, httpDetails, err := gs.createOrUpdateRequest(params)
if err != nil {
return err
}
resp, body, err := gs.client.SendPost(gs.getBaseUrl(), content, &httpDetails)
if err != nil {
return err
}
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusCreated)
}

func (gs *GroupService) Update(params GroupParams) error {
content, httpDetails, err := gs.createOrUpdateRequest(params)
if err != nil {
return err
}
url := fmt.Sprintf("%s/%s", gs.getBaseUrl(), params.Name)
resp, body, err := gs.client.SendPatch(url, content, &httpDetails)
if err != nil {
return err
}
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK)
}

func (gs *GroupService) createOrUpdateRequest(group GroupParams) (requestContent []byte, httpDetails httputils.HttpClientDetails, err error) {
httpDetails = gs.ServiceDetails.CreateHttpClientDetails()
requestContent, err = json.Marshal(group)
if errorutils.CheckError(err) != nil {
return
}
httpDetails.Headers = map[string]string{
"Content-Type": "application/json",
"Accept": "application/json",
}
return
}

func (gs *GroupService) Delete(name string) error {
httpDetails := gs.ServiceDetails.CreateHttpClientDetails()
url := fmt.Sprintf("%s/%s", gs.getBaseUrl(), name)
resp, body, err := gs.client.SendDelete(url, nil, &httpDetails)
if err != nil {
return err
}
if resp == nil {
return errorutils.CheckErrorf("no response provided (including status code)")
}
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusNoContent)
}
92 changes: 92 additions & 0 deletions tests/accessgroups_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package tests

import (
"fmt"
"testing"

services "github.com/jfrog/jfrog-client-go/access/services/v2"
"github.com/stretchr/testify/assert"
)

func TestAccessGroups(t *testing.T) {
initAccessTest(t)
t.Run("create", testCreateAccessGroup)
t.Run("update", testUpdateAccessGroup)
t.Run("delete", testDeleteAccessGroup)
}

func getTestAccessGroupParams() services.GroupParams {
group := services.GroupDetails{
Name: fmt.Sprintf("test-%s", getRunId()),
Description: "hello",
AutoJoin: &falseValue,
AdminPrivileges: &trueValue,
Realm: "internal",
RealmAttributes: "",
ExternalId: "",
}
return services.GroupParams{GroupDetails: group}
}

func testCreateAccessGroup(t *testing.T) {
groupParams := getTestAccessGroupParams()
err := testAccessGroupService.Create(groupParams)
defer deleteAccessGroupAndAssert(t, groupParams.GroupDetails.Name)
assert.NoError(t, err)

createdGroup, err := testAccessGroupService.Get(groupParams.Name)
assert.NoError(t, err)
assert.NotNil(t, createdGroup)
assert.Equal(t, groupParams.GroupDetails, *createdGroup)

allGroups, err := testAccessGroupService.GetAll()
assert.NoError(t, err)
assert.NotNil(t, allGroups)

var groupNames []string
for _, v := range allGroups {
groupNames = append(groupNames, v.GroupName)
}
assert.Contains(t, groupNames, groupParams.GroupDetails.Name)

}

func testUpdateAccessGroup(t *testing.T) {
groupParams := getTestAccessGroupParams()
err := testAccessGroupService.Create(groupParams)
defer deleteAccessGroupAndAssert(t, groupParams.Name)
assert.NoError(t, err)
groupParams.Description = "Changed description"
groupParams.AutoJoin = &trueValue
groupParams.AdminPrivileges = &falseValue
err = testAccessGroupService.Update(groupParams)
assert.NoError(t, err)
group, err := testAccessGroupService.Get(groupParams.Name)
assert.NoError(t, err)
assert.Equal(t, groupParams.GroupDetails, *group)
}

func testDeleteAccessGroup(t *testing.T) {
groupParams := getTestAccessGroupParams()
assert.NoError(t, testAccessGroupService.Create(groupParams))

deleteAccessGroupAndAssert(t, groupParams.Name)

group, err := testAccessGroupService.Get(groupParams.Name)
assert.NoError(t, err)
assert.Nil(t, group)

allGroups, err := testAccessGroupService.GetAll()
assert.NoError(t, err)
assert.NotNil(t, allGroups)

var allGroupNames []string
for _, v := range allGroups {
allGroupNames = append(allGroupNames, v.GroupName)
}
assert.NotContains(t, allGroupNames, groupParams.Name)
}

func deleteAccessGroupAndAssert(t *testing.T, groupName string) {
assert.NoError(t, testAccessGroupService.Delete(groupName))
}
1 change: 1 addition & 0 deletions tests/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ var (
testsAccessInviteService *accessServices.InviteService
testsAccessTokensService *accessServices.TokenService
testAccessUserService *accessServicesV2.UserService
testAccessGroupService *accessServicesV2.GroupService

timestamp = time.Now().Unix()
timestampStr = strconv.FormatInt(timestamp, 10)
Expand Down

0 comments on commit bd6250e

Please sign in to comment.