feat: user v3 contact email and phone (#8644)

# Which Problems Are Solved

Endpoints to maintain email and phone contact on user v3 are not
implemented.

# How the Problems Are Solved

Add 3 endpoints with SetContactEmail, VerifyContactEmail and
ResendContactEmailCode.
Add 3 endpoints with SetContactPhone, VerifyContactPhone and
ResendContactPhoneCode.
Refactor the logic how contact is managed in the user creation and
update.

# Additional Changes

None

# Additional Context

- part of https://github.com/zitadel/zitadel/issues/6433

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz
2024-09-25 15:31:31 +02:00
committed by GitHub
parent 624fee97c0
commit 62cdec222e
21 changed files with 4924 additions and 432 deletions

View File

@@ -7,7 +7,6 @@ import (
"testing"
"time"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
@@ -875,8 +874,9 @@ func TestCommands_CreateSchemaUser(t *testing.T) {
idGenerator: tt.fields.idGenerator,
checkPermission: tt.fields.checkPermission,
newEncryptedCode: tt.fields.newCode,
userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
}
err := c.CreateSchemaUser(tt.args.ctx, tt.args.user, crypto.CreateMockEncryptionAlg(gomock.NewController(t)))
details, err := c.CreateSchemaUser(tt.args.ctx, tt.args.user)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -884,14 +884,16 @@ func TestCommands_CreateSchemaUser(t *testing.T) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assertObjectDetails(t, tt.res.details, tt.args.user.Details)
assertObjectDetails(t, tt.res.details, details)
}
if tt.res.returnCodePhone != "" {
assert.Equal(t, tt.res.returnCodePhone, tt.args.user.ReturnCodePhone)
assert.NotNil(t, tt.args.user.ReturnCodePhone)
assert.Equal(t, tt.res.returnCodePhone, *tt.args.user.ReturnCodePhone)
}
if tt.res.returnCodeEmail != "" {
assert.Equal(t, tt.res.returnCodeEmail, tt.args.user.ReturnCodeEmail)
assert.NotNil(t, tt.args.user.ReturnCodeEmail)
assert.Equal(t, tt.res.returnCodeEmail, *tt.args.user.ReturnCodeEmail)
}
})
}
@@ -1988,6 +1990,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"schema not existing, error",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(),
),
checkPermission: newMockPermissionCheckAllowed(),
@@ -1995,8 +2010,10 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
args{
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("type"),
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "type",
},
},
},
res{
@@ -2060,6 +2077,25 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
context.Background(),
&schema.NewAggregate("id1", "instanceID").Aggregate,
"type",
json.RawMessage(`{
"$schema": "urn:zitadel:schema:v1",
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}`),
[]domain.AuthenticatorType{domain.AuthenticatorTypeUsername},
),
),
),
),
checkPermission: newMockPermissionCheckNotAllowed(),
},
@@ -2067,9 +2103,11 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
Data: json.RawMessage(`{
SchemaUser: &SchemaUser{
Data: json.RawMessage(`{
"name": "user"
}`),
},
},
},
res{
@@ -2134,9 +2172,11 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
Data: json.RawMessage(`{
SchemaUser: &SchemaUser{
Data: json.RawMessage(`{
"name": "user2"
}`),
},
},
},
res{
@@ -2149,6 +2189,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user updated, changed schema",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2168,19 +2221,6 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectPush(
schemauser.NewUpdatedEvent(
context.Background(),
@@ -2196,8 +2236,10 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
args{
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("id2"),
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "id2",
},
},
},
res{
@@ -2210,6 +2252,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user updated, new schema",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2229,19 +2284,6 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectPush(
schemauser.NewUpdatedEvent(
context.Background(),
@@ -2262,11 +2304,13 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
args{
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("id2"),
Data: json.RawMessage(`{
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "id2",
Data: json.RawMessage(`{
"name": "user2"
}`),
},
},
},
res{
@@ -2350,9 +2394,11 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
Data: json.RawMessage(`{
SchemaUser: &SchemaUser{
Data: json.RawMessage(`{
"name2": "user2"
}`),
},
},
},
res{
@@ -2365,6 +2411,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user updated, new schema and revision",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
2,
json.RawMessage(`{
"name1": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2384,19 +2443,6 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
2,
json.RawMessage(`{
"name1": "user1"
}`),
),
),
),
expectPush(
schemauser.NewUpdatedEvent(
context.Background(),
@@ -2418,11 +2464,13 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
args{
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("id2"),
Data: json.RawMessage(`{
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "id2",
Data: json.RawMessage(`{
"name2": "user2"
}`),
},
},
},
res{
@@ -2435,6 +2483,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user update, no field permission as admin",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2457,30 +2518,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
),
checkPermission: newMockPermissionCheckAllowed(),
},
args{
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("id1"),
Data: json.RawMessage(`{
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "id1",
Data: json.RawMessage(`{
"name": "user"
}`),
},
},
},
res{
@@ -2494,6 +2544,18 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
), expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
context.Background(),
@@ -2515,29 +2577,18 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
),
},
args{
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("type"),
Data: json.RawMessage(`{
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "type",
Data: json.RawMessage(`{
"name": "user"
}`),
},
},
},
res{
@@ -2550,6 +2601,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user update, invalid data type",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2569,30 +2633,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
),
checkPermission: newMockPermissionCheckAllowed(),
},
args{
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("type"),
Data: json.RawMessage(`{
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "type",
Data: json.RawMessage(`{
"name": 1
}`),
},
},
},
res{
@@ -2605,6 +2658,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user update, additional property",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2624,19 +2690,6 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectPush(
schemauser.NewUpdatedEvent(
context.Background(),
@@ -2657,12 +2710,14 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
args{
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("id1"),
Data: json.RawMessage(`{
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "id1",
Data: json.RawMessage(`{
"name": "user1",
"additional": "property"
}`),
},
},
},
res{
@@ -2675,6 +2730,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user update, invalid data attribute name",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2695,30 +2763,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
),
checkPermission: newMockPermissionCheckAllowed(),
},
args{
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("type"),
Data: json.RawMessage(`{
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "type",
Data: json.RawMessage(`{
"invalid": "user"
}`),
},
},
},
res{
@@ -2775,6 +2832,19 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
"user update, email return",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectFilter(
eventFromEventPusher(
schema.NewCreatedEvent(
@@ -2794,19 +2864,6 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
schemauser.NewCreatedEvent(
context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
"id1",
1,
json.RawMessage(`{
"name": "user1"
}`),
),
),
),
expectPush(
schemauser.NewEmailUpdatedEvent(context.Background(),
&schemauser.NewAggregate("user1", "org1").Aggregate,
@@ -2832,8 +2889,10 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
args{
ctx: authz.NewMockContext("instanceID", "", ""),
user: &ChangeSchemaUser{
ID: "user1",
SchemaID: gu.Ptr("id1"),
ID: "user1",
SchemaUser: &SchemaUser{
SchemaID: "id1",
},
Email: &Email{
Address: "test@example.com",
ReturnCode: true,
@@ -3101,8 +3160,9 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
eventstore: tt.fields.eventstore(t),
checkPermission: tt.fields.checkPermission,
newEncryptedCode: tt.fields.newCode,
userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
}
err := c.ChangeSchemaUser(tt.args.ctx, tt.args.user, crypto.CreateMockEncryptionAlg(gomock.NewController(t)))
details, err := c.ChangeSchemaUser(tt.args.ctx, tt.args.user)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -3110,14 +3170,16 @@ func TestCommands_ChangeSchemaUser(t *testing.T) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assertObjectDetails(t, tt.res.details, tt.args.user.Details)
assertObjectDetails(t, tt.res.details, details)
}
if tt.res.returnCodePhone != "" {
assert.Equal(t, tt.res.returnCodePhone, tt.args.user.ReturnCodePhone)
assert.NotNil(t, tt.args.user.ReturnCodePhone)
assert.Equal(t, tt.res.returnCodePhone, *tt.args.user.ReturnCodePhone)
}
if tt.res.returnCodeEmail != "" {
assert.Equal(t, tt.res.returnCodeEmail, tt.args.user.ReturnCodeEmail)
assert.NotNil(t, tt.args.user.ReturnCodeEmail)
assert.Equal(t, tt.res.returnCodeEmail, *tt.args.user.ReturnCodeEmail)
}
})
}