diff --git a/pkg/connector/account.go b/pkg/connector/account.go index ced12d0..36029fe 100644 --- a/pkg/connector/account.go +++ b/pkg/connector/account.go @@ -82,7 +82,7 @@ func (acc *accountResourceType) Entitlements(ctx context.Context, resource *v2.R } func (acc *accountResourceType) Grants(ctx context.Context, resource *v2.Resource, token *pagination.Token) ([]*v2.Grant, string, annotations.Annotations, error) { - // parse the roleIds from the users + // parse the roleIDs from the users bag, err := parsePageToken(token.Token, &v2.ResourceId{ResourceType: resourceTypeUser.Id}) if err != nil { return nil, "", nil, err diff --git a/pkg/connector/helpers.go b/pkg/connector/helpers.go index 72cf505..e65da21 100644 --- a/pkg/connector/helpers.go +++ b/pkg/connector/helpers.go @@ -44,7 +44,7 @@ func filterUsersByRole(id string, users []hubspot.User) []hubspot.User { var filteredUsers []hubspot.User for _, user := range users { - for _, roleId := range user.RoleIds { + for _, roleId := range user.RoleIDs { if roleId == id { filteredUsers = append(filteredUsers, user) break @@ -55,8 +55,20 @@ func filterUsersByRole(id string, users []hubspot.User) []hubspot.User { return filteredUsers } -func containsTeam(tIds []string, targetTeam string) bool { - for _, id := range tIds { +func filterUsersBySuperAdmin(users []hubspot.User) []hubspot.User { + var superAdmins []hubspot.User + + for _, user := range users { + if user.SuperAdmin { + superAdmins = append(superAdmins, user) + } + } + + return superAdmins +} + +func containsTeam(tIDs []string, targetTeam string) bool { + for _, id := range tIDs { if id == targetTeam { return true } @@ -65,10 +77,10 @@ func containsTeam(tIds []string, targetTeam string) bool { return false } -func removeTeam(tIds []string, targetTeam string) []string { - tv := make([]string, 0, len(tIds)) +func removeTeam(tIDs []string, targetTeam string) []string { + tv := make([]string, 0, len(tIDs)) - for _, id := range tIds { + for _, id := range tIDs { if id != targetTeam { tv = append(tv, id) } diff --git a/pkg/connector/role.go b/pkg/connector/role.go index 9dea97d..a84bdef 100644 --- a/pkg/connector/role.go +++ b/pkg/connector/role.go @@ -15,7 +15,10 @@ import ( "go.uber.org/zap" ) -const roleMembership = "member" +const ( + roleMembership = "member" + superAdminRole = "super_admin" +) type roleResourceType struct { resourceType *v2.ResourceType @@ -27,7 +30,7 @@ func (r *roleResourceType) ResourceType(_ context.Context) *v2.ResourceType { } // Create a new connector resource for an HubSpot user. -func roleResource(ctx context.Context, role *hubspot.Role, parentResourceID *v2.ResourceId) (*v2.Resource, error) { +func roleResource(role *hubspot.Role, parentResourceID *v2.ResourceId) (*v2.Resource, error) { displayName := titleCase(role.Name) profile := map[string]interface{}{ "role_id": role.Id, @@ -68,7 +71,7 @@ func (r *roleResourceType) List(ctx context.Context, parentId *v2.ResourceId, _ for _, role := range roles { roleCopy := role - rr, err := roleResource(ctx, &roleCopy, parentId) + rr, err := roleResource(&roleCopy, parentId) if err != nil { return nil, "", nil, err } @@ -76,6 +79,15 @@ func (r *roleResourceType) List(ctx context.Context, parentId *v2.ResourceId, _ rv = append(rv, rr) } + // add concrete super admin role + saRole := hubspot.NewRole(superAdminRole, "Super Admin") + sar, err := roleResource(saRole, parentId) + if err != nil { + return nil, "", nil, err + } + + rv = append(rv, sar) + return rv, "", annotations, nil } @@ -129,7 +141,14 @@ func (r *roleResourceType) Grants(ctx context.Context, resource *v2.Resource, to } var rv []*v2.Grant - for _, user := range filterUsersByRole(roleId, users) { + var filteredUsers []hubspot.User + if roleId == superAdminRole { + filteredUsers = filterUsersBySuperAdmin(users) + } else { + filteredUsers = filterUsersByRole(roleId, users) + } + + for _, user := range filteredUsers { userCopy := user ur, err := userResource(ctx, &userCopy, nil) if err != nil { diff --git a/pkg/connector/teams.go b/pkg/connector/teams.go index 5b9d3d9..b67401a 100644 --- a/pkg/connector/teams.go +++ b/pkg/connector/teams.go @@ -37,12 +37,12 @@ func teamResource(ctx context.Context, team *hubspot.Team, parentResourceID *v2. "team_name": team.Name, } - if len(team.UserIds) > 0 { - profile["team_primary_users"] = strings.Join(team.UserIds, ",") + if len(team.UserIDs) > 0 { + profile["team_primary_users"] = strings.Join(team.UserIDs, ",") } - if len(team.SecondaryUserIds) > 0 { - profile["team_secondary_users"] = strings.Join(team.SecondaryUserIds, ",") + if len(team.SecondaryUserIDs) > 0 { + profile["team_secondary_users"] = strings.Join(team.SecondaryUserIDs, ",") } resource, err := rs.NewGroupResource( @@ -122,21 +122,21 @@ func (t *teamResourceType) Grants(ctx context.Context, resource *v2.Resource, _ return nil, "", nil, err } - var primaryUserIds, secondaryUserIds []string + var primaryUserIDs, secondaryUserIDs []string - primaryUserIdsString, ok := rs.GetProfileStringValue(teamTrait.Profile, "team_primary_users") + primaryUserIDsString, ok := rs.GetProfileStringValue(teamTrait.Profile, "team_primary_users") if ok { - primaryUserIds = strings.Split(primaryUserIdsString, ",") + primaryUserIDs = strings.Split(primaryUserIDsString, ",") } - secondaryUserIdsString, ok := rs.GetProfileStringValue(teamTrait.Profile, "team_secondary_users") + secondaryUserIDsString, ok := rs.GetProfileStringValue(teamTrait.Profile, "team_secondary_users") if ok { - secondaryUserIds = strings.Split(secondaryUserIdsString, ",") + secondaryUserIDs = strings.Split(secondaryUserIDsString, ",") } // create membership grants var rv []*v2.Grant - for _, id := range primaryUserIds { + for _, id := range primaryUserIDs { user, _, err := t.client.GetUser(ctx, id) if err != nil { return nil, "", nil, err @@ -158,7 +158,7 @@ func (t *teamResourceType) Grants(ctx context.Context, resource *v2.Resource, _ ) } - for _, id := range secondaryUserIds { + for _, id := range secondaryUserIDs { user, _, err := t.client.GetUser(ctx, id) if err != nil { return nil, "", nil, err @@ -207,8 +207,8 @@ func (t *teamResourceType) Grant(ctx context.Context, principal *v2.Resource, en // there is only one role supported so far var roleId string - if len(user.RoleIds) != 0 { - roleId = user.RoleIds[0] + if len(user.RoleIDs) != 0 { + roleId = user.RoleIDs[0] } var annos annotations.Annotations @@ -229,7 +229,7 @@ func (t *teamResourceType) Grant(ctx context.Context, principal *v2.Resource, en return nil, fmt.Errorf("hubspot-connector: failed to update user: %w", err) } } else if entitlementId == secondaryMemberEntitlement { - if containsTeam(user.SecondaryTeamIds, teamId) { + if containsTeam(user.SecondaryTeamIDs, teamId) { return nil, fmt.Errorf("hubspot-connector: user is already a secondary member of team %s", teamId) } @@ -238,7 +238,7 @@ func (t *teamResourceType) Grant(ctx context.Context, principal *v2.Resource, en principal.Id.Resource, &hubspot.UpdateUserPayload{ RoleId: roleId, - SecondaryTeamIds: append(user.SecondaryTeamIds, teamId), + SecondaryTeamIDs: append(user.SecondaryTeamIDs, teamId), }, ) if err != nil { @@ -274,8 +274,8 @@ func (t *teamResourceType) Revoke(ctx context.Context, grant *v2.Grant) (annotat } var roleId string - if len(user.RoleIds) != 0 { - roleId = user.RoleIds[0] + if len(user.RoleIDs) != 0 { + roleId = user.RoleIDs[0] } var annos annotations.Annotations @@ -295,17 +295,17 @@ func (t *teamResourceType) Revoke(ctx context.Context, grant *v2.Grant) (annotat return nil, fmt.Errorf("hubspot-connector: failed to update user: %w", err) } } else if entitlementId == secondaryMemberEntitlement { - if !containsTeam(user.SecondaryTeamIds, teamId) { + if !containsTeam(user.SecondaryTeamIDs, teamId) { return nil, fmt.Errorf("hubspot-connector: user is not a secondary member of team %s", teamId) } - updatedTeams := removeTeam(user.SecondaryTeamIds, teamId) + updatedTeams := removeTeam(user.SecondaryTeamIDs, teamId) annos, err = t.client.UpdateUser( ctx, principal.Id.Resource, &hubspot.UpdateUserPayload{ RoleId: roleId, - SecondaryTeamIds: updatedTeams, + SecondaryTeamIDs: updatedTeams, }, ) if err != nil { diff --git a/pkg/hubspot/client.go b/pkg/hubspot/client.go index a1ccfd7..5c9a6e6 100644 --- a/pkg/hubspot/client.go +++ b/pkg/hubspot/client.go @@ -156,7 +156,7 @@ func (c *Client) GetRoles(ctx context.Context) ([]Role, annotations.Annotations, type UpdateUserPayload struct { RoleId string `json:"roleId,omitempty"` PrimaryTeamId string `json:"primaryTeamId,omitempty"` - SecondaryTeamIds []string `json:"secondaryTeamIds,omitempty"` + SecondaryTeamIDs []string `json:"secondaryTeamIds,omitempty"` } // UpdateUser updates information about provided user. diff --git a/pkg/hubspot/models.go b/pkg/hubspot/models.go index 584187d..5e5dc30 100644 --- a/pkg/hubspot/models.go +++ b/pkg/hubspot/models.go @@ -7,16 +7,17 @@ type BaseResource struct { type User struct { BaseResource Email string `json:"email"` - RoleIds []string `json:"roleIds"` + RoleIDs []string `json:"roleIds"` TeamId string `json:"primaryTeamId"` - SecondaryTeamIds []string `json:"secondaryTeamIds"` + SecondaryTeamIDs []string `json:"secondaryTeamIds"` + SuperAdmin bool `json:"superAdmin"` } type Team struct { BaseResource Name string `json:"name"` - UserIds []string `json:"userIds"` - SecondaryUserIds []string `json:"secondaryUserIds"` + UserIDs []string `json:"userIds"` + SecondaryUserIDs []string `json:"secondaryUserIds"` } type Account struct { @@ -29,6 +30,15 @@ type Role struct { Name string `json:"name"` } +func NewRole(id, name string) *Role { + return &Role{ + BaseResource: BaseResource{ + Id: id, + }, + Name: name, + } +} + type Page struct { After string `json:"after"` Link string `json:"link"`