mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:17:32 +00:00
feat: org v2 ListOrganizations (#8411)
# Which Problems Are Solved Org v2 service does not have a ListOrganizations endpoint. # How the Problems Are Solved Implement ListOrganizations endpoint. # Additional Changes - moved descriptions in the protos to comments - corrected the RemoveNoPermissions for the ListUsers, to get the correct TotalResults # Additional Context For new typescript login
This commit is contained in:
@@ -36,7 +36,7 @@ func (s *Server) ExportData(ctx context.Context, req *admin_pb.ExportDataRequest
|
||||
}
|
||||
orgSearchQuery.Queries = []query.SearchQuery{orgIDsSearchQuery}
|
||||
}
|
||||
queriedOrgs, err := s.query.SearchOrgs(ctx, orgSearchQuery)
|
||||
queriedOrgs, err := s.query.SearchOrgs(ctx, orgSearchQuery, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -554,7 +554,7 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{orgSearch}})
|
||||
users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{orgSearch}}, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@ func (s *Server) ListOrgs(ctx context.Context, req *admin_pb.ListOrgsRequest) (*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgs, err := s.query.SearchOrgs(ctx, queries)
|
||||
orgs, err := s.query.SearchOrgs(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func (s *Server) getClaimedUserIDsOfOrgDomain(ctx context.Context, orgDomain str
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}})
|
||||
users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -220,7 +220,7 @@ func (s *Server) ListMyProjectOrgs(ctx context.Context, req *auth_pb.ListMyProje
|
||||
}
|
||||
}
|
||||
|
||||
orgs, err := s.query.SearchOrgs(ctx, queries)
|
||||
orgs, err := s.query.SearchOrgs(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -330,7 +330,7 @@ func (s *Server) getClaimedUserIDsOfOrgDomain(ctx context.Context, orgDomain, or
|
||||
}
|
||||
queries = append(queries, owner)
|
||||
}
|
||||
users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: queries})
|
||||
users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: queries}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@ func (s *Server) ListUsers(ctx context.Context, req *mgmt_pb.ListUsersRequest) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.SearchUsers(ctx, queries)
|
||||
res, err := s.query.SearchUsers(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -19,22 +19,26 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
CTX context.Context
|
||||
Tester *integration.Tester
|
||||
Client org.OrganizationServiceClient
|
||||
User *user.AddHumanUserResponse
|
||||
CTX context.Context
|
||||
OwnerCTX context.Context
|
||||
UserCTX context.Context
|
||||
Tester *integration.Tester
|
||||
Client org.OrganizationServiceClient
|
||||
User *user.AddHumanUserResponse
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(func() int {
|
||||
ctx, errCtx, cancel := integration.Contexts(5 * time.Minute)
|
||||
ctx, _, cancel := integration.Contexts(5 * time.Minute)
|
||||
defer cancel()
|
||||
|
||||
Tester = integration.NewTester(ctx)
|
||||
defer Tester.Done()
|
||||
Client = Tester.Client.OrgV2
|
||||
|
||||
CTX, _ = Tester.WithAuthorization(ctx, integration.IAMOwner), errCtx
|
||||
CTX = Tester.WithAuthorization(ctx, integration.IAMOwner)
|
||||
OwnerCTX = Tester.WithAuthorization(ctx, integration.OrgOwner)
|
||||
UserCTX = Tester.WithAuthorization(ctx, integration.Login)
|
||||
User = Tester.CreateHumanUser(CTX)
|
||||
return m.Run()
|
||||
}())
|
||||
|
132
internal/api/grpc/org/v2/query.go
Normal file
132
internal/api/grpc/org/v2/query.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/org/v2"
|
||||
)
|
||||
|
||||
func (s *Server) ListOrganizations(ctx context.Context, req *org.ListOrganizationsRequest) (*org.ListOrganizationsResponse, error) {
|
||||
queries, err := listOrgRequestToModel(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgs, err := s.query.SearchOrgs(ctx, queries, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org.ListOrganizationsResponse{
|
||||
Result: organizationsToPb(orgs.Orgs),
|
||||
Details: object.ToListDetails(orgs.SearchResponse),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func listOrgRequestToModel(req *org.ListOrganizationsRequest) (*query.OrgSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
||||
queries, err := orgQueriesToQuery(req.Queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.OrgSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
SortingColumn: fieldNameToOrganizationColumn(req.SortingColumn),
|
||||
Asc: asc,
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func orgQueriesToQuery(queries []*org.SearchQuery) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = orgQueryToQuery(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func orgQueryToQuery(orgQuery *org.SearchQuery) (query.SearchQuery, error) {
|
||||
switch q := orgQuery.Query.(type) {
|
||||
case *org.SearchQuery_DomainQuery:
|
||||
return query.NewOrgDomainSearchQuery(object.TextMethodToQuery(q.DomainQuery.Method), q.DomainQuery.Domain)
|
||||
case *org.SearchQuery_NameQuery:
|
||||
return query.NewOrgNameSearchQuery(object.TextMethodToQuery(q.NameQuery.Method), q.NameQuery.Name)
|
||||
case *org.SearchQuery_StateQuery:
|
||||
return query.NewOrgStateSearchQuery(orgStateToDomain(q.StateQuery.State))
|
||||
case *org.SearchQuery_IdQuery:
|
||||
return query.NewOrgIDSearchQuery(q.IdQuery.Id)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-vR9nC", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func orgStateToPb(state domain.OrgState) org.OrganizationState {
|
||||
switch state {
|
||||
case domain.OrgStateActive:
|
||||
return org.OrganizationState_ORGANIZATION_STATE_ACTIVE
|
||||
case domain.OrgStateInactive:
|
||||
return org.OrganizationState_ORGANIZATION_STATE_INACTIVE
|
||||
case domain.OrgStateRemoved:
|
||||
return org.OrganizationState_ORGANIZATION_STATE_REMOVED
|
||||
case domain.OrgStateUnspecified:
|
||||
fallthrough
|
||||
default:
|
||||
return org.OrganizationState_ORGANIZATION_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func orgStateToDomain(state org.OrganizationState) domain.OrgState {
|
||||
switch state {
|
||||
case org.OrganizationState_ORGANIZATION_STATE_ACTIVE:
|
||||
return domain.OrgStateActive
|
||||
case org.OrganizationState_ORGANIZATION_STATE_INACTIVE:
|
||||
return domain.OrgStateInactive
|
||||
case org.OrganizationState_ORGANIZATION_STATE_REMOVED:
|
||||
return domain.OrgStateRemoved
|
||||
case org.OrganizationState_ORGANIZATION_STATE_UNSPECIFIED:
|
||||
fallthrough
|
||||
default:
|
||||
return domain.OrgStateUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func fieldNameToOrganizationColumn(fieldName org.OrganizationFieldName) query.Column {
|
||||
switch fieldName {
|
||||
case org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME:
|
||||
return query.OrgColumnName
|
||||
case org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_UNSPECIFIED:
|
||||
return query.Column{}
|
||||
default:
|
||||
return query.Column{}
|
||||
}
|
||||
}
|
||||
|
||||
func organizationsToPb(orgs []*query.Org) []*org.Organization {
|
||||
o := make([]*org.Organization, len(orgs))
|
||||
for i, org := range orgs {
|
||||
o[i] = organizationToPb(org)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func organizationToPb(organization *query.Org) *org.Organization {
|
||||
return &org.Organization{
|
||||
Id: organization.ID,
|
||||
Name: organization.Name,
|
||||
PrimaryDomain: organization.Domain,
|
||||
Details: object.DomainToDetailsPb(&domain.ObjectDetails{
|
||||
Sequence: organization.Sequence,
|
||||
EventDate: organization.ChangeDate,
|
||||
ResourceOwner: organization.ResourceOwner,
|
||||
}),
|
||||
State: orgStateToPb(organization.State),
|
||||
}
|
||||
}
|
443
internal/api/grpc/org/v2/query_integration_test.go
Normal file
443
internal/api/grpc/org/v2/query_integration_test.go
Normal file
@@ -0,0 +1,443 @@
|
||||
//go:build integration
|
||||
|
||||
package org_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/org/v2"
|
||||
)
|
||||
|
||||
type orgAttr struct {
|
||||
ID string
|
||||
Name string
|
||||
Details *object.Details
|
||||
}
|
||||
|
||||
func TestServer_ListOrganizations(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *org.ListOrganizationsRequest
|
||||
dep func(ctx context.Context, request *org.ListOrganizationsRequest) ([]orgAttr, error)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *org.ListOrganizationsResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "list org by id, ok, multiple",
|
||||
args: args{
|
||||
CTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationIdQuery(Tester.Organisation.ID),
|
||||
},
|
||||
},
|
||||
func(ctx context.Context, request *org.ListOrganizationsRequest) ([]orgAttr, error) {
|
||||
count := 3
|
||||
orgs := make([]orgAttr, count)
|
||||
prefix := fmt.Sprintf("ListOrgs%d", time.Now().UnixNano())
|
||||
for i := 0; i < count; i++ {
|
||||
name := prefix + strconv.Itoa(i)
|
||||
orgResp := Tester.CreateOrganization(ctx, name, fmt.Sprintf("%d@mouse.com", time.Now().UnixNano()))
|
||||
orgs[i] = orgAttr{
|
||||
ID: orgResp.GetOrganizationId(),
|
||||
Name: name,
|
||||
Details: orgResp.GetDetails(),
|
||||
}
|
||||
}
|
||||
request.Queries = []*org.SearchQuery{
|
||||
OrganizationNamePrefixQuery(prefix),
|
||||
}
|
||||
return orgs, nil
|
||||
},
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 3,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 0,
|
||||
Result: []*org.Organization{
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
},
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
},
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org by id, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationIdQuery(Tester.Organisation.ID),
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 0,
|
||||
Result: []*org.Organization{
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
Name: Tester.Organisation.Name,
|
||||
Details: &object.Details{
|
||||
Sequence: Tester.Organisation.Sequence,
|
||||
ChangeDate: timestamppb.New(Tester.Organisation.ChangeDate),
|
||||
ResourceOwner: Tester.Organisation.ResourceOwner,
|
||||
},
|
||||
Id: Tester.Organisation.ID,
|
||||
PrimaryDomain: Tester.Organisation.Domain,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org by name, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationNameQuery(Tester.Organisation.Name),
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 0,
|
||||
Result: []*org.Organization{
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
Name: Tester.Organisation.Name,
|
||||
Details: &object.Details{
|
||||
Sequence: Tester.Organisation.Sequence,
|
||||
ChangeDate: timestamppb.New(Tester.Organisation.ChangeDate),
|
||||
ResourceOwner: Tester.Organisation.ResourceOwner,
|
||||
},
|
||||
Id: Tester.Organisation.ID,
|
||||
PrimaryDomain: Tester.Organisation.Domain,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org by domain, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationDomainQuery(Tester.Organisation.Domain),
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 0,
|
||||
Result: []*org.Organization{
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
Name: Tester.Organisation.Name,
|
||||
Details: &object.Details{
|
||||
Sequence: Tester.Organisation.Sequence,
|
||||
ChangeDate: timestamppb.New(Tester.Organisation.ChangeDate),
|
||||
ResourceOwner: Tester.Organisation.ResourceOwner,
|
||||
},
|
||||
Id: Tester.Organisation.ID,
|
||||
PrimaryDomain: Tester.Organisation.Domain,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org by inactive state, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{},
|
||||
},
|
||||
func(ctx context.Context, request *org.ListOrganizationsRequest) ([]orgAttr, error) {
|
||||
name := gofakeit.Name()
|
||||
orgResp := Tester.CreateOrganization(ctx, name, gofakeit.Email())
|
||||
deactivateOrgResp := Tester.DeactivateOrganization(ctx, orgResp.GetOrganizationId())
|
||||
request.Queries = []*org.SearchQuery{
|
||||
OrganizationIdQuery(orgResp.GetOrganizationId()),
|
||||
OrganizationStateQuery(org.OrganizationState_ORGANIZATION_STATE_INACTIVE),
|
||||
}
|
||||
return []orgAttr{{
|
||||
ID: orgResp.GetOrganizationId(),
|
||||
Name: name,
|
||||
Details: &object.Details{
|
||||
ResourceOwner: deactivateOrgResp.GetDetails().GetResourceOwner(),
|
||||
Sequence: deactivateOrgResp.GetDetails().GetSequence(),
|
||||
ChangeDate: deactivateOrgResp.GetDetails().GetChangeDate(),
|
||||
},
|
||||
}}, nil
|
||||
},
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 0,
|
||||
Result: []*org.Organization{
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_INACTIVE,
|
||||
Details: &object.Details{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org by domain, ok, sorted",
|
||||
args: args{
|
||||
CTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationDomainQuery(Tester.Organisation.Domain),
|
||||
},
|
||||
SortingColumn: org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 1,
|
||||
Result: []*org.Organization{
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
Name: Tester.Organisation.Name,
|
||||
Details: &object.Details{
|
||||
Sequence: Tester.Organisation.Sequence,
|
||||
ChangeDate: timestamppb.New(Tester.Organisation.ChangeDate),
|
||||
ResourceOwner: Tester.Organisation.ResourceOwner,
|
||||
},
|
||||
Id: Tester.Organisation.ID,
|
||||
PrimaryDomain: Tester.Organisation.Domain,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org, no result",
|
||||
args: args{
|
||||
CTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationDomainQuery("notexisting"),
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 0,
|
||||
Result: []*org.Organization{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org, no login",
|
||||
args: args{
|
||||
context.Background(),
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationDomainQuery("nopermission"),
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "list org, no permission",
|
||||
args: args{
|
||||
UserCTX,
|
||||
&org.ListOrganizationsRequest{},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 1,
|
||||
Result: []*org.Organization{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org, no permission org owner",
|
||||
args: args{
|
||||
OwnerCTX,
|
||||
&org.ListOrganizationsRequest{
|
||||
Queries: []*org.SearchQuery{
|
||||
OrganizationDomainQuery("nopermission"),
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 1,
|
||||
Result: []*org.Organization{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list org, org owner",
|
||||
args: args{
|
||||
OwnerCTX,
|
||||
&org.ListOrganizationsRequest{},
|
||||
nil,
|
||||
},
|
||||
want: &org.ListOrganizationsResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
SortingColumn: 1,
|
||||
Result: []*org.Organization{
|
||||
{
|
||||
State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE,
|
||||
Name: Tester.Organisation.Name,
|
||||
Details: &object.Details{
|
||||
Sequence: Tester.Organisation.Sequence,
|
||||
ChangeDate: timestamppb.New(Tester.Organisation.ChangeDate),
|
||||
ResourceOwner: Tester.Organisation.ResourceOwner,
|
||||
},
|
||||
Id: Tester.Organisation.ID,
|
||||
PrimaryDomain: Tester.Organisation.Domain,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.dep != nil {
|
||||
orgs, err := tt.args.dep(tt.args.ctx, tt.args.req)
|
||||
require.NoError(t, err)
|
||||
if len(orgs) > 0 {
|
||||
for i, org := range orgs {
|
||||
tt.want.Result[i].Name = org.Name
|
||||
tt.want.Result[i].Id = org.ID
|
||||
tt.want.Result[i].Details = org.Details
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retryDuration := time.Minute
|
||||
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||
got, listErr := Client.ListOrganizations(tt.args.ctx, tt.args.req)
|
||||
assertErr := assert.NoError
|
||||
if tt.wantErr {
|
||||
assertErr = assert.Error
|
||||
}
|
||||
assertErr(ttt, listErr)
|
||||
if listErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// totalResult is unrelated to the tests here so gets carried over, can vary from the count of results due to permissions
|
||||
tt.want.Details.TotalResult = got.Details.TotalResult
|
||||
// always first check length, otherwise its failed anyway
|
||||
assert.Len(ttt, got.Result, len(tt.want.Result))
|
||||
|
||||
for i := range tt.want.Result {
|
||||
// domain from result, as it is generated though the create
|
||||
tt.want.Result[i].PrimaryDomain = got.Result[i].PrimaryDomain
|
||||
// sequence from result, as it can be with different sequence from create
|
||||
tt.want.Result[i].Details.Sequence = got.Result[i].Details.Sequence
|
||||
}
|
||||
|
||||
for i := range tt.want.Result {
|
||||
assert.Contains(ttt, got.Result, tt.want.Result[i])
|
||||
}
|
||||
integration.AssertListDetails(t, tt.want, got)
|
||||
}, retryDuration, time.Millisecond*100, "timeout waiting for expected user result")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func OrganizationIdQuery(resourceowner string) *org.SearchQuery {
|
||||
return &org.SearchQuery{Query: &org.SearchQuery_IdQuery{
|
||||
IdQuery: &org.OrganizationIDQuery{
|
||||
Id: resourceowner,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
func OrganizationNameQuery(name string) *org.SearchQuery {
|
||||
return &org.SearchQuery{Query: &org.SearchQuery_NameQuery{
|
||||
NameQuery: &org.OrganizationNameQuery{
|
||||
Name: name,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
func OrganizationNamePrefixQuery(name string) *org.SearchQuery {
|
||||
return &org.SearchQuery{Query: &org.SearchQuery_NameQuery{
|
||||
NameQuery: &org.OrganizationNameQuery{
|
||||
Name: name,
|
||||
Method: object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
func OrganizationDomainQuery(domain string) *org.SearchQuery {
|
||||
return &org.SearchQuery{Query: &org.SearchQuery_DomainQuery{
|
||||
DomainQuery: &org.OrganizationDomainQuery{
|
||||
Domain: domain,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
func OrganizationStateQuery(state org.OrganizationState) *org.SearchQuery {
|
||||
return &org.SearchQuery{Query: &org.SearchQuery_StateQuery{
|
||||
StateQuery: &org.OrganizationStateQuery{
|
||||
State: state,
|
||||
},
|
||||
}}
|
||||
}
|
@@ -39,11 +39,10 @@ func (s *Server) ListUsers(ctx context.Context, req *user.ListUsersRequest) (*us
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.SearchUsers(ctx, queries)
|
||||
res, err := s.query.SearchUsers(ctx, queries, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.RemoveNoPermission(ctx, s.checkPermission)
|
||||
return &user.ListUsersResponse{
|
||||
Result: UsersToPb(res.Users, s.assetAPIPrefix(ctx)),
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
|
@@ -13,8 +13,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
)
|
||||
@@ -914,6 +914,10 @@ func TestServer_ListUsers(t *testing.T) {
|
||||
assert.Len(ttt, tt.want.Result, len(infos))
|
||||
// always first check length, otherwise its failed anyway
|
||||
assert.Len(ttt, got.Result, len(tt.want.Result))
|
||||
|
||||
// totalResult is unrelated to the tests here so gets carried over, can vary from the count of results due to permissions
|
||||
tt.want.Details.TotalResult = got.Details.TotalResult
|
||||
|
||||
// fill in userid and username as it is generated
|
||||
for i := range infos {
|
||||
tt.want.Result[i].UserId = infos[i].UserID
|
||||
|
@@ -39,11 +39,10 @@ func (s *Server) ListUsers(ctx context.Context, req *user.ListUsersRequest) (*us
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.SearchUsers(ctx, queries)
|
||||
res, err := s.query.SearchUsers(ctx, queries, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.RemoveNoPermission(ctx, s.checkPermission)
|
||||
return &user.ListUsersResponse{
|
||||
Result: UsersToPb(res.Users, s.assetAPIPrefix(ctx)),
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
|
@@ -923,6 +923,10 @@ func TestServer_ListUsers(t *testing.T) {
|
||||
// always first check length, otherwise its failed anyway
|
||||
assert.Len(ttt, got.Result, len(tt.want.Result))
|
||||
// fill in userid and username as it is generated
|
||||
|
||||
// totalResult is unrelated to the tests here so gets carried over, can vary from the count of results due to permissions
|
||||
tt.want.Details.TotalResult = got.Details.TotalResult
|
||||
|
||||
for i := range infos {
|
||||
tt.want.Result[i].UserId = infos[i].UserID
|
||||
tt.want.Result[i].Username = infos[i].Username
|
||||
|
@@ -171,7 +171,7 @@ func (l *Login) getClaimedUserIDsOfOrgDomain(ctx context.Context, orgName string
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users, err := l.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}})
|
||||
users, err := l.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Reference in New Issue
Block a user