fix: restructure resend email code to send email code (#9099)

# Which Problems Are Solved

There is currently no endpoint to send an email code for verification of
the email if you don't change the email itself.

# How the Problems Are Solved

Endpoint HasEmailCode to get the information that an email code is
existing, used by the new login.
Endpoint SendEmailCode, if no code is existing to replace
ResendEmailCode as there is a check that a code has to be there, before
it can be resend.

# Additional Changes

None

# Additional Context

Closes #9096

---------

Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com>
This commit is contained in:
Stefan Benz
2024-12-27 16:34:38 +01:00
committed by GitHub
parent 1f8623d3dc
commit 8ec099ae28
5 changed files with 573 additions and 76 deletions

View File

@@ -67,6 +67,33 @@ func (s *Server) ResendEmailCode(ctx context.Context, req *user.ResendEmailCodeR
}, nil
}
func (s *Server) SendEmailCode(ctx context.Context, req *user.SendEmailCodeRequest) (resp *user.SendEmailCodeResponse, err error) {
var email *domain.Email
switch v := req.GetVerification().(type) {
case *user.SendEmailCodeRequest_SendCode:
email, err = s.command.SendUserEmailCodeURLTemplate(ctx, req.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
case *user.SendEmailCodeRequest_ReturnCode:
email, err = s.command.SendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
case nil:
email, err = s.command.SendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg)
default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method SendEmailCode not implemented", v)
}
if err != nil {
return nil, err
}
return &user.SendEmailCodeResponse{
Details: &object.Details{
Sequence: email.Sequence,
ChangeDate: timestamppb.New(email.ChangeDate),
ResourceOwner: email.ResourceOwner,
},
VerificationCode: email.PlainCode,
}, nil
}
func (s *Server) VerifyEmail(ctx context.Context, req *user.VerifyEmailRequest) (*user.VerifyEmailResponse, error) {
details, err := s.command.VerifyUserEmail(ctx,
req.GetUserId(),

View File

@@ -249,6 +249,116 @@ func TestServer_ResendEmailCode(t *testing.T) {
}
}
func TestServer_SendEmailCode(t *testing.T) {
userID := Instance.CreateHumanUser(CTX).GetUserId()
verifiedUserID := Instance.CreateHumanUserVerified(CTX, Instance.DefaultOrg.Id, gofakeit.Email()).GetUserId()
tests := []struct {
name string
req *user.SendEmailCodeRequest
want *user.SendEmailCodeResponse
wantErr bool
}{
{
name: "user not existing",
req: &user.SendEmailCodeRequest{
UserId: "xxx",
},
wantErr: true,
},
{
name: "user no code",
req: &user.SendEmailCodeRequest{
UserId: verifiedUserID,
},
want: &user.SendEmailCodeResponse{
Details: &object.Details{
Sequence: 1,
ChangeDate: timestamppb.Now(),
ResourceOwner: Instance.DefaultOrg.Id,
},
},
},
{
name: "resend",
req: &user.SendEmailCodeRequest{
UserId: userID,
},
want: &user.SendEmailCodeResponse{
Details: &object.Details{
Sequence: 1,
ChangeDate: timestamppb.Now(),
ResourceOwner: Instance.DefaultOrg.Id,
},
},
},
{
name: "custom url template",
req: &user.SendEmailCodeRequest{
UserId: userID,
Verification: &user.SendEmailCodeRequest_SendCode{
SendCode: &user.SendEmailVerificationCode{
UrlTemplate: gu.Ptr("https://example.com/email/verify?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}"),
},
},
},
want: &user.SendEmailCodeResponse{
Details: &object.Details{
Sequence: 1,
ChangeDate: timestamppb.Now(),
ResourceOwner: Instance.DefaultOrg.Id,
},
},
},
{
name: "template error",
req: &user.SendEmailCodeRequest{
UserId: userID,
Verification: &user.SendEmailCodeRequest_SendCode{
SendCode: &user.SendEmailVerificationCode{
UrlTemplate: gu.Ptr("{{"),
},
},
},
wantErr: true,
},
{
name: "return code",
req: &user.SendEmailCodeRequest{
UserId: userID,
Verification: &user.SendEmailCodeRequest_ReturnCode{
ReturnCode: &user.ReturnEmailVerificationCode{},
},
},
want: &user.SendEmailCodeResponse{
Details: &object.Details{
Sequence: 1,
ChangeDate: timestamppb.Now(),
ResourceOwner: Instance.DefaultOrg.Id,
},
VerificationCode: gu.Ptr("xxx"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Client.SendEmailCode(CTX, tt.req)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
integration.AssertDetails(t, tt.want, got)
if tt.want.GetVerificationCode() != "" {
assert.NotEmpty(t, got.GetVerificationCode())
} else {
assert.Empty(t, got.GetVerificationCode())
}
})
}
}
func TestServer_VerifyEmail(t *testing.T) {
userResp := Instance.CreateHumanUser(CTX)
tests := []struct {