feat(api): move organization settings endpoints to v2 (#10910)

# Which Problems Are Solved

As part of our efforts to simplify the structure and versions of our
APIs, were moving all existing v2beta endpoints to v2 and deprecate
them. They will be removed in Zitadel V5.

# How the Problems Are Solved

- This PR adds the organization settings endpoints to the settings
service v2. This was split from #10909, since that PR targets v4.x and
the corresponding feature is not yet available in v4.x, but only v5.
- The comments and have been improved and, where not already done, moved
from swagger annotations to proto.

# Additional Changes

None

# Additional Context

- relates to #10909 
- relates to #10772
This commit is contained in:
Livio Spring
2025-10-17 11:21:01 +02:00
committed by GitHub
parent dbf877e028
commit 8d5f92f80a
9 changed files with 903 additions and 3 deletions
@@ -16,6 +16,7 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/filter/v2"
"github.com/zitadel/zitadel/pkg/grpc/idp"
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
object_pb "github.com/zitadel/zitadel/pkg/grpc/object/v2"
@@ -427,3 +428,267 @@ func TestServer_GetHostedLoginTranslation(t *testing.T) {
})
}
}
func TestServer_ListOrganizationSettings(t *testing.T) {
instance := integration.NewInstance(CTX)
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
dep func(*settings.ListOrganizationSettingsRequest, *settings.ListOrganizationSettingsResponse)
req *settings.ListOrganizationSettingsRequest
}
tests := []struct {
name string
args args
want *settings.ListOrganizationSettingsResponse
wantErr bool
}{
{
name: "list by id, unauthenticated",
args: args{
ctx: CTX,
dep: func(request *settings.ListOrganizationSettingsRequest, response *settings.ListOrganizationSettingsResponse) {
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp.GetOrganizationId(), true)
request.Filters[0].Filter = &settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter{
InOrganizationIdsFilter: &filter.InIDsFilter{
Ids: []string{orgResp.GetOrganizationId()},
},
}
},
req: &settings.ListOrganizationSettingsRequest{
Filters: []*settings.OrganizationSettingsSearchFilter{{}},
},
},
wantErr: true,
},
{
name: "list by id, no permission",
args: args{
ctx: instance.WithAuthorizationToken(CTX, integration.UserTypeNoPermission),
dep: func(request *settings.ListOrganizationSettingsRequest, response *settings.ListOrganizationSettingsResponse) {
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp.GetOrganizationId(), true)
request.Filters[0].Filter = &settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter{
InOrganizationIdsFilter: &filter.InIDsFilter{
Ids: []string{orgResp.GetOrganizationId()},
},
}
},
req: &settings.ListOrganizationSettingsRequest{
Filters: []*settings.OrganizationSettingsSearchFilter{{}},
},
},
want: &settings.ListOrganizationSettingsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
OrganizationSettings: []*settings.OrganizationSettings{},
},
},
{
name: "list by id, missing permission",
args: args{
ctx: instance.WithAuthorizationToken(CTX, integration.UserTypeOrgOwner),
dep: func(request *settings.ListOrganizationSettingsRequest, response *settings.ListOrganizationSettingsResponse) {
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp.GetOrganizationId(), true)
request.Filters[0].Filter = &settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter{
InOrganizationIdsFilter: &filter.InIDsFilter{
Ids: []string{orgResp.GetOrganizationId()},
},
}
},
req: &settings.ListOrganizationSettingsRequest{
Filters: []*settings.OrganizationSettingsSearchFilter{{}},
},
},
want: &settings.ListOrganizationSettingsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
OrganizationSettings: []*settings.OrganizationSettings{},
},
},
{
name: "list, not found",
args: args{
ctx: iamOwnerCtx,
req: &settings.ListOrganizationSettingsRequest{
Filters: []*settings.OrganizationSettingsSearchFilter{{
Filter: &settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter{
InOrganizationIdsFilter: &filter.InIDsFilter{
Ids: []string{"notexisting"},
},
},
}},
},
},
want: &settings.ListOrganizationSettingsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 0,
AppliedLimit: 100,
},
OrganizationSettings: []*settings.OrganizationSettings{},
},
},
{
name: "list single id",
args: args{
ctx: iamOwnerCtx,
dep: func(request *settings.ListOrganizationSettingsRequest, response *settings.ListOrganizationSettingsResponse) {
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
settingsResp := instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp.GetOrganizationId(), true)
request.Filters[0].Filter = &settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter{
InOrganizationIdsFilter: &filter.InIDsFilter{
Ids: []string{orgResp.GetOrganizationId()},
},
}
response.OrganizationSettings[0] = &settings.OrganizationSettings{
OrganizationId: orgResp.GetOrganizationId(),
CreationDate: settingsResp.GetSetDate(),
ChangeDate: settingsResp.GetSetDate(),
OrganizationScopedUsernames: true,
}
},
req: &settings.ListOrganizationSettingsRequest{
Filters: []*settings.OrganizationSettingsSearchFilter{{}},
},
},
want: &settings.ListOrganizationSettingsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
OrganizationSettings: []*settings.OrganizationSettings{{}},
},
},
{
name: "list multiple id",
args: args{
ctx: iamOwnerCtx,
dep: func(request *settings.ListOrganizationSettingsRequest, response *settings.ListOrganizationSettingsResponse) {
orgResp1 := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
settingsResp1 := instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp1.GetOrganizationId(), true)
orgResp2 := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
settingsResp2 := instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp2.GetOrganizationId(), true)
orgResp3 := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
settingsResp3 := instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp3.GetOrganizationId(), true)
request.Filters[0].Filter = &settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter{
InOrganizationIdsFilter: &filter.InIDsFilter{
Ids: []string{orgResp1.GetOrganizationId(), orgResp2.GetOrganizationId(), orgResp3.GetOrganizationId()},
},
}
response.OrganizationSettings[2] = &settings.OrganizationSettings{
OrganizationId: orgResp1.GetOrganizationId(),
CreationDate: settingsResp1.GetSetDate(),
ChangeDate: settingsResp1.GetSetDate(),
OrganizationScopedUsernames: true,
}
response.OrganizationSettings[1] = &settings.OrganizationSettings{
OrganizationId: orgResp2.GetOrganizationId(),
CreationDate: settingsResp2.GetSetDate(),
ChangeDate: settingsResp2.GetSetDate(),
OrganizationScopedUsernames: true,
}
response.OrganizationSettings[0] = &settings.OrganizationSettings{
OrganizationId: orgResp3.GetOrganizationId(),
CreationDate: settingsResp3.GetSetDate(),
ChangeDate: settingsResp3.GetSetDate(),
OrganizationScopedUsernames: true,
}
},
req: &settings.ListOrganizationSettingsRequest{
Filters: []*settings.OrganizationSettingsSearchFilter{{}},
},
},
want: &settings.ListOrganizationSettingsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 3,
AppliedLimit: 100,
},
OrganizationSettings: []*settings.OrganizationSettings{{}, {}, {}},
},
},
{
name: "list multiple id, only org scoped usernames",
args: args{
ctx: iamOwnerCtx,
dep: func(request *settings.ListOrganizationSettingsRequest, response *settings.ListOrganizationSettingsResponse) {
orgResp1 := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp1.GetOrganizationId(), false)
orgResp2 := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
settingsResp2 := instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp2.GetOrganizationId(), true)
orgResp3 := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), integration.Email())
instance.SetOrganizationSettings(iamOwnerCtx, t, orgResp3.GetOrganizationId(), false)
request.Filters[0].Filter = &settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter{
InOrganizationIdsFilter: &filter.InIDsFilter{
Ids: []string{orgResp1.GetOrganizationId(), orgResp2.GetOrganizationId(), orgResp3.GetOrganizationId()},
},
}
request.Filters[1].Filter = &settings.OrganizationSettingsSearchFilter_OrganizationScopedUsernamesFilter{
OrganizationScopedUsernamesFilter: &settings.OrganizationScopedUsernamesFilter{
OrganizationScopedUsernames: true,
},
}
response.OrganizationSettings[0] = &settings.OrganizationSettings{
OrganizationId: orgResp2.GetOrganizationId(),
CreationDate: settingsResp2.GetSetDate(),
ChangeDate: settingsResp2.GetSetDate(),
OrganizationScopedUsernames: true,
}
},
req: &settings.ListOrganizationSettingsRequest{
Filters: []*settings.OrganizationSettingsSearchFilter{{}, {}},
},
},
want: &settings.ListOrganizationSettingsResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
OrganizationSettings: []*settings.OrganizationSettings{{}},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.dep != nil {
tt.args.dep(tt.args.req, tt.want)
}
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(iamOwnerCtx, time.Minute)
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
got, listErr := instance.Client.SettingsV2.ListOrganizationSettings(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(ttt, listErr)
return
}
require.NoError(ttt, listErr)
// always first check length, otherwise its failed anyway
if assert.Len(ttt, got.OrganizationSettings, len(tt.want.OrganizationSettings)) {
for i := range tt.want.OrganizationSettings {
assert.EqualExportedValues(ttt, tt.want.OrganizationSettings[i], got.OrganizationSettings[i])
}
}
assertPaginationResponse(ttt, tt.want.Pagination, got.Pagination)
}, retryDuration, tick, "timeout waiting for expected execution result")
})
}
}
func assertPaginationResponse(t *assert.CollectT, expected *filter.PaginationResponse, actual *filter.PaginationResponse) {
assert.Equal(t, expected.AppliedLimit, actual.AppliedLimit)
assert.Equal(t, expected.TotalResult, actual.TotalResult)
}
@@ -8,7 +8,9 @@ import (
"encoding/hex"
"fmt"
"testing"
"time"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
@@ -189,3 +191,279 @@ func TestSetHostedLoginTranslation(t *testing.T) {
})
}
}
func TestServer_SetOrganizationSettings(t *testing.T) {
instance := integration.NewInstance(CTX)
iamOwnerCTX := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
req *settings.SetOrganizationSettingsRequest
}
type want struct {
set bool
setDate bool
}
tests := []struct {
name string
prepare func(req *settings.SetOrganizationSettingsRequest)
args args
want want
wantErr bool
}{
{
name: "permission error",
args: args{
ctx: instance.WithAuthorizationToken(CTX, integration.UserTypeOrgOwner),
req: &settings.SetOrganizationSettingsRequest{
OrganizationId: Instance.DefaultOrg.GetId(),
OrganizationScopedUsernames: gu.Ptr(true),
},
},
wantErr: true,
},
{
name: "org not provided",
args: args{
ctx: iamOwnerCTX,
req: &settings.SetOrganizationSettingsRequest{
OrganizationId: "",
OrganizationScopedUsernames: gu.Ptr(true),
},
},
wantErr: true,
},
{
name: "org not existing",
args: args{
ctx: iamOwnerCTX,
req: &settings.SetOrganizationSettingsRequest{
OrganizationId: "notexisting",
OrganizationScopedUsernames: gu.Ptr(true),
},
},
wantErr: true,
},
{
name: "success no changes",
prepare: func(req *settings.SetOrganizationSettingsRequest) {
orgResp := instance.CreateOrganization(iamOwnerCTX, integration.OrganizationName(), integration.Email())
req.OrganizationId = orgResp.GetOrganizationId()
},
args: args{
ctx: iamOwnerCTX,
req: &settings.SetOrganizationSettingsRequest{},
},
want: want{
set: false,
setDate: true,
},
},
{
name: "success user uniqueness",
prepare: func(req *settings.SetOrganizationSettingsRequest) {
orgResp := instance.CreateOrganization(iamOwnerCTX, integration.OrganizationName(), integration.Email())
req.OrganizationId = orgResp.GetOrganizationId()
},
args: args{
ctx: iamOwnerCTX,
req: &settings.SetOrganizationSettingsRequest{
OrganizationScopedUsernames: gu.Ptr(true),
},
},
want: want{
set: true,
setDate: true,
},
},
{
name: "success no change",
prepare: func(req *settings.SetOrganizationSettingsRequest) {
orgResp := instance.CreateOrganization(iamOwnerCTX, integration.OrganizationName(), integration.Email())
req.OrganizationId = orgResp.GetOrganizationId()
},
args: args{
ctx: iamOwnerCTX,
req: &settings.SetOrganizationSettingsRequest{
OrganizationScopedUsernames: gu.Ptr(false),
},
},
want: want{
set: false,
setDate: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
creationDate := time.Now().UTC()
if tt.prepare != nil {
tt.prepare(tt.args.req)
}
got, err := instance.Client.SettingsV2.SetOrganizationSettings(tt.args.ctx, tt.args.req)
if tt.wantErr {
assert.Error(t, err)
return
}
setDate := time.Time{}
if tt.want.set {
setDate = time.Now().UTC()
}
assert.NoError(t, err)
assertOrganizationSettingsResponse(t, creationDate, setDate, tt.want.setDate, got)
})
}
}
func assertOrganizationSettingsResponse(t *testing.T, creationDate, setDate time.Time, expectedSetDate bool, actualResp *settings.SetOrganizationSettingsResponse) {
if expectedSetDate {
if !setDate.IsZero() {
assert.WithinRange(t, actualResp.GetSetDate().AsTime(), creationDate, setDate)
} else {
assert.WithinRange(t, actualResp.GetSetDate().AsTime(), creationDate, time.Now().UTC())
}
} else {
assert.Nil(t, actualResp.SetDate)
}
}
func TestServer_DeleteOrganizationSettings(t *testing.T) {
instance := integration.NewInstance(CTX)
iamOwnerCTX := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
req *settings.DeleteOrganizationSettingsRequest
}
type want struct {
deletion bool
deletionDate bool
}
tests := []struct {
name string
prepare func(t *testing.T, req *settings.DeleteOrganizationSettingsRequest)
args args
want want
wantErr bool
}{
{
name: "permission error",
prepare: func(t *testing.T, req *settings.DeleteOrganizationSettingsRequest) {
orgResp := instance.CreateOrganization(iamOwnerCTX, integration.OrganizationName(), integration.Email())
req.OrganizationId = orgResp.GetOrganizationId()
instance.SetOrganizationSettings(iamOwnerCTX, t, orgResp.GetOrganizationId(), true)
},
args: args{
ctx: instance.WithAuthorizationToken(CTX, integration.UserTypeOrgOwner),
req: &settings.DeleteOrganizationSettingsRequest{
OrganizationId: Instance.DefaultOrg.GetId(),
},
},
wantErr: true,
},
{
name: "org not provided",
args: args{
ctx: iamOwnerCTX,
req: &settings.DeleteOrganizationSettingsRequest{
OrganizationId: "",
},
},
wantErr: true,
},
{
name: "org not existing",
args: args{
ctx: iamOwnerCTX,
req: &settings.DeleteOrganizationSettingsRequest{
OrganizationId: "notexisting",
},
},
want: want{
deletion: false,
deletionDate: false,
},
},
{
name: "success user uniqueness",
prepare: func(t *testing.T, req *settings.DeleteOrganizationSettingsRequest) {
orgResp := instance.CreateOrganization(iamOwnerCTX, integration.OrganizationName(), integration.Email())
req.OrganizationId = orgResp.GetOrganizationId()
instance.SetOrganizationSettings(iamOwnerCTX, t, orgResp.GetOrganizationId(), true)
},
args: args{
ctx: iamOwnerCTX,
req: &settings.DeleteOrganizationSettingsRequest{},
},
want: want{
deletion: true,
deletionDate: true,
},
},
{
name: "success no existing",
prepare: func(t *testing.T, req *settings.DeleteOrganizationSettingsRequest) {
orgResp := instance.CreateOrganization(iamOwnerCTX, integration.OrganizationName(), integration.Email())
req.OrganizationId = orgResp.GetOrganizationId()
},
args: args{
ctx: iamOwnerCTX,
req: &settings.DeleteOrganizationSettingsRequest{},
},
want: want{
deletion: false,
deletionDate: true,
},
},
{
name: "success already deleted",
prepare: func(t *testing.T, req *settings.DeleteOrganizationSettingsRequest) {
orgResp := instance.CreateOrganization(iamOwnerCTX, integration.OrganizationName(), integration.Email())
req.OrganizationId = orgResp.GetOrganizationId()
instance.SetOrganizationSettings(iamOwnerCTX, t, orgResp.GetOrganizationId(), true)
instance.DeleteOrganizationSettings(iamOwnerCTX, t, orgResp.GetOrganizationId())
},
args: args{
ctx: iamOwnerCTX,
req: &settings.DeleteOrganizationSettingsRequest{},
},
want: want{
deletion: false,
deletionDate: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
creationDate := time.Now().UTC()
if tt.prepare != nil {
tt.prepare(t, tt.args.req)
}
got, err := instance.Client.SettingsV2.DeleteOrganizationSettings(tt.args.ctx, tt.args.req)
if tt.wantErr {
assert.Error(t, err)
return
}
deletionDate := time.Time{}
if tt.want.deletion {
deletionDate = time.Now().UTC()
}
assert.NoError(t, err)
assertDeleteOrganizationSettingsResponse(t, creationDate, deletionDate, tt.want.deletionDate, got)
})
}
}
func assertDeleteOrganizationSettingsResponse(t *testing.T, creationDate, deletionDate time.Time, expectedDeletionDate bool, actualResp *settings.DeleteOrganizationSettingsResponse) {
if expectedDeletionDate {
if !deletionDate.IsZero() {
assert.WithinRange(t, actualResp.GetDeletionDate().AsTime(), creationDate, deletionDate)
} else {
assert.WithinRange(t, actualResp.GetDeletionDate().AsTime(), creationDate, time.Now().UTC())
}
} else {
assert.Nil(t, actualResp.DeletionDate)
}
}
+103
View File
@@ -7,10 +7,13 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors"
filter_pb "github.com/zitadel/zitadel/pkg/grpc/filter/v2"
object_pb "github.com/zitadel/zitadel/pkg/grpc/object/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2"
)
@@ -208,3 +211,103 @@ func (s *Server) GetHostedLoginTranslation(ctx context.Context, req *connect.Req
return connect.NewResponse(translation), nil
}
func (s *Server) ListOrganizationSettings(ctx context.Context, req *connect.Request[settings.ListOrganizationSettingsRequest]) (*connect.Response[settings.ListOrganizationSettingsResponse], error) {
queries, err := s.listOrganizationSettingsRequestToModel(req.Msg)
if err != nil {
return nil, err
}
resp, err := s.query.SearchOrganizationSettings(ctx, queries, s.checkPermission)
if err != nil {
return nil, err
}
return connect.NewResponse(&settings.ListOrganizationSettingsResponse{
OrganizationSettings: organizationSettingsListToPb(resp.OrganizationSettingsList),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
}), nil
}
func (s *Server) listOrganizationSettingsRequestToModel(req *settings.ListOrganizationSettingsRequest) (*query.OrganizationSettingsSearchQueries, error) {
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
if err != nil {
return nil, err
}
queries, err := organizationSettingsFiltersToQuery(req.Filters)
if err != nil {
return nil, err
}
return &query.OrganizationSettingsSearchQueries{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
SortingColumn: organizationSettingsFieldNameToSortingColumn(req.SortingColumn),
},
Queries: queries,
}, nil
}
func organizationSettingsFieldNameToSortingColumn(field *settings.OrganizationSettingsFieldName) query.Column {
if field == nil {
return query.OrganizationSettingsColumnCreationDate
}
switch *field {
case settings.OrganizationSettingsFieldName_ORGANIZATION_SETTINGS_FIELD_NAME_CREATION_DATE:
return query.OrganizationSettingsColumnCreationDate
case settings.OrganizationSettingsFieldName_ORGANIZATION_SETTINGS_FIELD_NAME_ORGANIZATION_ID:
return query.OrganizationSettingsColumnID
case settings.OrganizationSettingsFieldName_ORGANIZATION_SETTINGS_FIELD_NAME_CHANGE_DATE:
return query.OrganizationSettingsColumnChangeDate
case settings.OrganizationSettingsFieldName_ORGANIZATION_SETTINGS_FIELD_NAME_UNSPECIFIED:
return query.OrganizationSettingsColumnCreationDate
default:
return query.OrganizationSettingsColumnCreationDate
}
}
func organizationSettingsFiltersToQuery(queries []*settings.OrganizationSettingsSearchFilter) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, len(queries))
for i, qry := range queries {
q[i], err = organizationSettingsToModel(qry)
if err != nil {
return nil, err
}
}
return q, nil
}
func organizationSettingsToModel(filter *settings.OrganizationSettingsSearchFilter) (query.SearchQuery, error) {
switch q := filter.Filter.(type) {
case *settings.OrganizationSettingsSearchFilter_InOrganizationIdsFilter:
return organizationInIDsFilterToQuery(q.InOrganizationIdsFilter)
case *settings.OrganizationSettingsSearchFilter_OrganizationScopedUsernamesFilter:
return organizationScopedUsernamesFilterToQuery(q.OrganizationScopedUsernamesFilter)
default:
return nil, zerrors.ThrowInvalidArgument(nil, "SETTINGS-uvTDqZHlvS", "List.Query.Invalid")
}
}
func organizationInIDsFilterToQuery(q *filter_pb.InIDsFilter) (query.SearchQuery, error) {
return query.NewOrganizationSettingsOrganizationIDSearchQuery(q.Ids)
}
func organizationScopedUsernamesFilterToQuery(q *settings.OrganizationScopedUsernamesFilter) (query.SearchQuery, error) {
return query.NewOrganizationSettingsOrganizationScopedUsernamesSearchQuery(q.OrganizationScopedUsernames)
}
func organizationSettingsListToPb(settingsList []*query.OrganizationSettings) []*settings.OrganizationSettings {
o := make([]*settings.OrganizationSettings, len(settingsList))
for i, organizationSettings := range settingsList {
o[i] = organizationSettingsToPb(organizationSettings)
}
return o
}
func organizationSettingsToPb(organizationSettings *query.OrganizationSettings) *settings.OrganizationSettings {
return &settings.OrganizationSettings{
OrganizationId: organizationSettings.ID,
CreationDate: timestamppb.New(organizationSettings.CreationDate),
ChangeDate: timestamppb.New(organizationSettings.ChangeDate),
OrganizationScopedUsernames: organizationSettings.OrganizationScopedUsernames,
}
}
+10 -2
View File
@@ -11,6 +11,8 @@ import (
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2/settingsconnect"
@@ -19,19 +21,25 @@ import (
var _ settingsconnect.SettingsServiceHandler = (*Server)(nil)
type Server struct {
command *command.Commands
query *query.Queries
systemDefaults systemdefaults.SystemDefaults
command *command.Commands
query *query.Queries
checkPermission domain.PermissionCheck
assetsAPIDomain func(context.Context) string
}
func CreateServer(
systemDefaults systemdefaults.SystemDefaults,
command *command.Commands,
query *query.Queries,
checkPermission domain.PermissionCheck,
) *Server {
return &Server{
systemDefaults: systemDefaults,
command: command,
query: query,
checkPermission: checkPermission,
assetsAPIDomain: assets.AssetAPI(),
}
}
+29
View File
@@ -4,6 +4,7 @@ import (
"context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2"
@@ -27,3 +28,31 @@ func (s *Server) SetHostedLoginTranslation(ctx context.Context, req *connect.Req
return connect.NewResponse(res), nil
}
func (s *Server) SetOrganizationSettings(ctx context.Context, req *connect.Request[settings.SetOrganizationSettingsRequest]) (*connect.Response[settings.SetOrganizationSettingsResponse], error) {
details, err := s.command.SetOrganizationSettings(ctx, organizationSettingsToCommand(req.Msg))
if err != nil {
return nil, err
}
var setDate *timestamppb.Timestamp
if !details.EventDate.IsZero() {
setDate = timestamppb.New(details.EventDate)
}
return connect.NewResponse(&settings.SetOrganizationSettingsResponse{
SetDate: setDate,
}), nil
}
func (s *Server) DeleteOrganizationSettings(ctx context.Context, req *connect.Request[settings.DeleteOrganizationSettingsRequest]) (*connect.Response[settings.DeleteOrganizationSettingsResponse], error) {
details, err := s.command.DeleteOrganizationSettings(ctx, req.Msg.GetOrganizationId())
if err != nil {
return nil, err
}
var deletionDate *timestamppb.Timestamp
if !details.EventDate.IsZero() {
deletionDate = timestamppb.New(details.EventDate)
}
return connect.NewResponse(&settings.DeleteOrganizationSettingsResponse{
DeletionDate: deletionDate,
}), nil
}
@@ -252,3 +252,10 @@ func securitySettingsToCommand(req *settings.SetSecuritySettingsRequest) *comman
EnableImpersonation: req.GetEnableImpersonation(),
}
}
func organizationSettingsToCommand(req *settings.SetOrganizationSettingsRequest) *command.SetOrganizationSettings {
return &command.SetOrganizationSettings{
OrganizationID: req.OrganizationId,
OrganizationScopedUsernames: req.OrganizationScopedUsernames,
}
}