<commit_before>package payment

import (
	"github.com/fritzpay/paymentd/pkg/paymentd/nonce"
	"github.com/fritzpay/paymentd/pkg/paymentd/payment"
	"github.com/fritzpay/paymentd/pkg/paymentd/project"
	"github.com/fritzpay/paymentd/pkg/service"
	"github.com/fritzpay/paymentd/pkg/service/payment/notification"
	"gopkg.in/inconshreveable/log15.v2"
	"net/http"
	"time"
)

// Callbacker describes a type that can provide information about callbacks to be made
type Callbacker interface {
	HasCallback() bool
	CallbackConfig() (url, apiVersion, projectKey string)
}

func CanCallback(c Callbacker) bool {
	return c.HasCallback()
}

func (s *Service) Notify(c Callbacker, paymentTx *payment.PaymentTransaction) {
	cbURL, cbAPIVersion, cbProjectKey := c.CallbackConfig()
	log := s.log.New(log15.Ctx{
		"method":                      "Notify",
		"projectID":                   paymentTx.Payment.ProjectID(),
		"paymentID":                   paymentTx.Payment.ID(),
		"paymentTransactionTimestamp": paymentTx.Timestamp.UnixNano(),
		"callbackURL":                 cbURL,
		"callbackAPIVersion":          cbAPIVersion,
		"callbackProjectKey":          cbProjectKey,
	})
	log.Info("notifying...")
	notF, err := notification.NotificationByVersion(cbAPIVersion)
	if err != nil {
		log.Error("error retrieving notification by version", log15.Ctx{"err": err})
		return
	}
	not, err := notF(s.EncodedPaymentID(paymentTx.Payment.PaymentID()), paymentTx.Payment)
	if err != nil {
		log.Error("error creating notification", log15.Ctx{"err": err})
		return
	}
	projectKey, err := project.ProjectKeyByKeyDB(s.ctx.PrincipalDB(service.ReadOnly), cbProjectKey)
	if err != nil {
		if err == project.ErrProjectKeyNotFound {
			log.Error("invalid project key")
			return
		}
		log.Error("error retrieving project key", log15.Ctx{"err": err})
		return
	}
	if !projectKey.IsValid() {
		log.Warn("cannot notify with invalid project key", log15.Ctx{"projectKey": projectKey})
		return
	}
	// balance
	tl, err := payment.PaymentTransactionsBeforeDB(s.ctx.PaymentDB(service.ReadOnly), paymentTx)
	if err != nil {
		log.Error("error retrieving transaction history", log15.Ctx{"err": err})
		return
	}
	not.SetTransactions(tl)
	// signing
	non, err := nonce.New()
	if err != nil {
		log.Error("error generating nonce", log15.Ctx{"err": err})
		return
	}
	secret, err := projectKey.SecretBytes()
	if err != nil {
		log.Error("error retrieving secret", log15.Ctx{"err": err})
		return
	}
	err = not.Sign(time.Now(), non.Nonce, secret)
	if err != nil {
		log.Error("error signing notification", log15.Ctx{"err": err})
		return
	}

	req, err := http.NewRequest("POST", cbURL, not.Reader())
	if err != nil {
		log.Error("error creating HTTP request", log15.Ctx{"err": err})
		return
	}
	req.Header.Set("User-Agent", not.Identification())
	req.Close = true<commit_msg>notification without transaction history is not an error<commit_after>package payment

import (
	"github.com/fritzpay/paymentd/pkg/paymentd/nonce"
	"github.com/fritzpay/paymentd/pkg/paymentd/payment"
	"github.com/fritzpay/paymentd/pkg/paymentd/project"
	"github.com/fritzpay/paymentd/pkg/service"
	"github.com/fritzpay/paymentd/pkg/service/payment/notification"
	"gopkg.in/inconshreveable/log15.v2"
	"net/http"
	"time"
)

// Callbacker describes a type that can provide information about callbacks to be made
type Callbacker interface {
	HasCallback() bool
	CallbackConfig() (url, apiVersion, projectKey string)
}

func CanCallback(c Callbacker) bool {
	return c.HasCallback()
}

func (s *Service) Notify(c Callbacker, paymentTx *payment.PaymentTransaction) {
	cbURL, cbAPIVersion, cbProjectKey := c.CallbackConfig()
	log := s.log.New(log15.Ctx{
		"method":                      "Notify",
		"projectID":                   paymentTx.Payment.ProjectID(),
		"paymentID":                   paymentTx.Payment.ID(),
		"paymentTransactionTimestamp": paymentTx.Timestamp.UnixNano(),
		"callbackURL":                 cbURL,
		"callbackAPIVersion":          cbAPIVersion,
		"callbackProjectKey":          cbProjectKey,
	})
	log.Info("notifying...")
	notF, err := notification.NotificationByVersion(cbAPIVersion)
	if err != nil {
		log.Error("error retrieving notification by version", log15.Ctx{"err": err})
		return
	}
	not, err := notF(s.EncodedPaymentID(paymentTx.Payment.PaymentID()), paymentTx.Payment)
	if err != nil {
		log.Error("error creating notification", log15.Ctx{"err": err})
		return
	}
	projectKey, err := project.ProjectKeyByKeyDB(s.ctx.PrincipalDB(service.ReadOnly), cbProjectKey)
	if err != nil {
		if err == project.ErrProjectKeyNotFound {
			log.Error("invalid project key")
			return
		}
		log.Error("error retrieving project key", log15.Ctx{"err": err})
		return
	}
	if !projectKey.IsValid() {
		log.Warn("cannot notify with invalid project key", log15.Ctx{"projectKey": projectKey})
		return
	}
	// balance
	tl, err := payment.PaymentTransactionsBeforeDB(s.ctx.PaymentDB(service.ReadOnly), paymentTx)
	if err != nil && err != payment.ErrPaymentTransactionNotFound {
		log.Error("error retrieving transaction history", log15.Ctx{"err": err})
		return
	}
	if tl != nil {
		not.SetTransactions(tl)
	}
	// signing
	non, err := nonce.New()
	if err != nil {
		log.Error("error generating nonce", log15.Ctx{"err": err})
		return
	}
	secret, err := projectKey.SecretBytes()
	if err != nil {
		log.Error("error retrieving secret", log15.Ctx{"err": err})
		return
	}
	err = not.Sign(time.Now(), non.Nonce, secret)
	if err != nil {
		log.Error("error signing notification", log15.Ctx{"err": err})
		return
	}

	req, err := http.NewRequest("POST", cbURL, not.Reader())
	if err != nil {
		log.Error("error creating HTTP request", log15.Ctx{"err": err})
		return
	}
	req.Header.Set("User-Agent", not.Identification())
	req.Close = true
{'fraction_non_alphanumeric': 0.1421628189550425, 'fraction_numerical': 0.007984724874153793, 'mean_word_length': 4.081128747795415, 'pattern_counts': {'":': 32, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6864540', 'n_tokens_mistral': 1983, 'n_tokens_neox': 1909, 'n_words': 411}