mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:57:33 +00:00
feat(api): add possibility to retrieve user schemas (#7614)
This PR extends the user schema service (V3 API) with the possibility to ListUserSchemas and GetUserSchemaByID. The previously started guide is extended to demonstrate how to retrieve the schema(s) and notes the generated revision property.
This commit is contained in:
@@ -21,7 +21,7 @@ func UserQueriesToQuery(queries []*user_pb.SearchQuery, level uint8) (_ []query.
|
||||
func UserQueryToQuery(query *user_pb.SearchQuery, level uint8) (query.SearchQuery, error) {
|
||||
if level > 20 {
|
||||
// can't go deeper than 20 levels of nesting.
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "USER-zsQ97", "Errors.User.TooManyNestingLevels")
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "USER-zsQ97", "Errors.Query.TooManyNestingLevels")
|
||||
}
|
||||
switch q := query.Query.(type) {
|
||||
case *user_pb.SearchQuery_UserNameQuery:
|
||||
|
@@ -3,10 +3,13 @@ package schema
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/user/schema/v3alpha"
|
||||
)
|
||||
@@ -45,6 +48,7 @@ func (s *Server) UpdateUserSchema(ctx context.Context, req *schema.UpdateUserSch
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateUserSchema(ctx context.Context, req *schema.DeactivateUserSchemaRequest) (*schema.DeactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -57,6 +61,7 @@ func (s *Server) DeactivateUserSchema(ctx context.Context, req *schema.Deactivat
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateUserSchema(ctx context.Context, req *schema.ReactivateUserSchemaRequest) (*schema.ReactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -69,6 +74,7 @@ func (s *Server) ReactivateUserSchema(ctx context.Context, req *schema.Reactivat
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteUserSchema(ctx context.Context, req *schema.DeleteUserSchemaRequest) (*schema.DeleteUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -82,6 +88,153 @@ func (s *Server) DeleteUserSchema(ctx context.Context, req *schema.DeleteUserSch
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListUserSchemas(ctx context.Context, req *schema.ListUserSchemasRequest) (*schema.ListUserSchemasResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries, err := listUserSchemaToQuery(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.SearchUserSchema(ctx, queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchemas, err := userSchemasToPb(res.UserSchemas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.ListUserSchemasResponse{
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
Result: userSchemas,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetUserSchemaByID(ctx context.Context, req *schema.GetUserSchemaByIDRequest) (*schema.GetUserSchemaByIDResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.GetUserSchemaByID(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchema, err := userSchemaToPb(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.GetUserSchemaByIDResponse{
|
||||
Schema: userSchema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userSchemasToPb(schemas []*query.UserSchema) (_ []*schema.UserSchema, err error) {
|
||||
userSchemas := make([]*schema.UserSchema, len(schemas))
|
||||
for i, userSchema := range schemas {
|
||||
userSchemas[i], err = userSchemaToPb(userSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return userSchemas, nil
|
||||
}
|
||||
|
||||
func userSchemaToPb(userSchema *query.UserSchema) (*schema.UserSchema, error) {
|
||||
s := new(structpb.Struct)
|
||||
if err := s.UnmarshalJSON(userSchema.Schema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.UserSchema{
|
||||
Id: userSchema.ID,
|
||||
Details: object.DomainToDetailsPb(&userSchema.ObjectDetails),
|
||||
Type: userSchema.Type,
|
||||
State: userSchemaStateToPb(userSchema.State),
|
||||
Revision: userSchema.Revision,
|
||||
Schema: s,
|
||||
PossibleAuthenticators: authenticatorTypesToPb(userSchema.PossibleAuthenticators),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func authenticatorTypesToPb(authenticators []domain.AuthenticatorType) []schema.AuthenticatorType {
|
||||
authTypes := make([]schema.AuthenticatorType, len(authenticators))
|
||||
for i, authenticator := range authenticators {
|
||||
authTypes[i] = authenticatorTypeToPb(authenticator)
|
||||
}
|
||||
return authTypes
|
||||
}
|
||||
|
||||
func authenticatorTypeToPb(authenticator domain.AuthenticatorType) schema.AuthenticatorType {
|
||||
switch authenticator {
|
||||
case domain.AuthenticatorTypeUsername:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME
|
||||
case domain.AuthenticatorTypePassword:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_PASSWORD
|
||||
case domain.AuthenticatorTypeWebAuthN:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_WEBAUTHN
|
||||
case domain.AuthenticatorTypeTOTP:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_TOTP
|
||||
case domain.AuthenticatorTypeOTPEmail:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_EMAIL
|
||||
case domain.AuthenticatorTypeOTPSMS:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_SMS
|
||||
case domain.AuthenticatorTypeAuthenticationKey:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_AUTHENTICATION_KEY
|
||||
case domain.AuthenticatorTypeIdentityProvider:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_IDENTITY_PROVIDER
|
||||
case domain.AuthenticatorTypeUnspecified:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED
|
||||
default:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaStateToPb(state domain.UserSchemaState) schema.State {
|
||||
switch state {
|
||||
case domain.UserSchemaStateActive:
|
||||
return schema.State_STATE_ACTIVE
|
||||
case domain.UserSchemaStateInactive:
|
||||
return schema.State_STATE_INACTIVE
|
||||
case domain.UserSchemaStateUnspecified,
|
||||
domain.UserSchemaStateDeleted:
|
||||
return schema.State_STATE_UNSPECIFIED
|
||||
default:
|
||||
return schema.State_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func listUserSchemaToQuery(req *schema.ListUserSchemasRequest) (*query.UserSchemaSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
||||
queries, err := userSchemaQueriesToQuery(req.Queries, 0) // start at level 0
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.UserSchemaSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: userSchemaFieldNameToSortingColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userSchemaFieldNameToSortingColumn(column schema.FieldName) query.Column {
|
||||
switch column {
|
||||
case schema.FieldName_FIELD_NAME_TYPE:
|
||||
return query.UserSchemaTypeCol
|
||||
case schema.FieldName_FIELD_NAME_STATE:
|
||||
return query.UserSchemaStateCol
|
||||
case schema.FieldName_FIELD_NAME_REVISION:
|
||||
return query.UserSchemaRevisionCol
|
||||
case schema.FieldName_FIELD_NAME_CHANGE_DATE:
|
||||
return query.UserSchemaChangeDateCol
|
||||
case schema.FieldName_FIELD_NAME_UNSPECIFIED:
|
||||
return query.UserSchemaIDCol
|
||||
default:
|
||||
return query.UserSchemaIDCol
|
||||
}
|
||||
}
|
||||
|
||||
func checkUserSchemaEnabled(ctx context.Context) error {
|
||||
if authz.GetInstance(ctx).Features().UserSchema {
|
||||
return nil
|
||||
@@ -148,3 +301,86 @@ func authenticatorTypeToDomain(authenticator schema.AuthenticatorType) domain.Au
|
||||
return domain.AuthenticatorTypeUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaStateToDomain(state schema.State) domain.UserSchemaState {
|
||||
switch state {
|
||||
case schema.State_STATE_ACTIVE:
|
||||
return domain.UserSchemaStateActive
|
||||
case schema.State_STATE_INACTIVE:
|
||||
return domain.UserSchemaStateInactive
|
||||
case schema.State_STATE_UNSPECIFIED:
|
||||
return domain.UserSchemaStateUnspecified
|
||||
default:
|
||||
return domain.UserSchemaStateUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaQueriesToQuery(queries []*schema.SearchQuery, level uint8) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = userSchemaQueryToQuery(query, level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func userSchemaQueryToQuery(query *schema.SearchQuery, level uint8) (query.SearchQuery, error) {
|
||||
if level > 20 {
|
||||
// can't go deeper than 20 levels of nesting.
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "SCHEMA-zsQ97", "Errors.Query.TooManyNestingLevels")
|
||||
}
|
||||
switch q := query.Query.(type) {
|
||||
case *schema.SearchQuery_StateQuery:
|
||||
return stateQueryToQuery(q.StateQuery)
|
||||
case *schema.SearchQuery_TypeQuery:
|
||||
return typeQueryToQuery(q.TypeQuery)
|
||||
case *schema.SearchQuery_IdQuery:
|
||||
return idQueryToQuery(q.IdQuery)
|
||||
case *schema.SearchQuery_OrQuery:
|
||||
return orQueryToQuery(q.OrQuery, level)
|
||||
case *schema.SearchQuery_AndQuery:
|
||||
return andQueryToQuery(q.AndQuery, level)
|
||||
case *schema.SearchQuery_NotQuery:
|
||||
return notQueryToQuery(q.NotQuery, level)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "SCHEMA-vR9nC", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func stateQueryToQuery(q *schema.StateQuery) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaStateSearchQuery(userSchemaStateToDomain(q.GetState()))
|
||||
}
|
||||
|
||||
func typeQueryToQuery(q *schema.TypeQuery) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaTypeSearchQuery(q.GetType(), object.TextMethodToQuery(q.GetMethod()))
|
||||
}
|
||||
|
||||
func idQueryToQuery(q *schema.IDQuery) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaIDSearchQuery(q.GetId(), object.TextMethodToQuery(q.GetMethod()))
|
||||
}
|
||||
|
||||
func orQueryToQuery(q *schema.OrQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := userSchemaQueriesToQuery(q.GetQueries(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserOrSearchQuery(mappedQueries)
|
||||
}
|
||||
|
||||
func andQueryToQuery(q *schema.AndQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := userSchemaQueriesToQuery(q.GetQueries(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserAndSearchQuery(mappedQueries)
|
||||
}
|
||||
|
||||
func notQueryToQuery(q *schema.NotQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQuery, err := userSchemaQueryToQuery(q.GetQuery(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserNotSearchQuery(mappedQuery)
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ import (
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
|
||||
@@ -810,3 +811,294 @@ func TestServer_DeleteUserSchema(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_GetUserSchemaByID(t *testing.T) {
|
||||
userSchema := new(structpb.Struct)
|
||||
err := userSchema.UnmarshalJSON([]byte(`{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}`))
|
||||
require.NoError(t, err)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.GetUserSchemaByIDRequest
|
||||
prepare func(request *schema.GetUserSchemaByIDRequest, resp *schema.GetUserSchemaByIDResponse) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.GetUserSchemaByIDResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission",
|
||||
args: args{
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.GetUserSchemaByIDRequest{},
|
||||
prepare: func(request *schema.GetUserSchemaByIDRequest, resp *schema.GetUserSchemaByIDResponse) error {
|
||||
schemaType := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||
createResp := Tester.CreateUserSchemaWithType(CTX, t, schemaType)
|
||||
request.Id = createResp.GetId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.GetUserSchemaByIDRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "get, ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.GetUserSchemaByIDRequest{},
|
||||
prepare: func(request *schema.GetUserSchemaByIDRequest, resp *schema.GetUserSchemaByIDResponse) error {
|
||||
schemaType := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||
createResp := Tester.CreateUserSchemaWithType(CTX, t, schemaType)
|
||||
request.Id = createResp.GetId()
|
||||
|
||||
resp.Schema.Id = createResp.GetId()
|
||||
resp.Schema.Type = schemaType
|
||||
resp.Schema.Details = &object.Details{
|
||||
Sequence: createResp.GetDetails().GetSequence(),
|
||||
ChangeDate: createResp.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: createResp.GetDetails().GetResourceOwner(),
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.GetUserSchemaByIDResponse{
|
||||
Schema: &schema.UserSchema{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Schema: userSchema,
|
||||
PossibleAuthenticators: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureFeatureEnabled(t)
|
||||
if tt.args.prepare != nil {
|
||||
err := tt.args.prepare(tt.args.req, tt.want)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
retryDuration := 5 * time.Second
|
||||
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
|
||||
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||
got, err := Client.GetUserSchemaByID(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(ttt, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(ttt, err)
|
||||
|
||||
integration.AssertDetails(t, tt.want.GetSchema(), got.GetSchema())
|
||||
grpc.AllFieldsEqual(t, tt.want.ProtoReflect(), got.ProtoReflect(), grpc.CustomMappers)
|
||||
|
||||
}, retryDuration, time.Millisecond*100, "timeout waiting for expected user schema result")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_ListUserSchemas(t *testing.T) {
|
||||
userSchema := new(structpb.Struct)
|
||||
err := userSchema.UnmarshalJSON([]byte(`{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}`))
|
||||
require.NoError(t, err)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.ListUserSchemasRequest
|
||||
prepare func(request *schema.ListUserSchemasRequest, resp *schema.ListUserSchemasResponse) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.ListUserSchemasResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission",
|
||||
args: args{
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.ListUserSchemasRequest{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "not found, error",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.ListUserSchemasRequest{
|
||||
Queries: []*schema.SearchQuery{
|
||||
{
|
||||
Query: &schema.SearchQuery_IdQuery{
|
||||
IdQuery: &schema.IDQuery{
|
||||
Id: "notexisting",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.ListUserSchemasResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
},
|
||||
Result: []*schema.UserSchema{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single (id), ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.ListUserSchemasRequest{},
|
||||
prepare: func(request *schema.ListUserSchemasRequest, resp *schema.ListUserSchemasResponse) error {
|
||||
schemaType := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||
createResp := Tester.CreateUserSchemaWithType(CTX, t, schemaType)
|
||||
request.Queries = []*schema.SearchQuery{
|
||||
{
|
||||
Query: &schema.SearchQuery_IdQuery{
|
||||
IdQuery: &schema.IDQuery{
|
||||
Id: createResp.GetId(),
|
||||
Method: object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp.Result[0].Id = createResp.GetId()
|
||||
resp.Result[0].Type = schemaType
|
||||
resp.Result[0].Details = &object.Details{
|
||||
Sequence: createResp.GetDetails().GetSequence(),
|
||||
ChangeDate: createResp.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: createResp.GetDetails().GetResourceOwner(),
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.ListUserSchemasResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
},
|
||||
Result: []*schema.UserSchema{
|
||||
{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Schema: userSchema,
|
||||
PossibleAuthenticators: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple (type), ok",
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &schema.ListUserSchemasRequest{},
|
||||
prepare: func(request *schema.ListUserSchemasRequest, resp *schema.ListUserSchemasResponse) error {
|
||||
schemaType := fmt.Sprint(time.Now().UnixNano())
|
||||
schemaType1 := schemaType + "_1"
|
||||
schemaType2 := schemaType + "_2"
|
||||
createResp := Tester.CreateUserSchemaWithType(CTX, t, schemaType1)
|
||||
createResp2 := Tester.CreateUserSchemaWithType(CTX, t, schemaType2)
|
||||
|
||||
request.SortingColumn = schema.FieldName_FIELD_NAME_TYPE
|
||||
request.Query = &object.ListQuery{Asc: true}
|
||||
request.Queries = []*schema.SearchQuery{
|
||||
{
|
||||
Query: &schema.SearchQuery_TypeQuery{
|
||||
TypeQuery: &schema.TypeQuery{
|
||||
Type: schemaType,
|
||||
Method: object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp.Result[0].Id = createResp.GetId()
|
||||
resp.Result[0].Type = schemaType1
|
||||
resp.Result[0].Details = &object.Details{
|
||||
Sequence: createResp.GetDetails().GetSequence(),
|
||||
ChangeDate: createResp.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: createResp.GetDetails().GetResourceOwner(),
|
||||
}
|
||||
resp.Result[1].Id = createResp2.GetId()
|
||||
resp.Result[1].Type = schemaType2
|
||||
resp.Result[1].Details = &object.Details{
|
||||
Sequence: createResp2.GetDetails().GetSequence(),
|
||||
ChangeDate: createResp2.GetDetails().GetChangeDate(),
|
||||
ResourceOwner: createResp2.GetDetails().GetResourceOwner(),
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.ListUserSchemasResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 2,
|
||||
},
|
||||
Result: []*schema.UserSchema{
|
||||
{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Schema: userSchema,
|
||||
PossibleAuthenticators: nil,
|
||||
},
|
||||
{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Schema: userSchema,
|
||||
PossibleAuthenticators: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureFeatureEnabled(t)
|
||||
if tt.args.prepare != nil {
|
||||
err := tt.args.prepare(tt.args.req, tt.want)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
retryDuration := 20 * time.Second
|
||||
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
|
||||
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||
got, err := Client.ListUserSchemas(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(ttt, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(ttt, err)
|
||||
|
||||
// always first check length, otherwise its failed anyway
|
||||
assert.Len(ttt, got.Result, len(tt.want.Result))
|
||||
for i := range tt.want.Result {
|
||||
//
|
||||
grpc.AllFieldsEqual(t, tt.want.Result[i].ProtoReflect(), got.Result[i].ProtoReflect(), grpc.CustomMappers)
|
||||
}
|
||||
integration.AssertListDetails(t, tt.want, got)
|
||||
}, retryDuration, time.Millisecond*100, "timeout waiting for expected user schema result")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -218,7 +218,7 @@ func userQueriesToQuery(queries []*user.SearchQuery, level uint8) (_ []query.Sea
|
||||
func userQueryToQuery(query *user.SearchQuery, level uint8) (query.SearchQuery, error) {
|
||||
if level > 20 {
|
||||
// can't go deeper than 20 levels of nesting.
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "USER-zsQ97", "Errors.User.TooManyNestingLevels")
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "USER-zsQ97", "Errors.Query.TooManyNestingLevels")
|
||||
}
|
||||
switch q := query.Query.(type) {
|
||||
case *user.SearchQuery_UserNameQuery:
|
||||
|
Reference in New Issue
Block a user