Merge remote-tracking branch 'origin/main' into next-rc

This commit is contained in:
Stefan Benz
2025-07-04 18:14:40 +02:00
142 changed files with 13223 additions and 2497 deletions

View File

@@ -16,6 +16,13 @@ import (
)
func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUserRequest_Human, orgId string, userName, userId *string) (*connect.Response[user.CreateUserResponse], error) {
metadataEntries := make([]*user.SetMetadataEntry, len(humanPb.Metadata))
for i, metadataEntry := range humanPb.Metadata {
metadataEntries[i] = &user.SetMetadataEntry{
Key: metadataEntry.GetKey(),
Value: metadataEntry.GetValue(),
}
}
addHumanPb := &user.AddHumanUserRequest{
Username: userName,
UserId: userId,
@@ -27,6 +34,7 @@ func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUs
Phone: humanPb.Phone,
IdpLinks: humanPb.IdpLinks,
TotpSecret: humanPb.TotpSecret,
Metadata: metadataEntries,
}
switch pwType := humanPb.GetPasswordType().(type) {
case *user.CreateUserRequest_Human_HashedPassword:

View File

@@ -10,7 +10,7 @@ import (
"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/user/v2"

View File

@@ -22,7 +22,7 @@ import (
)
func TestServer_AddKey(t *testing.T) {
resp := Instance.CreateUserTypeMachine(IamCTX)
resp := Instance.CreateUserTypeMachine(IamCTX, Instance.DefaultOrg.Id)
userId := resp.GetId()
expirationDate := timestamppb.New(time.Now().Add(time.Hour * 24))
type args struct {
@@ -108,7 +108,7 @@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
ExpirationDate: expirationDate,
},
func(request *user.AddKeyRequest) error {
resp := Instance.CreateUserTypeHuman(IamCTX)
resp := Instance.CreateUserTypeHuman(IamCTX, gofakeit.Email())
request.UserId = resp.Id
return nil
},
@@ -220,7 +220,7 @@ func TestServer_AddKey_Permission(t *testing.T) {
}
func TestServer_RemoveKey(t *testing.T) {
resp := Instance.CreateUserTypeMachine(IamCTX)
resp := Instance.CreateUserTypeMachine(IamCTX, Instance.DefaultOrg.Id)
userId := resp.GetId()
expirationDate := timestamppb.New(time.Now().Add(time.Hour * 24))
type args struct {
@@ -388,7 +388,7 @@ func TestServer_ListKeys(t *testing.T) {
})
require.NoError(t, err)
otherOrgUserId := otherOrgUser.GetId()
otherUserId := Instance.CreateUserTypeMachine(SystemCTX).GetId()
otherUserId := Instance.CreateUserTypeMachine(SystemCTX, Instance.DefaultOrg.Id).GetId()
onlySinceTestStartFilter := &user.KeysSearchFilter{Filter: &user.KeysSearchFilter_CreatedDateFilter{CreatedDateFilter: &filter.TimestampFilter{
Timestamp: timestamppb.Now(),
Method: filter.TimestampFilterMethod_TIMESTAMP_FILTER_METHOD_AFTER_OR_EQUALS,

View File

@@ -0,0 +1,403 @@
//go:build integration
package user_test
import (
"context"
"encoding/base64"
"testing"
"time"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/filter/v2"
metadata "github.com/zitadel/zitadel/pkg/grpc/metadata/v2"
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
)
func TestServer_SetUserMetadata(t *testing.T) {
iamOwnerCTX := Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
tests := []struct {
name string
ctx context.Context
dep func(request *user.SetUserMetadataRequest)
req *user.SetUserMetadataRequest
setDate bool
wantErr bool
}{
{
name: "missing permission",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeNoPermission),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(CTX, gofakeit.Email()).GetId()
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
},
wantErr: true,
},
{
name: "set user metadata",
ctx: iamOwnerCTX,
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(CTX, gofakeit.Email()).GetId()
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
},
setDate: true,
},
{
name: "set user metadata, multiple",
ctx: iamOwnerCTX,
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(CTX, gofakeit.Email()).GetId()
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{
{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))},
{Key: "key2", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value2")))},
{Key: "key3", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value3")))},
},
},
setDate: true,
},
{
name: "set user metadata on non existent user",
ctx: iamOwnerCTX,
req: &user.SetUserMetadataRequest{
UserId: "notexisting",
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
},
wantErr: true,
},
{
name: "update user metadata",
ctx: Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value2")))}},
},
setDate: true,
},
{
name: "update user metadata with same value",
ctx: Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
},
setDate: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
creationDate := time.Now().UTC()
if tt.dep != nil {
tt.dep(tt.req)
}
got, err := Client.SetUserMetadata(tt.ctx, tt.req)
changeDate := time.Now().UTC()
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assertSetUserMetadataResponse(t, creationDate, changeDate, tt.setDate, got)
})
}
}
func assertSetUserMetadataResponse(t *testing.T, creationDate, changeDate time.Time, expectedSetDat bool, actualResp *user.SetUserMetadataResponse) {
if expectedSetDat {
if !changeDate.IsZero() {
assert.WithinRange(t, actualResp.GetSetDate().AsTime(), creationDate, changeDate)
} else {
assert.WithinRange(t, actualResp.GetSetDate().AsTime(), creationDate, time.Now().UTC())
}
} else {
assert.Nil(t, actualResp.SetDate)
}
}
func TestServer_ListUserMetadata(t *testing.T) {
iamOwnerCTX := Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
dep func(context.Context, *user.ListUserMetadataRequest, *user.ListUserMetadataResponse)
req *user.ListUserMetadataRequest
}
tests := []struct {
name string
args args
want *user.ListUserMetadataResponse
wantErr bool
}{
{
name: "missing permission",
args: args{
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeNoPermission),
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
Instance.SetUserMetadata(iamOwnerCTX, userID, "key1", "value1")
},
req: &user.ListUserMetadataRequest{},
},
wantErr: true,
},
{
name: "list request",
args: args{
ctx: iamOwnerCTX,
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
metadataResp := Instance.SetUserMetadata(iamOwnerCTX, userID, "key1", "value1")
response.Metadata[0] = &metadata.Metadata{
CreationDate: metadataResp.GetSetDate(),
ChangeDate: metadataResp.GetSetDate(),
Key: "key1",
Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1"))),
}
},
req: &user.ListUserMetadataRequest{},
},
want: &user.ListUserMetadataResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
Metadata: []*metadata.Metadata{
{},
},
},
},
{
name: "list request single key",
args: args{
ctx: iamOwnerCTX,
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
key := "key1"
response.Metadata[0] = setUserMetadata(iamOwnerCTX, userID, key, "value1")
Instance.SetUserMetadata(iamOwnerCTX, userID, "key2", "value2")
Instance.SetUserMetadata(iamOwnerCTX, userID, "key3", "value3")
request.Filters[0] = &metadata.MetadataSearchFilter{
Filter: &metadata.MetadataSearchFilter_KeyFilter{KeyFilter: &metadata.MetadataKeyFilter{Key: key}},
}
},
req: &user.ListUserMetadataRequest{
Filters: []*metadata.MetadataSearchFilter{{}},
},
},
want: &user.ListUserMetadataResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
Metadata: []*metadata.Metadata{
{},
},
},
},
{
name: "list multiple keys",
args: args{
ctx: iamOwnerCTX,
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
response.Metadata[2] = setUserMetadata(iamOwnerCTX, userID, "key1", "value1")
response.Metadata[1] = setUserMetadata(iamOwnerCTX, userID, "key2", "value2")
response.Metadata[0] = setUserMetadata(iamOwnerCTX, userID, "key3", "value3")
},
req: &user.ListUserMetadataRequest{},
},
want: &user.ListUserMetadataResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 3,
AppliedLimit: 100,
},
Metadata: []*metadata.Metadata{
{}, {}, {},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.dep != nil {
tt.args.dep(tt.args.ctx, tt.args.req, tt.want)
}
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(iamOwnerCTX, time.Minute)
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
got, listErr := Instance.Client.UserV2.ListUserMetadata(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.Metadata, len(tt.want.Metadata)) {
assert.EqualExportedValues(ttt, got.Metadata, tt.want.Metadata)
}
assertPaginationResponse(ttt, tt.want.Pagination, got.Pagination)
}, retryDuration, tick, "timeout waiting for expected execution result")
})
}
}
func setUserMetadata(ctx context.Context, userID, key, value string) *metadata.Metadata {
metadataResp := Instance.SetUserMetadata(ctx, userID, key, value)
return &metadata.Metadata{
CreationDate: metadataResp.GetSetDate(),
ChangeDate: metadataResp.GetSetDate(),
Key: key,
Value: []byte(base64.StdEncoding.EncodeToString([]byte(value))),
}
}
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)
}
func TestServer_DeleteUserMetadata(t *testing.T) {
iamOwnerCTX := Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
tests := []struct {
name string
ctx context.Context
prepare func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time)
req *user.DeleteUserMetadataRequest
wantDeletionDate bool
wantErr bool
}{
{
name: "empty id",
ctx: iamOwnerCTX,
req: &user.DeleteUserMetadataRequest{
UserId: "",
},
wantErr: true,
},
{
name: "delete, user not existing",
ctx: iamOwnerCTX,
req: &user.DeleteUserMetadataRequest{
UserId: "notexisting",
},
wantErr: true,
},
{
name: "delete",
ctx: iamOwnerCTX,
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
creationDate := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
key := "key1"
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
request.Keys = []string{key}
return creationDate, time.Time{}
},
req: &user.DeleteUserMetadataRequest{},
wantDeletionDate: true,
},
{
name: "delete, empty list",
ctx: iamOwnerCTX,
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
creationDate := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
key := "key1"
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
Instance.DeleteUserMetadata(iamOwnerCTX, userID, key)
return creationDate, time.Now().UTC()
},
req: &user.DeleteUserMetadataRequest{},
wantErr: true,
},
{
name: "delete, already removed",
ctx: iamOwnerCTX,
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
creationDate := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
key := "key1"
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
Instance.DeleteUserMetadata(iamOwnerCTX, userID, key)
request.Keys = []string{key}
return creationDate, time.Now().UTC()
},
req: &user.DeleteUserMetadataRequest{},
wantErr: true,
},
{
name: "delete, multiple",
ctx: iamOwnerCTX,
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
creationDate := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
request.UserId = userID
key1 := "key1"
Instance.SetUserMetadata(iamOwnerCTX, userID, key1, "value1")
key2 := "key2"
Instance.SetUserMetadata(iamOwnerCTX, userID, key2, "value1")
key3 := "key3"
Instance.SetUserMetadata(iamOwnerCTX, userID, key3, "value1")
request.Keys = []string{key1, key2, key3}
return creationDate, time.Time{}
},
req: &user.DeleteUserMetadataRequest{},
wantDeletionDate: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var creationDate, deletionDate time.Time
if tt.prepare != nil {
creationDate, deletionDate = tt.prepare(tt.req)
}
got, err := Instance.Client.UserV2.DeleteUserMetadata(tt.ctx, tt.req)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assertDeleteProjectResponse(t, creationDate, deletionDate, tt.wantDeletionDate, got)
})
}
}
func assertDeleteProjectResponse(t *testing.T, creationDate, deletionDate time.Time, expectedDeletionDate bool, actualResp *user.DeleteUserMetadataResponse) {
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)
}
}

View File

@@ -22,7 +22,7 @@ import (
)
func TestServer_AddPersonalAccessToken(t *testing.T) {
resp := Instance.CreateUserTypeMachine(IamCTX)
resp := Instance.CreateUserTypeMachine(IamCTX, Instance.DefaultOrg.Id)
userId := resp.GetId()
expirationDate := timestamppb.New(time.Now().Add(time.Hour * 24))
type args struct {
@@ -64,7 +64,7 @@ func TestServer_AddPersonalAccessToken(t *testing.T) {
ExpirationDate: expirationDate,
},
func(request *user.AddPersonalAccessTokenRequest) error {
resp := Instance.CreateUserTypeHuman(IamCTX)
resp := Instance.CreateUserTypeHuman(IamCTX, gofakeit.Email())
request.UserId = resp.Id
return nil
},
@@ -172,7 +172,7 @@ func TestServer_AddPersonalAccessToken_Permission(t *testing.T) {
}
func TestServer_RemovePersonalAccessToken(t *testing.T) {
resp := Instance.CreateUserTypeMachine(IamCTX)
resp := Instance.CreateUserTypeMachine(IamCTX, Instance.DefaultOrg.Id)
userId := resp.GetId()
expirationDate := timestamppb.New(time.Now().Add(time.Hour * 24))
type args struct {
@@ -339,7 +339,7 @@ func TestServer_ListPersonalAccessTokens(t *testing.T) {
})
require.NoError(t, err)
otherOrgUserId := otherOrgUser.GetId()
otherUserId := Instance.CreateUserTypeMachine(SystemCTX).GetId()
otherUserId := Instance.CreateUserTypeMachine(SystemCTX, Instance.DefaultOrg.Id).GetId()
onlySinceTestStartFilter := &user.PersonalAccessTokensSearchFilter{Filter: &user.PersonalAccessTokensSearchFilter_CreatedDateFilter{CreatedDateFilter: &filter.TimestampFilter{
Timestamp: timestamppb.Now(),
Method: filter.TimestampFilterMethod_TIMESTAMP_FILTER_METHOD_AFTER_OR_EQUALS,

View File

@@ -43,7 +43,7 @@ func TestServer_AddSecret(t *testing.T) {
CTX,
&user.AddSecretRequest{},
func(request *user.AddSecretRequest) error {
resp := Instance.CreateUserTypeMachine(CTX)
resp := Instance.CreateUserTypeMachine(CTX, Instance.DefaultOrg.Id)
request.UserId = resp.GetId()
return nil
},
@@ -55,7 +55,7 @@ func TestServer_AddSecret(t *testing.T) {
CTX,
&user.AddSecretRequest{},
func(request *user.AddSecretRequest) error {
resp := Instance.CreateUserTypeMachine(CTX)
resp := Instance.CreateUserTypeMachine(CTX, Instance.DefaultOrg.Id)
request.UserId = resp.GetId()
return nil
},
@@ -67,7 +67,7 @@ func TestServer_AddSecret(t *testing.T) {
CTX,
&user.AddSecretRequest{},
func(request *user.AddSecretRequest) error {
resp := Instance.CreateUserTypeMachine(CTX)
resp := Instance.CreateUserTypeMachine(CTX, Instance.DefaultOrg.Id)
request.UserId = resp.GetId()
_, err := Client.AddSecret(CTX, &user.AddSecretRequest{
UserId: resp.GetId(),
@@ -202,7 +202,7 @@ func TestServer_RemoveSecret(t *testing.T) {
CTX,
&user.RemoveSecretRequest{},
func(request *user.RemoveSecretRequest) error {
resp := Instance.CreateUserTypeMachine(CTX)
resp := Instance.CreateUserTypeMachine(CTX, Instance.DefaultOrg.Id)
request.UserId = resp.GetId()
return nil
},
@@ -215,7 +215,7 @@ func TestServer_RemoveSecret(t *testing.T) {
CTX,
&user.RemoveSecretRequest{},
func(request *user.RemoveSecretRequest) error {
resp := Instance.CreateUserTypeMachine(CTX)
resp := Instance.CreateUserTypeMachine(CTX, Instance.DefaultOrg.Id)
request.UserId = resp.GetId()
_, err := Instance.Client.UserV2.AddSecret(CTX, &user.AddSecretRequest{
UserId: resp.GetId(),

View File

@@ -4,6 +4,7 @@ package user_test
import (
"context"
"encoding/base64"
"fmt"
"net/url"
"os"
@@ -1818,7 +1819,7 @@ func TestServer_DeleteUser(t *testing.T) {
request.UserId = resp.GetUserId()
Instance.CreateProjectUserGrant(t, CTX, projectResp.GetId(), request.UserId)
Instance.CreateProjectMembership(t, CTX, projectResp.GetId(), request.UserId)
Instance.CreateOrgMembership(t, CTX, request.UserId)
Instance.CreateOrgMembership(t, CTX, Instance.DefaultOrg.Id, request.UserId)
return CTX
},
},
@@ -3969,6 +3970,44 @@ func TestServer_CreateUser(t *testing.T) {
}
},
},
{
name: "with metadata",
testCase: func(runId string) testCase {
username := fmt.Sprintf("donald.duck+%s", runId)
email := username + "@example.com"
return testCase{
args: args{
CTX,
&user.CreateUserRequest{
OrganizationId: Instance.DefaultOrg.Id,
Username: &username,
UserType: &user.CreateUserRequest_Human_{
Human: &user.CreateUserRequest_Human{
Profile: &user.SetHumanProfile{
GivenName: "Donald",
FamilyName: "Duck",
},
Email: &user.SetHumanEmail{
Email: email,
Verification: &user.SetHumanEmail_IsVerified{
IsVerified: true,
},
},
Metadata: []*user.Metadata{
{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))},
{Key: "key2", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value2")))},
{Key: "key3", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value3")))},
},
},
},
},
},
want: &user.CreateUserResponse{
Id: "is generated",
},
}
},
},
{
name: "with idp",
testCase: func(runId string) testCase {
@@ -4914,7 +4953,7 @@ func TestServer_UpdateUserTypeHuman(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
now := time.Now()
runId := fmt.Sprint(now.UnixNano() + int64(i))
userId := Instance.CreateUserTypeHuman(CTX).GetId()
userId := Instance.CreateUserTypeHuman(CTX, gofakeit.Email()).GetId()
test := tt.testCase(runId, userId)
got, err := Client.UpdateUser(test.args.ctx, test.args.req)
if test.wantErr {
@@ -4996,7 +5035,7 @@ func TestServer_UpdateUserTypeMachine(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
now := time.Now()
runId := fmt.Sprint(now.UnixNano() + int64(i))
userId := Instance.CreateUserTypeMachine(CTX).GetId()
userId := Instance.CreateUserTypeMachine(CTX, Instance.DefaultOrg.Id).GetId()
test := tt.testCase(runId, userId)
got, err := Client.UpdateUser(test.args.ctx, test.args.req)
if test.wantErr {

View File

@@ -0,0 +1,80 @@
package user
import (
"context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
"github.com/zitadel/zitadel/internal/api/grpc/metadata/v2"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
)
func (s *Server) ListUserMetadata(ctx context.Context, req *connect.Request[user.ListUserMetadataRequest]) (*connect.Response[user.ListUserMetadataResponse], error) {
metadataQueries, err := s.listUserMetadataRequestToModel(req.Msg)
if err != nil {
return nil, err
}
res, err := s.query.SearchUserMetadata(ctx, true, req.Msg.UserId, metadataQueries, s.checkPermission)
if err != nil {
return nil, err
}
return connect.NewResponse(&user.ListUserMetadataResponse{
Metadata: metadata.UserMetadataListToPb(res.Metadata),
Pagination: filter.QueryToPaginationPb(metadataQueries.SearchRequest, res.SearchResponse),
}), nil
}
func (s *Server) listUserMetadataRequestToModel(req *user.ListUserMetadataRequest) (*query.UserMetadataSearchQueries, error) {
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
if err != nil {
return nil, err
}
queries, err := metadata.UserMetadataFiltersToQuery(req.Filters)
if err != nil {
return nil, err
}
return &query.UserMetadataSearchQueries{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
SortingColumn: query.UserMetadataCreationDateCol,
},
Queries: queries,
}, nil
}
func (s *Server) SetUserMetadata(ctx context.Context, req *connect.Request[user.SetUserMetadataRequest]) (*connect.Response[user.SetUserMetadataResponse], error) {
result, err := s.command.BulkSetUserMetadata(ctx, req.Msg.UserId, "", setUserMetadataToDomain(req.Msg)...)
if err != nil {
return nil, err
}
return connect.NewResponse(&user.SetUserMetadataResponse{
SetDate: timestamppb.New(result.EventDate),
}), nil
}
func setUserMetadataToDomain(req *user.SetUserMetadataRequest) []*domain.Metadata {
metadata := make([]*domain.Metadata, len(req.Metadata))
for i, data := range req.Metadata {
metadata[i] = &domain.Metadata{
Key: data.Key,
Value: data.Value,
}
}
return metadata
}
func (s *Server) DeleteUserMetadata(ctx context.Context, req *connect.Request[user.DeleteUserMetadataRequest]) (*connect.Response[user.DeleteUserMetadataResponse], error) {
result, err := s.command.BulkRemoveUserMetadata(ctx, req.Msg.UserId, "", req.Msg.Keys...)
if err != nil {
return nil, err
}
return connect.NewResponse(&user.DeleteUserMetadataResponse{
DeletionDate: timestamppb.New(result.EventDate),
}), nil
}

View File

@@ -37,9 +37,9 @@ type Server struct {
type Config struct{}
func CreateServer(
systemDefaults systemdefaults.SystemDefaults,
command *command.Commands,
query *query.Queries,
systemDefaults systemdefaults.SystemDefaults,
userCodeAlg crypto.EncryptionAlgorithm,
idpAlg crypto.EncryptionAlgorithm,
idpCallback func(ctx context.Context) string,
@@ -48,7 +48,6 @@ func CreateServer(
checkPermission domain.PermissionCheck,
) *Server {
return &Server{
systemDefaults: systemDefaults,
command: command,
query: query,
userCodeAlg: userCodeAlg,
@@ -57,6 +56,7 @@ func CreateServer(
samlRootURL: samlRootURL,
assetAPIPrefix: assetAPIPrefix,
checkPermission: checkPermission,
systemDefaults: systemDefaults,
}
}

View File

@@ -204,7 +204,7 @@ func (s *Server) removeUserDependencies(ctx context.Context, userID string) ([]*
}
grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{
Queries: []query.SearchQuery{userGrantUserQuery},
}, true)
}, true, nil)
if err != nil {
return nil, nil, err
}