mirror of
https://github.com/grafana/grafana.git
synced 2026-01-15 13:48:14 +00:00
Compare commits
2 Commits
ash/react-
...
dmihai/tea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7337c65d1 | ||
|
|
375c22c5b0 |
@@ -2,6 +2,8 @@ package v0alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
@@ -27,9 +29,12 @@ type TeamSearchResults struct {
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
type TeamHit struct {
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Provisioned bool `json:"provisioned,omitempty"`
|
||||
ExternalUID string `json:"externalUID,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Provisioned bool `json:"provisioned,omitempty"`
|
||||
ExternalUID string `json:"externalUID,omitempty"`
|
||||
MemberCount int64 `json:"memberCount"`
|
||||
Permission team.PermissionType `json:"permission"`
|
||||
AccessControl map[string]bool `json:"accessControl,omitempty"`
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package team
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math"
|
||||
@@ -78,7 +80,7 @@ func (c *LegacyTeamSearchClient) Search(ctx context.Context, req *resourcepb.Res
|
||||
namespace := signedInUser.GetNamespace()
|
||||
|
||||
for _, t := range res.Teams {
|
||||
cells := createCells(t, req.Fields)
|
||||
cells := createCells(c.log, t, req.Fields)
|
||||
list.Results.Rows = append(list.Results.Rows, &resourcepb.ResourceTableRow{
|
||||
Key: getResourceKey(t, namespace),
|
||||
Cells: cells,
|
||||
@@ -120,7 +122,7 @@ func getDefaultColumns() []*resourcepb.ResourceTableColumnDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
func createCells(t *team.TeamDTO, fields []string) [][]byte {
|
||||
func createCells(log *slog.Logger, t *team.TeamDTO, fields []string) [][]byte {
|
||||
cells := createDefaultCells(t)
|
||||
for _, field := range fields {
|
||||
fieldName := strings.TrimPrefix(field, res.SEARCH_FIELD_PREFIX)
|
||||
@@ -131,6 +133,22 @@ func createCells(t *team.TeamDTO, fields []string) [][]byte {
|
||||
cells = append(cells, []byte(strconv.FormatBool(t.IsProvisioned)))
|
||||
case builders.TEAM_SEARCH_EXTERNAL_UID:
|
||||
cells = append(cells, []byte(t.ExternalUID))
|
||||
case builders.TEAM_SEARCH_MEMBER_COUNT:
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, uint64(t.MemberCount))
|
||||
cells = append(cells, b)
|
||||
case builders.TEAM_SEARCH_PERMISSION:
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, uint32(t.Permission))
|
||||
cells = append(cells, b)
|
||||
case builders.TEAM_SEARCH_ACCESS_CONTROL:
|
||||
accessControl, err := json.Marshal(t.AccessControl)
|
||||
if err != nil {
|
||||
log.Error("error marshalling access control", "error", err)
|
||||
cells = append(cells, []byte(""))
|
||||
continue
|
||||
}
|
||||
cells = append(cells, accessControl)
|
||||
}
|
||||
}
|
||||
return cells
|
||||
|
||||
@@ -2,6 +2,7 @@ package team
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"testing"
|
||||
@@ -25,7 +26,7 @@ func TestLegacyTeamSearchClient_Search(t *testing.T) {
|
||||
Limit: 10,
|
||||
Page: 1,
|
||||
Query: "test",
|
||||
Fields: []string{"name", "email", "provisioned", "externalUID"},
|
||||
Fields: []string{"name", "email", "provisioned", "externalUID", "memberCount", "permission", "accessControl"},
|
||||
}
|
||||
|
||||
mockTeamService.ExpectedSearchTeamsResult = team.SearchTeamQueryResult{
|
||||
@@ -36,6 +37,9 @@ func TestLegacyTeamSearchClient_Search(t *testing.T) {
|
||||
Email: "test@example.com",
|
||||
IsProvisioned: true,
|
||||
ExternalUID: "testExternalUID",
|
||||
MemberCount: 10,
|
||||
Permission: team.PermissionTypeAdmin,
|
||||
AccessControl: map[string]bool{"test": true},
|
||||
},
|
||||
},
|
||||
TotalCount: 1,
|
||||
@@ -48,7 +52,7 @@ func TestLegacyTeamSearchClient_Search(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), resp.TotalHits)
|
||||
require.Len(t, resp.Results.Rows, 1)
|
||||
require.Len(t, resp.Results.Columns, 5)
|
||||
require.Len(t, resp.Results.Columns, 8)
|
||||
require.Equal(t, "default", resp.Results.Rows[0].Key.Namespace)
|
||||
require.Equal(t, "iam.grafana.com", resp.Results.Rows[0].Key.Group)
|
||||
require.Equal(t, "teams", resp.Results.Rows[0].Key.Resource)
|
||||
@@ -58,6 +62,9 @@ func TestLegacyTeamSearchClient_Search(t *testing.T) {
|
||||
require.Equal(t, "test@example.com", string(resp.Results.Rows[0].Cells[2]))
|
||||
require.Equal(t, "true", string(resp.Results.Rows[0].Cells[3]))
|
||||
require.Equal(t, "testExternalUID", string(resp.Results.Rows[0].Cells[4]))
|
||||
require.Equal(t, 10, int(binary.BigEndian.Uint64(resp.Results.Rows[0].Cells[5])))
|
||||
require.Equal(t, team.PermissionTypeAdmin, team.PermissionType(binary.BigEndian.Uint32(resp.Results.Rows[0].Cells[6])))
|
||||
require.Equal(t, "{\"test\":true}", string(resp.Results.Rows[0].Cells[7]))
|
||||
})
|
||||
|
||||
t.Run("returns error if page is negative", func(t *testing.T) {
|
||||
|
||||
@@ -179,6 +179,9 @@ func (s *TeamSearchHandler) DoTeamSearch(w http.ResponseWriter, r *http.Request)
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_EMAIL,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_PROVISIONED,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_EXTERNAL_UID,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_MEMBER_COUNT,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_PERMISSION,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_ACCESS_CONTROL,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestTeamSearchHandler(t *testing.T) {
|
||||
if mockClient.LastSearchRequest == nil {
|
||||
t.Fatalf("expected Search to be called, but it was not")
|
||||
}
|
||||
expectedFields := []string{"title", "fields.email", "fields.provisioned", "fields.externalUID"}
|
||||
expectedFields := []string{"title", "fields.email", "fields.provisioned", "fields.externalUID", "fields.memberCount", "fields.permission", "fields.accessControl"}
|
||||
if fmt.Sprintf("%v", mockClient.LastSearchRequest.Fields) != fmt.Sprintf("%v", expectedFields) {
|
||||
t.Errorf("expected fields %v, got %v", expectedFields, mockClient.LastSearchRequest.Fields)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/search/builders"
|
||||
@@ -22,6 +25,9 @@ func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0al
|
||||
emailIDX := -1
|
||||
provisionedIDX := -1
|
||||
externalUIDIDX := -1
|
||||
memberCountIDX := -1
|
||||
permissionIDX := -1
|
||||
accessControlIDX := -1
|
||||
|
||||
for i, v := range result.Results.Columns {
|
||||
if v == nil {
|
||||
@@ -37,6 +43,12 @@ func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0al
|
||||
provisionedIDX = i
|
||||
case builders.TEAM_SEARCH_EXTERNAL_UID:
|
||||
externalUIDIDX = i
|
||||
case builders.TEAM_SEARCH_MEMBER_COUNT:
|
||||
memberCountIDX = i
|
||||
case builders.TEAM_SEARCH_PERMISSION:
|
||||
permissionIDX = i
|
||||
case builders.TEAM_SEARCH_ACCESS_CONTROL:
|
||||
accessControlIDX = i
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +87,25 @@ func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0al
|
||||
hit.ExternalUID = string(row.Cells[externalUIDIDX])
|
||||
}
|
||||
|
||||
if memberCountIDX >= 0 && row.Cells[memberCountIDX] != nil {
|
||||
memberCount := binary.BigEndian.Uint64(row.Cells[memberCountIDX])
|
||||
hit.MemberCount = int64(memberCount)
|
||||
}
|
||||
|
||||
if permissionIDX >= 0 && row.Cells[permissionIDX] != nil {
|
||||
permission := binary.BigEndian.Uint32(row.Cells[permissionIDX])
|
||||
hit.Permission = team.PermissionType(permission)
|
||||
}
|
||||
|
||||
if accessControlIDX >= 0 && row.Cells[accessControlIDX] != nil {
|
||||
var accessControl map[string]bool
|
||||
err := json.Unmarshal(row.Cells[accessControlIDX], &accessControl)
|
||||
if err != nil {
|
||||
return v0alpha1.TeamSearchResults{}, fmt.Errorf("error parsing team search response: error unmarshalling access control: %w", err)
|
||||
}
|
||||
hit.AccessControl = accessControl
|
||||
}
|
||||
|
||||
sr.Hits[i] = *hit
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
)
|
||||
|
||||
@@ -29,6 +31,18 @@ func TestParseResults(t *testing.T) {
|
||||
Name: "externalUID",
|
||||
Type: resourcepb.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
{
|
||||
Name: "memberCount",
|
||||
Type: resourcepb.ResourceTableColumnDefinition_INT64,
|
||||
},
|
||||
{
|
||||
Name: "permission",
|
||||
Type: resourcepb.ResourceTableColumnDefinition_INT32,
|
||||
},
|
||||
{
|
||||
Name: "accessControl",
|
||||
Type: resourcepb.ResourceTableColumnDefinition_OBJECT,
|
||||
},
|
||||
},
|
||||
Rows: []*resourcepb.ResourceTableRow{
|
||||
{
|
||||
@@ -41,6 +55,17 @@ func TestParseResults(t *testing.T) {
|
||||
[]byte("team1@example.com"),
|
||||
[]byte("true"),
|
||||
[]byte("team1-uid"),
|
||||
func() []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, 10)
|
||||
return b
|
||||
}(),
|
||||
func() []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, 4)
|
||||
return b
|
||||
}(),
|
||||
[]byte("{\"test\":true}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -55,6 +80,9 @@ func TestParseResults(t *testing.T) {
|
||||
require.Equal(t, "team1@example.com", results.Hits[0].Email)
|
||||
require.True(t, results.Hits[0].Provisioned)
|
||||
require.Equal(t, "team1-uid", results.Hits[0].ExternalUID)
|
||||
require.Equal(t, int64(10), results.Hits[0].MemberCount)
|
||||
require.Equal(t, team.PermissionTypeAdmin, results.Hits[0].Permission)
|
||||
require.Equal(t, map[string]bool{"test": true}, results.Hits[0].AccessControl)
|
||||
})
|
||||
|
||||
t.Run("should handle nil result", func(t *testing.T) {
|
||||
|
||||
@@ -14,9 +14,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
TEAM_SEARCH_EMAIL = "email"
|
||||
TEAM_SEARCH_PROVISIONED = "provisioned"
|
||||
TEAM_SEARCH_EXTERNAL_UID = "externalUID"
|
||||
TEAM_SEARCH_EMAIL = "email"
|
||||
TEAM_SEARCH_PROVISIONED = "provisioned"
|
||||
TEAM_SEARCH_EXTERNAL_UID = "externalUID"
|
||||
TEAM_SEARCH_MEMBER_COUNT = "memberCount"
|
||||
TEAM_SEARCH_PERMISSION = "permission"
|
||||
TEAM_SEARCH_ACCESS_CONTROL = "accessControl"
|
||||
)
|
||||
|
||||
var TeamSearchTableColumnDefinitions = map[string]*resourcepb.ResourceTableColumnDefinition{
|
||||
@@ -35,6 +38,21 @@ var TeamSearchTableColumnDefinitions = map[string]*resourcepb.ResourceTableColum
|
||||
Type: resourcepb.ResourceTableColumnDefinition_STRING,
|
||||
Description: "External UID of the team",
|
||||
},
|
||||
TEAM_SEARCH_MEMBER_COUNT: {
|
||||
Name: TEAM_SEARCH_MEMBER_COUNT,
|
||||
Type: resourcepb.ResourceTableColumnDefinition_INT64,
|
||||
Description: "Number of members in the team",
|
||||
},
|
||||
TEAM_SEARCH_PERMISSION: {
|
||||
Name: TEAM_SEARCH_PERMISSION,
|
||||
Type: resourcepb.ResourceTableColumnDefinition_INT32,
|
||||
Description: "Permission of the team",
|
||||
},
|
||||
TEAM_SEARCH_ACCESS_CONTROL: {
|
||||
Name: TEAM_SEARCH_ACCESS_CONTROL,
|
||||
Type: resourcepb.ResourceTableColumnDefinition_OBJECT,
|
||||
Description: "Access control of the team",
|
||||
},
|
||||
}
|
||||
|
||||
func GetTeamSearchBuilder() (resource.DocumentBuilderInfo, error) {
|
||||
|
||||
Reference in New Issue
Block a user