separated quotation and payments

This commit is contained in:
Stephan D
2026-02-10 18:29:47 +01:00
parent 6745bc0f6f
commit 296cc7b86a
163 changed files with 13516 additions and 191 deletions

View File

@@ -77,7 +77,7 @@ func CreateAPI(apiCtx eapi.API) (*PaymentAPI, error) {
}
p.permissionRef = desc.ID
if err := p.initPaymentClient(apiCtx.Config().PaymentOrchestrator); err != nil {
if err := p.initPaymentClient(apiCtx.Config().PaymentOrchestrator, apiCtx.Config().PaymentQuotation); err != nil {
p.logger.Error("Failed to initialize payment orchestrator client", zap.Error(err))
return nil, err
}
@@ -98,7 +98,7 @@ func CreateAPI(apiCtx eapi.API) (*PaymentAPI, error) {
return p, nil
}
func (a *PaymentAPI) initPaymentClient(cfg *eapi.PaymentOrchestratorConfig) error {
func (a *PaymentAPI) initPaymentClient(cfg *eapi.PaymentOrchestratorConfig, quoteCfg *eapi.PaymentOrchestratorConfig) error {
if cfg == nil {
return merrors.InvalidArgument("payment orchestrator configuration is not provided")
}
@@ -111,11 +111,23 @@ func (a *PaymentAPI) initPaymentClient(cfg *eapi.PaymentOrchestratorConfig) erro
return merrors.InvalidArgument(fmt.Sprintf("payment orchestrator address is not specified and address env %s is empty", cfg.AddressEnv))
}
quoteAddress := address
if quoteCfg != nil {
if addr := strings.TrimSpace(quoteCfg.Address); addr != "" {
quoteAddress = addr
} else if env := strings.TrimSpace(quoteCfg.AddressEnv); env != "" {
if resolved := strings.TrimSpace(os.Getenv(env)); resolved != "" {
quoteAddress = resolved
}
}
}
clientCfg := orchestratorclient.Config{
Address: address,
DialTimeout: time.Duration(cfg.DialTimeoutSeconds) * time.Second,
CallTimeout: time.Duration(cfg.CallTimeoutSeconds) * time.Second,
Insecure: cfg.Insecure,
Address: address,
QuoteAddress: quoteAddress,
DialTimeout: time.Duration(cfg.DialTimeoutSeconds) * time.Second,
CallTimeout: time.Duration(cfg.CallTimeoutSeconds) * time.Second,
Insecure: cfg.Insecure,
}
client, err := orchestratorclient.New(context.Background(), clientCfg)

View File

@@ -30,7 +30,7 @@ func (a *VerificationAPI) requestCode(r *http.Request, account *model.Account, t
return response.Forbidden(a.logger, a.Name(), "pending_token_required", "login confirmation requires pending token")
}
target := a.resolveTarget(req.Destination, account)
target := a.resolveTarget(req.Target, account)
if target == "" {
return response.BadRequest(a.logger, a.Name(), "missing_destination", "email destination is required")
}
@@ -51,7 +51,7 @@ func (a *VerificationAPI) requestCode(r *http.Request, account *model.Account, t
return response.Accepted(a.logger, verificationResponse{
TTLSeconds: int(vReq.Ttl.Seconds()),
CooldownSeconds: int(a.config.Cooldown.Seconds()),
Destination: mask.Email(target),
Target: mask.Email(target),
IdempotencyKey: req.IdempotencyKey,
})
}

View File

@@ -21,11 +21,7 @@ func (s *ConfirmationStore) Create(
ctx context.Context,
request *verification.Request,
) (verificationCode string, err error) {
code, err := s.db.Create(ctx, request)
if err != nil {
return "", err
}
return code, nil
return s.db.Create(ctx, request)
}
func (s *ConfirmationStore) Verify(

View File

@@ -6,7 +6,7 @@ import (
type verificationCodeRequest struct {
Purpose string `json:"purpose"`
Destination string `json:"destination,omitempty"`
Target string `json:"target,omitempty"`
IdempotencyKey string `json:"idempotencyKey"`
}
@@ -20,5 +20,5 @@ type verificationResponse struct {
IdempotencyKey string `json:"idempotencyKey"`
TTLSeconds int `json:"ttl_seconds"`
CooldownSeconds int `json:"cooldown_seconds"`
Destination string `json:"destination"`
Target string `json:"target"`
}

View File

@@ -27,17 +27,20 @@ func (a *VerificationAPI) verifyCode(r *http.Request, account *model.Account, to
return response.BadRequest(a.logger, a.Name(), "invalid_target", err.Error())
}
if strings.TrimSpace(req.Code) == "" {
code := strings.TrimSpace(req.Code)
if code == "" {
return response.BadRequest(a.logger, a.Name(), "missing_code", "confirmation code is required")
}
target := a.resolveTarget(req.Destination, account)
target := a.resolveTarget(req.Target, account)
if target == "" {
return response.BadRequest(a.logger, a.Name(), "missing_destination", "email destination is required")
}
dst, err := a.store.Verify(r.Context(), account.ID, purpose, req.Code)
dst, err := a.store.Verify(r.Context(), account.ID, purpose, code)
if err != nil {
a.logger.Debug("Code verification failed", zap.Error(err))
a.logger.Debug("Code verification failed", zap.Error(err),
mzap.AccRef(account.ID), zap.String("purpose", req.Purpose),
)
return mutil.MapTokenErrorToResponse(a.logger, a.Name(), err)
}
if dst != target {