mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
User: Add sub resource and api for user teams (#92649)
* Add sub resource for user teams * Add test snapshots * Update to use ref:s
This commit is contained in:
parent
31c9084a3a
commit
294712d7ef
@ -161,6 +161,7 @@ func AddKnownTypes(scheme *runtime.Scheme, version string) {
|
|||||||
schema.GroupVersion{Group: GROUP, Version: version},
|
schema.GroupVersion{Group: GROUP, Version: version},
|
||||||
&User{},
|
&User{},
|
||||||
&UserList{},
|
&UserList{},
|
||||||
|
&UserTeamList{},
|
||||||
&ServiceAccount{},
|
&ServiceAccount{},
|
||||||
&ServiceAccountList{},
|
&ServiceAccountList{},
|
||||||
&Team{},
|
&Team{},
|
||||||
|
@ -13,7 +13,7 @@ type Team struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TeamSpec struct {
|
type TeamSpec struct {
|
||||||
Title string `json:"name,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,3 +25,17 @@ type UserList struct {
|
|||||||
|
|
||||||
Items []User `json:"items,omitempty"`
|
Items []User `json:"items,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
type UserTeamList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Items []UserTeam `json:"items,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserTeam struct {
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
TeamRef TeamRef `json:"teamRef,omitempty"`
|
||||||
|
Permission TeamPermission `json:"permission,omitempty"`
|
||||||
|
}
|
||||||
|
@ -533,3 +533,51 @@ func (in *UserSpec) DeepCopy() *UserSpec {
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *UserTeam) DeepCopyInto(out *UserTeam) {
|
||||||
|
*out = *in
|
||||||
|
out.TeamRef = in.TeamRef
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserTeam.
|
||||||
|
func (in *UserTeam) DeepCopy() *UserTeam {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(UserTeam)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *UserTeamList) DeepCopyInto(out *UserTeamList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]UserTeam, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserTeamList.
|
||||||
|
func (in *UserTeamList) DeepCopy() *UserTeamList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(UserTeamList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *UserTeamList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -35,6 +35,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||||||
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.User": schema_pkg_apis_identity_v0alpha1_User(ref),
|
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.User": schema_pkg_apis_identity_v0alpha1_User(ref),
|
||||||
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserList": schema_pkg_apis_identity_v0alpha1_UserList(ref),
|
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserList": schema_pkg_apis_identity_v0alpha1_UserList(ref),
|
||||||
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserSpec": schema_pkg_apis_identity_v0alpha1_UserSpec(ref),
|
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserSpec": schema_pkg_apis_identity_v0alpha1_UserSpec(ref),
|
||||||
|
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserTeam": schema_pkg_apis_identity_v0alpha1_UserTeam(ref),
|
||||||
|
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserTeamList": schema_pkg_apis_identity_v0alpha1_UserTeamList(ref),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,7 +765,7 @@ func schema_pkg_apis_identity_v0alpha1_TeamSpec(ref common.ReferenceCallback) co
|
|||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Type: []string{"object"},
|
Type: []string{"object"},
|
||||||
Properties: map[string]spec.Schema{
|
Properties: map[string]spec.Schema{
|
||||||
"name": {
|
"title": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Type: []string{"string"},
|
Type: []string{"string"},
|
||||||
Format: "",
|
Format: "",
|
||||||
@ -936,3 +938,84 @@ func schema_pkg_apis_identity_v0alpha1_UserSpec(ref common.ReferenceCallback) co
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func schema_pkg_apis_identity_v0alpha1_UserTeam(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
|
return common.OpenAPIDefinition{
|
||||||
|
Schema: spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"object"},
|
||||||
|
Properties: map[string]spec.Schema{
|
||||||
|
"title": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"string"},
|
||||||
|
Format: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"teamRef": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Default: map[string]interface{}{},
|
||||||
|
Ref: ref("github.com/grafana/grafana/pkg/apis/identity/v0alpha1.TeamRef"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"permission": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Description: "Possible enum values:\n - `\"admin\"`\n - `\"member\"`",
|
||||||
|
Type: []string{"string"},
|
||||||
|
Format: "",
|
||||||
|
Enum: []interface{}{"admin", "member"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Dependencies: []string{
|
||||||
|
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.TeamRef"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func schema_pkg_apis_identity_v0alpha1_UserTeamList(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
|
return common.OpenAPIDefinition{
|
||||||
|
Schema: spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"object"},
|
||||||
|
Properties: map[string]spec.Schema{
|
||||||
|
"kind": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||||
|
Type: []string{"string"},
|
||||||
|
Format: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"apiVersion": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||||
|
Type: []string{"string"},
|
||||||
|
Format: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Default: map[string]interface{}{},
|
||||||
|
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"array"},
|
||||||
|
Items: &spec.SchemaOrArray{
|
||||||
|
Schema: &spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Default: map[string]interface{}{},
|
||||||
|
Ref: ref("github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserTeam"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Dependencies: []string{
|
||||||
|
"github.com/grafana/grafana/pkg/apis/identity/v0alpha1.UserTeam", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/identity/v0alpha1,TeamBindingSpec,Subjects
|
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/identity/v0alpha1,TeamBindingSpec,Subjects
|
||||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/identity/v0alpha1,IdentityDisplay,IdentityType
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/identity/v0alpha1,IdentityDisplay,IdentityType
|
||||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/identity/v0alpha1,IdentityDisplay,InternalID
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/identity/v0alpha1,IdentityDisplay,InternalID
|
||||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/identity/v0alpha1,TeamSpec,Title
|
|
||||||
|
@ -2,6 +2,9 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
identityv0 "github.com/grafana/grafana/pkg/apis/identity/v0alpha1"
|
||||||
|
"github.com/grafana/grafana/pkg/services/team"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OptonalFormatInt formats num as a string. If num is less or equal than 0
|
// OptonalFormatInt formats num as a string. If num is less or equal than 0
|
||||||
@ -12,3 +15,11 @@ func OptionalFormatInt(num int64) string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MapTeamPermission(p team.PermissionType) identityv0.TeamPermission {
|
||||||
|
if p == team.PermissionTypeAdmin {
|
||||||
|
return identityv0.TeamPermissionAdmin
|
||||||
|
} else {
|
||||||
|
return identityv0.TeamPermissionMember
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/grafana/authlib/claims"
|
"github.com/grafana/authlib/claims"
|
||||||
"github.com/grafana/grafana/pkg/services/team"
|
|
||||||
"github.com/grafana/grafana/pkg/storage/legacysql"
|
"github.com/grafana/grafana/pkg/storage/legacysql"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,12 +15,11 @@ type LegacyIdentityStore interface {
|
|||||||
ListDisplay(ctx context.Context, ns claims.NamespaceInfo, query ListDisplayQuery) (*ListUserResult, error)
|
ListDisplay(ctx context.Context, ns claims.NamespaceInfo, query ListDisplayQuery) (*ListUserResult, error)
|
||||||
|
|
||||||
ListUsers(ctx context.Context, ns claims.NamespaceInfo, query ListUserQuery) (*ListUserResult, error)
|
ListUsers(ctx context.Context, ns claims.NamespaceInfo, query ListUserQuery) (*ListUserResult, error)
|
||||||
|
ListUserTeams(ctx context.Context, ns claims.NamespaceInfo, query ListUserTeamsQuery) (*ListUserTeamsResult, error)
|
||||||
|
|
||||||
ListTeams(ctx context.Context, ns claims.NamespaceInfo, query ListTeamQuery) (*ListTeamResult, error)
|
ListTeams(ctx context.Context, ns claims.NamespaceInfo, query ListTeamQuery) (*ListTeamResult, error)
|
||||||
ListTeamBindings(ctx context.Context, ns claims.NamespaceInfo, query ListTeamBindingsQuery) (*ListTeamBindingsResult, error)
|
ListTeamBindings(ctx context.Context, ns claims.NamespaceInfo, query ListTeamBindingsQuery) (*ListTeamBindingsResult, error)
|
||||||
ListTeamMembers(ctx context.Context, ns claims.NamespaceInfo, query ListTeamMembersQuery) (*ListTeamMembersResult, error)
|
ListTeamMembers(ctx context.Context, ns claims.NamespaceInfo, query ListTeamMembersQuery) (*ListTeamMembersResult, error)
|
||||||
|
|
||||||
GetUserTeams(ctx context.Context, ns claims.NamespaceInfo, uid string) ([]team.Team, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -48,6 +48,12 @@ func TestIdentityQueries(t *testing.T) {
|
|||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listUserTeams := func(q *ListUserTeamsQuery) sqltemplate.SQLTemplate {
|
||||||
|
v := newListUserTeams(nodb, q)
|
||||||
|
v.SQLTemplate = mocks.NewTestingSQLTemplate()
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{
|
mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{
|
||||||
RootDir: "testdata",
|
RootDir: "testdata",
|
||||||
Templates: map[*template.Template][]mocks.TemplateTestCase{
|
Templates: map[*template.Template][]mocks.TemplateTestCase{
|
||||||
@ -168,6 +174,24 @@ func TestIdentityQueries(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
sqlQueryUserTeamsTemplate: {
|
||||||
|
{
|
||||||
|
Name: "team_1_members_page_1",
|
||||||
|
Data: listUserTeams(&ListUserTeamsQuery{
|
||||||
|
UserUID: "user-1",
|
||||||
|
OrgID: 1,
|
||||||
|
Pagination: common.Pagination{Limit: 1},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "team_1_members_page_2",
|
||||||
|
Data: listUserTeams(&ListUserTeamsQuery{
|
||||||
|
UserUID: "user-1",
|
||||||
|
OrgID: 1,
|
||||||
|
Pagination: common.Pagination{Limit: 1, Continue: 2},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -328,8 +328,3 @@ func scanMember(rows *sql.Rows) (TeamMember, error) {
|
|||||||
err := rows.Scan(&m.ID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Name, &m.Email, &m.Username, &m.External, &m.Created, &m.Updated, &m.Permission)
|
err := rows.Scan(&m.ID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Name, &m.Email, &m.Username, &m.External, &m.Created, &m.Updated, &m.Permission)
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserTeams implements LegacyIdentityStore.
|
|
||||||
func (s *legacySQLStore) GetUserTeams(ctx context.Context, ns claims.NamespaceInfo, uid string) ([]team.Team, error) {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
8
pkg/registry/apis/identity/legacy/testdata/mysql--user_teams_query-team_1_members_page_1.sql
vendored
Executable file
8
pkg/registry/apis/identity/legacy/testdata/mysql--user_teams_query-team_1_members_page_1.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT t.id as team_id, t.uid as team_uid, t.name as team_name, tm.permission
|
||||||
|
FROM `grafana`.`user` u
|
||||||
|
INNER JOIN `grafana`.`team_member` tm on u.id = tm.user_id
|
||||||
|
INNER JOIN `grafana`.`team`t on tm.team_id = t.id
|
||||||
|
WHERE u.uid = 'user-1'
|
||||||
|
AND t.org_id = 1
|
||||||
|
ORDER BY t.id ASC
|
||||||
|
LIMIT 1;
|
9
pkg/registry/apis/identity/legacy/testdata/mysql--user_teams_query-team_1_members_page_2.sql
vendored
Executable file
9
pkg/registry/apis/identity/legacy/testdata/mysql--user_teams_query-team_1_members_page_2.sql
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
SELECT t.id as team_id, t.uid as team_uid, t.name as team_name, tm.permission
|
||||||
|
FROM `grafana`.`user` u
|
||||||
|
INNER JOIN `grafana`.`team_member` tm on u.id = tm.user_id
|
||||||
|
INNER JOIN `grafana`.`team`t on tm.team_id = t.id
|
||||||
|
WHERE u.uid = 'user-1'
|
||||||
|
AND t.org_id = 1
|
||||||
|
AND t.id >= 2
|
||||||
|
ORDER BY t.id ASC
|
||||||
|
LIMIT 1;
|
8
pkg/registry/apis/identity/legacy/testdata/postgres--user_teams_query-team_1_members_page_1.sql
vendored
Executable file
8
pkg/registry/apis/identity/legacy/testdata/postgres--user_teams_query-team_1_members_page_1.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT t.id as team_id, t.uid as team_uid, t.name as team_name, tm.permission
|
||||||
|
FROM "grafana"."user" u
|
||||||
|
INNER JOIN "grafana"."team_member" tm on u.id = tm.user_id
|
||||||
|
INNER JOIN "grafana"."team"t on tm.team_id = t.id
|
||||||
|
WHERE u.uid = 'user-1'
|
||||||
|
AND t.org_id = 1
|
||||||
|
ORDER BY t.id ASC
|
||||||
|
LIMIT 1;
|
9
pkg/registry/apis/identity/legacy/testdata/postgres--user_teams_query-team_1_members_page_2.sql
vendored
Executable file
9
pkg/registry/apis/identity/legacy/testdata/postgres--user_teams_query-team_1_members_page_2.sql
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
SELECT t.id as team_id, t.uid as team_uid, t.name as team_name, tm.permission
|
||||||
|
FROM "grafana"."user" u
|
||||||
|
INNER JOIN "grafana"."team_member" tm on u.id = tm.user_id
|
||||||
|
INNER JOIN "grafana"."team"t on tm.team_id = t.id
|
||||||
|
WHERE u.uid = 'user-1'
|
||||||
|
AND t.org_id = 1
|
||||||
|
AND t.id >= 2
|
||||||
|
ORDER BY t.id ASC
|
||||||
|
LIMIT 1;
|
8
pkg/registry/apis/identity/legacy/testdata/sqlite--user_teams_query-team_1_members_page_1.sql
vendored
Executable file
8
pkg/registry/apis/identity/legacy/testdata/sqlite--user_teams_query-team_1_members_page_1.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT t.id as team_id, t.uid as team_uid, t.name as team_name, tm.permission
|
||||||
|
FROM "grafana"."user" u
|
||||||
|
INNER JOIN "grafana"."team_member" tm on u.id = tm.user_id
|
||||||
|
INNER JOIN "grafana"."team"t on tm.team_id = t.id
|
||||||
|
WHERE u.uid = 'user-1'
|
||||||
|
AND t.org_id = 1
|
||||||
|
ORDER BY t.id ASC
|
||||||
|
LIMIT 1;
|
9
pkg/registry/apis/identity/legacy/testdata/sqlite--user_teams_query-team_1_members_page_2.sql
vendored
Executable file
9
pkg/registry/apis/identity/legacy/testdata/sqlite--user_teams_query-team_1_members_page_2.sql
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
SELECT t.id as team_id, t.uid as team_uid, t.name as team_name, tm.permission
|
||||||
|
FROM "grafana"."user" u
|
||||||
|
INNER JOIN "grafana"."team_member" tm on u.id = tm.user_id
|
||||||
|
INNER JOIN "grafana"."team"t on tm.team_id = t.id
|
||||||
|
WHERE u.uid = 'user-1'
|
||||||
|
AND t.org_id = 1
|
||||||
|
AND t.id >= 2
|
||||||
|
ORDER BY t.id ASC
|
||||||
|
LIMIT 1;
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/authlib/claims"
|
"github.com/grafana/authlib/claims"
|
||||||
"github.com/grafana/grafana/pkg/registry/apis/identity/common"
|
"github.com/grafana/grafana/pkg/registry/apis/identity/common"
|
||||||
|
"github.com/grafana/grafana/pkg/services/team"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/storage/legacysql"
|
"github.com/grafana/grafana/pkg/storage/legacysql"
|
||||||
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
||||||
@ -109,3 +110,95 @@ func (s *legacySQLStore) queryUsers(ctx context.Context, sql *legacysql.LegacyDa
|
|||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ListUserTeamsQuery struct {
|
||||||
|
UserUID string
|
||||||
|
OrgID int64
|
||||||
|
Pagination common.Pagination
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListUserTeamsResult struct {
|
||||||
|
Continue int64
|
||||||
|
Items []UserTeam
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserTeam struct {
|
||||||
|
ID int64
|
||||||
|
UID string
|
||||||
|
Name string
|
||||||
|
Permission team.PermissionType
|
||||||
|
}
|
||||||
|
|
||||||
|
var sqlQueryUserTeamsTemplate = mustTemplate("user_teams_query.sql")
|
||||||
|
|
||||||
|
func newListUserTeams(sql *legacysql.LegacyDatabaseHelper, q *ListUserTeamsQuery) listUserTeamsQuery {
|
||||||
|
return listUserTeamsQuery{
|
||||||
|
SQLTemplate: sqltemplate.New(sql.DialectForDriver()),
|
||||||
|
UserTable: sql.Table("user"),
|
||||||
|
TeamTable: sql.Table("team"),
|
||||||
|
TeamMemberTable: sql.Table("team_member"),
|
||||||
|
Query: q,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type listUserTeamsQuery struct {
|
||||||
|
sqltemplate.SQLTemplate
|
||||||
|
Query *ListUserTeamsQuery
|
||||||
|
UserTable string
|
||||||
|
TeamTable string
|
||||||
|
TeamMemberTable string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r listUserTeamsQuery) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *legacySQLStore) ListUserTeams(ctx context.Context, ns claims.NamespaceInfo, query ListUserTeamsQuery) (*ListUserTeamsResult, error) {
|
||||||
|
query.Pagination.Limit += 1
|
||||||
|
query.OrgID = ns.OrgID
|
||||||
|
if query.OrgID == 0 {
|
||||||
|
return nil, fmt.Errorf("expected non zero org id")
|
||||||
|
}
|
||||||
|
|
||||||
|
sql, err := s.sql(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req := newListUserTeams(sql, &query)
|
||||||
|
q, err := sqltemplate.Execute(sqlQueryUserTeamsTemplate, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("execute template %q: %w", sqlQueryTeamsTemplate.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := sql.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...)
|
||||||
|
defer func() {
|
||||||
|
if rows != nil {
|
||||||
|
_ = rows.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &ListUserTeamsResult{}
|
||||||
|
var lastID int64
|
||||||
|
for rows.Next() {
|
||||||
|
t := UserTeam{}
|
||||||
|
err := rows.Scan(&t.ID, &t.UID, &t.Name, &t.Permission)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lastID = t.ID
|
||||||
|
res.Items = append(res.Items, t)
|
||||||
|
if len(res.Items) > int(query.Pagination.Limit)-1 {
|
||||||
|
res.Continue = lastID
|
||||||
|
res.Items = res.Items[0 : len(res.Items)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
11
pkg/registry/apis/identity/legacy/user_teams_query.sql
Normal file
11
pkg/registry/apis/identity/legacy/user_teams_query.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
SELECT t.id as team_id, t.uid as team_uid, t.name as team_name, tm.permission
|
||||||
|
FROM {{ .Ident .UserTable }} u
|
||||||
|
INNER JOIN {{ .Ident .TeamMemberTable }} tm on u.id = tm.user_id
|
||||||
|
INNER JOIN {{ .Ident .TeamTable }}t on tm.team_id = t.id
|
||||||
|
WHERE u.uid = {{ .Arg .Query.UserUID }}
|
||||||
|
AND t.org_id = {{ .Arg .Query.OrgID }}
|
||||||
|
{{- if .Query.Pagination.Continue }}
|
||||||
|
AND t.id >= {{ .Arg .Query.Pagination.Continue }}
|
||||||
|
{{- end }}
|
||||||
|
ORDER BY t.id ASC
|
||||||
|
LIMIT {{ .Arg .Query.Pagination.Limit }};
|
@ -89,7 +89,7 @@ func (b *IdentityAPIBuilder) GetAPIGroupInfo(
|
|||||||
|
|
||||||
userResource := identityv0.UserResourceInfo
|
userResource := identityv0.UserResourceInfo
|
||||||
storage[userResource.StoragePath()] = user.NewLegacyStore(b.Store)
|
storage[userResource.StoragePath()] = user.NewLegacyStore(b.Store)
|
||||||
storage[userResource.StoragePath("teams")] = team.NewLegacyUserTeamsStore(b.Store)
|
storage[userResource.StoragePath("teams")] = user.NewLegacyTeamMemberREST(b.Store)
|
||||||
|
|
||||||
serviceaccountResource := identityv0.ServiceAccountResourceInfo
|
serviceaccountResource := identityv0.ServiceAccountResourceInfo
|
||||||
storage[serviceaccountResource.StoragePath()] = serviceaccount.NewLegacyStore(b.Store)
|
storage[serviceaccountResource.StoragePath()] = serviceaccount.NewLegacyStore(b.Store)
|
||||||
@ -100,7 +100,7 @@ func (b *IdentityAPIBuilder) GetAPIGroupInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The display endpoint -- NOTE, this uses a rewrite hack to allow requests without a name parameter
|
// The display endpoint -- NOTE, this uses a rewrite hack to allow requests without a name parameter
|
||||||
storage["display"] = user.NewLegacyDisplayStore(b.Store)
|
storage["display"] = user.NewLegacyDisplayREST(b.Store)
|
||||||
|
|
||||||
apiGroupInfo.VersionedResourcesStorageMap[identityv0.VERSION] = storage
|
apiGroupInfo.VersionedResourcesStorageMap[identityv0.VERSION] = storage
|
||||||
return &apiGroupInfo, nil
|
return &apiGroupInfo, nil
|
||||||
|
@ -62,8 +62,6 @@ func (s *LegacyTeamMemberREST) Connect(ctx context.Context, name string, options
|
|||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = common.PaginationFromListQuery(r.URL.Query())
|
|
||||||
|
|
||||||
res, err := s.store.ListTeamMembers(ctx, ns, legacy.ListTeamMembersQuery{
|
res, err := s.store.ListTeamMembers(ctx, ns, legacy.ListTeamMembersQuery{
|
||||||
UID: name,
|
UID: name,
|
||||||
Pagination: common.PaginationFromListQuery(r.URL.Query()),
|
Pagination: common.PaginationFromListQuery(r.URL.Query()),
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/registry/apis/identity/common"
|
"github.com/grafana/grafana/pkg/registry/apis/identity/common"
|
||||||
"github.com/grafana/grafana/pkg/registry/apis/identity/legacy"
|
"github.com/grafana/grafana/pkg/registry/apis/identity/legacy"
|
||||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||||
"github.com/grafana/grafana/pkg/services/team"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -130,28 +129,3 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO
|
|||||||
}
|
}
|
||||||
return nil, resource.NewNotFound(name)
|
return nil, resource.NewNotFound(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asTeam(team *team.Team, ns string) (*identityv0.Team, error) {
|
|
||||||
item := &identityv0.Team{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: team.UID,
|
|
||||||
Namespace: ns,
|
|
||||||
CreationTimestamp: metav1.NewTime(team.Created),
|
|
||||||
ResourceVersion: strconv.FormatInt(team.Updated.UnixMilli(), 10),
|
|
||||||
},
|
|
||||||
Spec: identityv0.TeamSpec{
|
|
||||||
Title: team.Name,
|
|
||||||
Email: team.Email,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
meta, err := utils.MetaAccessor(item)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
meta.SetUpdatedTimestamp(&team.Updated)
|
|
||||||
meta.SetOriginInfo(&utils.ResourceOriginInfo{
|
|
||||||
Name: "SQL",
|
|
||||||
Path: strconv.FormatInt(team.ID, 10),
|
|
||||||
})
|
|
||||||
return item, nil
|
|
||||||
}
|
|
||||||
|
@ -150,7 +150,7 @@ func mapToSubjects(members []legacy.TeamMember) []identityv0.TeamSubject {
|
|||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
out = append(out, identityv0.TeamSubject{
|
out = append(out, identityv0.TeamSubject{
|
||||||
Name: m.MemberID(),
|
Name: m.MemberID(),
|
||||||
Permission: mapPermisson(m.Permission),
|
Permission: common.MapTeamPermission(m.Permission),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
package team
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
|
||||||
|
|
||||||
identityv0 "github.com/grafana/grafana/pkg/apis/identity/v0alpha1"
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
|
||||||
"github.com/grafana/grafana/pkg/registry/apis/identity/legacy"
|
|
||||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ rest.Storage = (*LegacyUserTeamsStore)(nil)
|
|
||||||
_ rest.SingularNameProvider = (*LegacyUserTeamsStore)(nil)
|
|
||||||
_ rest.Connecter = (*LegacyUserTeamsStore)(nil)
|
|
||||||
_ rest.Scoper = (*LegacyUserTeamsStore)(nil)
|
|
||||||
_ rest.StorageMetadata = (*LegacyUserTeamsStore)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewLegacyUserTeamsStore(store legacy.LegacyIdentityStore) *LegacyUserTeamsStore {
|
|
||||||
return &LegacyUserTeamsStore{
|
|
||||||
logger: log.New("user teams"),
|
|
||||||
store: store,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type LegacyUserTeamsStore struct {
|
|
||||||
logger log.Logger
|
|
||||||
store legacy.LegacyIdentityStore
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) New() runtime.Object {
|
|
||||||
return &identityv0.TeamList{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) Destroy() {}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) NamespaceScoped() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) GetSingularName() string {
|
|
||||||
return "TeamList"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) ProducesMIMETypes(verb string) []string {
|
|
||||||
return []string{"application/json"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) ProducesObject(verb string) interface{} {
|
|
||||||
return &identityv0.TeamList{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) ConnectMethods() []string {
|
|
||||||
return []string{"GET"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) NewConnectOptions() (runtime.Object, bool, string) {
|
|
||||||
return nil, false, "" // true means you can use the trailing path as a variable
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LegacyUserTeamsStore) Connect(ctx context.Context, name string, _ runtime.Object, responder rest.Responder) (http.Handler, error) {
|
|
||||||
ns, err := request.NamespaceInfoFrom(ctx, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
teams, err := r.store.GetUserTeams(ctx, ns, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
|
||||||
list := &identityv0.TeamList{}
|
|
||||||
for _, team := range teams {
|
|
||||||
t, err := asTeam(&team, ns.Value)
|
|
||||||
if err != nil {
|
|
||||||
responder.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
list.Items = append(list.Items, *t)
|
|
||||||
}
|
|
||||||
responder.Object(200, list)
|
|
||||||
}), nil
|
|
||||||
}
|
|
@ -18,57 +18,57 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LegacyDisplayStore struct {
|
type LegacyDisplayREST struct {
|
||||||
store legacy.LegacyIdentityStore
|
store legacy.LegacyIdentityStore
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ rest.Storage = (*LegacyDisplayStore)(nil)
|
_ rest.Storage = (*LegacyDisplayREST)(nil)
|
||||||
_ rest.SingularNameProvider = (*LegacyDisplayStore)(nil)
|
_ rest.SingularNameProvider = (*LegacyDisplayREST)(nil)
|
||||||
_ rest.Connecter = (*LegacyDisplayStore)(nil)
|
_ rest.Connecter = (*LegacyDisplayREST)(nil)
|
||||||
_ rest.Scoper = (*LegacyDisplayStore)(nil)
|
_ rest.Scoper = (*LegacyDisplayREST)(nil)
|
||||||
_ rest.StorageMetadata = (*LegacyDisplayStore)(nil)
|
_ rest.StorageMetadata = (*LegacyDisplayREST)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLegacyDisplayStore(store legacy.LegacyIdentityStore) *LegacyDisplayStore {
|
func NewLegacyDisplayREST(store legacy.LegacyIdentityStore) *LegacyDisplayREST {
|
||||||
return &LegacyDisplayStore{store}
|
return &LegacyDisplayREST{store}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) New() runtime.Object {
|
func (r *LegacyDisplayREST) New() runtime.Object {
|
||||||
return &identity.IdentityDisplayResults{}
|
return &identity.IdentityDisplayResults{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) Destroy() {}
|
func (r *LegacyDisplayREST) Destroy() {}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) NamespaceScoped() bool {
|
func (r *LegacyDisplayREST) NamespaceScoped() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) GetSingularName() string {
|
func (r *LegacyDisplayREST) GetSingularName() string {
|
||||||
// not actually used anywhere, but required by SingularNameProvider
|
// not actually used anywhere, but required by SingularNameProvider
|
||||||
return "identitydisplay"
|
return "identitydisplay"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) ProducesMIMETypes(verb string) []string {
|
func (r *LegacyDisplayREST) ProducesMIMETypes(verb string) []string {
|
||||||
return []string{"application/json"}
|
return []string{"application/json"}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) ProducesObject(verb string) any {
|
func (r *LegacyDisplayREST) ProducesObject(verb string) any {
|
||||||
return &identity.IdentityDisplayResults{}
|
return &identity.IdentityDisplayResults{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) ConnectMethods() []string {
|
func (r *LegacyDisplayREST) ConnectMethods() []string {
|
||||||
return []string{"GET"}
|
return []string{"GET"}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) NewConnectOptions() (runtime.Object, bool, string) {
|
func (r *LegacyDisplayREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||||
return nil, false, "" // true means you can use the trailing path as a variable
|
return nil, false, "" // true means you can use the trailing path as a variable
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will always have an empty app url
|
// This will always have an empty app url
|
||||||
var fakeCfgForGravatar = &setting.Cfg{}
|
var fakeCfgForGravatar = &setting.Cfg{}
|
||||||
|
|
||||||
func (r *LegacyDisplayStore) Connect(ctx context.Context, name string, _ runtime.Object, responder rest.Responder) (http.Handler, error) {
|
func (r *LegacyDisplayREST) Connect(ctx context.Context, name string, _ runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||||
// See: /pkg/services/apiserver/builder/helper.go#L34
|
// See: /pkg/services/apiserver/builder/helper.go#L34
|
||||||
// The name is set with a rewriter hack
|
// The name is set with a rewriter hack
|
||||||
if name != "name" {
|
if name != "name" {
|
101
pkg/registry/apis/identity/user/rest_user_team.go
Normal file
101
pkg/registry/apis/identity/user/rest_user_team.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
|
|
||||||
|
identityv0 "github.com/grafana/grafana/pkg/apis/identity/v0alpha1"
|
||||||
|
"github.com/grafana/grafana/pkg/registry/apis/identity/common"
|
||||||
|
"github.com/grafana/grafana/pkg/registry/apis/identity/legacy"
|
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ rest.Storage = (*LegacyUserTeamREST)(nil)
|
||||||
|
_ rest.Scoper = (*LegacyUserTeamREST)(nil)
|
||||||
|
_ rest.StorageMetadata = (*LegacyUserTeamREST)(nil)
|
||||||
|
_ rest.Connecter = (*LegacyUserTeamREST)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewLegacyTeamMemberREST(store legacy.LegacyIdentityStore) *LegacyUserTeamREST {
|
||||||
|
return &LegacyUserTeamREST{store}
|
||||||
|
}
|
||||||
|
|
||||||
|
type LegacyUserTeamREST struct {
|
||||||
|
store legacy.LegacyIdentityStore
|
||||||
|
}
|
||||||
|
|
||||||
|
// New implements rest.Storage.
|
||||||
|
func (s *LegacyUserTeamREST) New() runtime.Object {
|
||||||
|
return &identityv0.UserTeamList{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy implements rest.Storage.
|
||||||
|
func (s *LegacyUserTeamREST) Destroy() {}
|
||||||
|
|
||||||
|
// NamespaceScoped implements rest.Scoper.
|
||||||
|
func (s *LegacyUserTeamREST) NamespaceScoped() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProducesMIMETypes implements rest.StorageMetadata.
|
||||||
|
func (s *LegacyUserTeamREST) ProducesMIMETypes(verb string) []string {
|
||||||
|
return []string{"application/json"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProducesObject implements rest.StorageMetadata.
|
||||||
|
func (s *LegacyUserTeamREST) ProducesObject(verb string) interface{} {
|
||||||
|
return s.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect implements rest.Connecter.
|
||||||
|
func (s *LegacyUserTeamREST) Connect(ctx context.Context, name string, options runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||||
|
ns, err := request.NamespaceInfoFrom(ctx, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
res, err := s.store.ListUserTeams(ctx, ns, legacy.ListUserTeamsQuery{
|
||||||
|
UserUID: name,
|
||||||
|
Pagination: common.PaginationFromListQuery(r.URL.Query()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
responder.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
list := &identityv0.UserTeamList{Items: make([]identityv0.UserTeam, 0, len(res.Items))}
|
||||||
|
|
||||||
|
for _, m := range res.Items {
|
||||||
|
list.Items = append(list.Items, mapToUserTeam(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
list.ListMeta.Continue = common.OptionalFormatInt(res.Continue)
|
||||||
|
|
||||||
|
responder.Object(http.StatusOK, list)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConnectOptions implements rest.Connecter.
|
||||||
|
func (s *LegacyUserTeamREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||||
|
return nil, false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectMethods implements rest.Connecter.
|
||||||
|
func (s *LegacyUserTeamREST) ConnectMethods() []string {
|
||||||
|
return []string{http.MethodGet}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapToUserTeam(t legacy.UserTeam) identityv0.UserTeam {
|
||||||
|
return identityv0.UserTeam{
|
||||||
|
Title: t.Name,
|
||||||
|
TeamRef: identityv0.TeamRef{
|
||||||
|
Name: t.UID,
|
||||||
|
},
|
||||||
|
Permission: common.MapTeamPermission(t.Permission),
|
||||||
|
}
|
||||||
|
}
|
@ -69,7 +69,6 @@ func TestIntegrationIdentity(t *testing.T) {
|
|||||||
rsp, err := teamClient.Resource.List(ctx, metav1.ListOptions{})
|
rsp, err := teamClient.Resource.List(ctx, metav1.ListOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
found := teamClient.SanitizeJSONList(rsp, "name")
|
found := teamClient.SanitizeJSONList(rsp, "name")
|
||||||
// fmt.Printf("%s", found)
|
|
||||||
require.JSONEq(t, `{
|
require.JSONEq(t, `{
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
@ -87,7 +86,7 @@ func TestIntegrationIdentity(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"email": "staff@Org1",
|
"email": "staff@Org1",
|
||||||
"name": "staff"
|
"title": "staff"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user