Integrate email notifications into signup and login (#38)

This commit is contained in:
Stephan D committed 2026-09-12 15:07:00 +02:00
1 parent 326d58f705
commit ad5a061164
55 files changed
+1859 -3464

No files matched your search

+16 -4
View File
@@ -3,9 +3,9 @@ package verification
import (
"context"
"errors"
verificationmodel "git.sendico.io/tech/sxchnge/product/verification/model"
"time"
verificationmodel "git.sendico.io/tech/sxchnge/product/verification/model"
"git.sendico.io/tech/sxchnge/shared/database/repository"
"git.sendico.io/tech/sxchnge/shared/database/repository/builder"
"git.sendico.io/tech/sxchnge/shared/errors"
@@ -21,7 +21,7 @@ func activeContextFilter(request *Request, now time.Time) builder.Query {
filters := []builder.Query{
repository.Filter("accountRef", request.AccountRef),
repository.Filter("purpose", request.Purpose),
repository.Filter("target", request.Target),
targetFilter(request.Target),
repository.Filter("usedAt", nil),
repository.Query().Comparison(repository.Field("expiresAt"), builder.Gt, now),
}
@@ -33,7 +33,7 @@ func cooldownActiveContextFilter(request *Request, now, cutoff time.Time) builde
filters := []builder.Query{
repository.Filter("accountRef", request.AccountRef),
repository.Filter("purpose", request.Purpose),
repository.Filter("target", request.Target),
targetFilter(request.Target),
repository.Filter("usedAt", nil),
repository.Query().Comparison(repository.Field("expiresAt"), builder.Gt, now),
repository.Query().Comparison(repository.Field("createdAt"), builder.Gt, cutoff),
@@ -140,7 +140,10 @@ func (db *verificationDB) CreateWithResult(
// Always store an idempotency key. Client keys enable replay; generated
// keys avoid null-key collisions on older Mongo indexes and keep
// transaction retries deterministic.
idempotencyKey = syntheticIdempotencyKey()
idempotencyKey, err = syntheticIdempotencyKey()
if err != nil {
return CreateResult{}, err
}
hasIdempotency = true
}
@@ -246,3 +249,12 @@ func (db *verificationDB) CreateWithResult(
createResult.VerificationToken = raw
return createResult, nil
}
// Older records omit an empty target; Mongo does not equate a missing field
// with the empty string. Match both forms for cooldown, invalidation and replay.
func targetFilter(target string) builder.Query {
if target != "" {
return repository.Filter("target", target)
}
return repository.Query().Or(repository.Filter("target", ""), repository.Filter("target", nil))
}