예제 #1
0
        private async Task <HttpResponseMessage> SendNotification(InvoicePaymentNotificationEventWrapper notification, CancellationToken cancellationToken)
        {
            var request = new HttpRequestMessage();

            request.Method = HttpMethod.Post;

            var notificationString = NBitcoin.JsonConverters.Serializer.ToString(notification);
            var jobj = JObject.Parse(notificationString);

            if (notification.ExtendedNotification)
            {
                jobj.Remove("extendedNotification");
                jobj.Remove("notificationURL");
                notificationString = jobj.ToString();
            }
            else
            {
                notificationString = jobj["data"].ToString();
            }

            request.RequestUri = new Uri(notification.NotificationURL, UriKind.Absolute);
            request.Content    = new StringContent(notificationString, UTF8, "application/json");

            using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            cts.CancelAfter(TimeSpan.FromMinutes(1.0));
            var response = await _Client.SendAsync(request, cts.Token);

            return(response);
        }
예제 #2
0
        private async Task <HttpResponseMessage> SendNotification(InvoicePaymentNotificationEventWrapper notification, CancellationToken cancellation)
        {
            var request = new HttpRequestMessage();

            request.Method = HttpMethod.Post;

            var notificationString = NBitcoin.JsonConverters.Serializer.ToString(notification);
            var jobj = JObject.Parse(notificationString);

            if (notification.ExtendedNotification)
            {
                jobj.Remove("extendedNotification");
                jobj.Remove("notificationURL");
                notificationString = jobj.ToString();
            }
            else
            {
                notificationString = jobj["data"].ToString();
            }

            request.RequestUri = new Uri(notification.NotificationURL, UriKind.Absolute);
            request.Content    = new StringContent(notificationString, UTF8, "application/json");
            var response = await Enqueue(notification.Data.Id, async() => await _Client.SendAsync(request, cancellation));

            return(response);
        }
        private async Task <HttpResponseMessage> SendNotification(InvoiceEntity invoice, int?eventCode, string name, CancellationToken cancellation)
        {
            var request = new HttpRequestMessage();

            request.Method = HttpMethod.Post;

            var dto = invoice.EntityToDTO(_NetworkProvider);
            InvoicePaymentNotification notification = new InvoicePaymentNotification()
            {
                Id              = dto.Id,
                Currency        = dto.Currency,
                CurrentTime     = dto.CurrentTime,
                ExceptionStatus = dto.ExceptionStatus,
                ExpirationTime  = dto.ExpirationTime,
                InvoiceTime     = dto.InvoiceTime,
                PosData         = dto.PosData,
                Price           = dto.Price,
                Status          = dto.Status,
                BuyerFields     = invoice.RefundMail == null ? null : new Newtonsoft.Json.Linq.JObject()
                {
                    new JProperty("buyerEmail", invoice.RefundMail)
                },
                PaymentSubtotals = dto.PaymentSubtotals,
                PaymentTotals    = dto.PaymentTotals,
                AmountPaid       = dto.AmountPaid,
                ExchangeRates    = dto.ExchangeRates
            };

            // We keep backward compatibility with bitpay by passing BTC info to the notification
            // we don't pass other info, as it is a bad idea to use IPN data for logic processing (can be faked)
            var btcCryptoInfo = dto.CryptoInfo.FirstOrDefault(c => c.GetpaymentMethodId() == new PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike));

            if (btcCryptoInfo != null)
            {
#pragma warning disable CS0618
                notification.Rate     = dto.Rate;
                notification.Url      = dto.Url;
                notification.BTCDue   = dto.BTCDue;
                notification.BTCPaid  = dto.BTCPaid;
                notification.BTCPrice = dto.BTCPrice;
#pragma warning restore CS0618
            }

            string notificationString = null;
            if (eventCode.HasValue)
            {
                var wrapper = new InvoicePaymentNotificationEventWrapper();
                wrapper.Data  = notification;
                wrapper.Event = new InvoicePaymentNotificationEvent()
                {
                    Code = eventCode.Value, Name = name
                };
                notificationString = JsonConvert.SerializeObject(wrapper);
            }
            else
            {
                notificationString = JsonConvert.SerializeObject(notification);
            }

            request.RequestUri = new Uri(invoice.NotificationURL, UriKind.Absolute);
            request.Content    = new StringContent(notificationString, UTF8, "application/json");
            var response = await Enqueue(invoice.Id, async() => await _Client.SendAsync(request, cancellation));

            return(response);
        }
예제 #4
0
        async Task Notify(InvoiceEntity invoice, InvoiceEvent invoiceEvent, bool extendedNotification, bool sendMail)
        {
            var dto          = invoice.EntityToDTO();
            var notification = new InvoicePaymentNotificationEventWrapper()
            {
                Data = new InvoicePaymentNotification()
                {
                    Id              = dto.Id,
                    Currency        = dto.Currency,
                    CurrentTime     = dto.CurrentTime,
                    ExceptionStatus = dto.ExceptionStatus,
                    ExpirationTime  = dto.ExpirationTime,
                    InvoiceTime     = dto.InvoiceTime,
                    PosData         = dto.PosData,
                    Price           = dto.Price,
                    Status          = dto.Status,
                    BuyerFields     = invoice.RefundMail == null ? null : new Newtonsoft.Json.Linq.JObject()
                    {
                        new JProperty("buyerEmail", invoice.RefundMail)
                    },
                    PaymentSubtotals = dto.PaymentSubtotals,
                    PaymentTotals    = dto.PaymentTotals,
                    AmountPaid       = dto.AmountPaid,
                    ExchangeRates    = dto.ExchangeRates,
                    OrderId          = dto.OrderId
                },
                Event = new InvoicePaymentNotificationEvent()
                {
                    Code = (int)invoiceEvent.EventCode,
                    Name = invoiceEvent.Name
                },
                ExtendedNotification = extendedNotification,
                NotificationURL      = invoice.NotificationURL?.AbsoluteUri
            };

            // For lightning network payments, paid, confirmed and completed come all at once.
            // So despite the event is "paid" or "confirmed" the Status of the invoice is technically complete
            // This confuse loggers who think their endpoint get duplicated events
            // So here, we just override the status expressed by the notification
            if (invoiceEvent.Name == InvoiceEvent.Confirmed)
            {
                notification.Data.Status = InvoiceState.ToString(InvoiceStatusLegacy.Confirmed);
            }
            if (invoiceEvent.Name == InvoiceEvent.PaidInFull)
            {
                notification.Data.Status = InvoiceState.ToString(InvoiceStatusLegacy.Paid);
            }
            //////////////////

            // We keep backward compatibility with bitpay by passing BTC info to the notification
            // we don't pass other info, as it is a bad idea to use IPN data for logic processing (can be faked)
            var btcCryptoInfo = dto.CryptoInfo.FirstOrDefault(c => c.GetpaymentMethodId() == new PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike) && !string.IsNullOrEmpty(c.Address));

            if (btcCryptoInfo != null)
            {
#pragma warning disable CS0618
                notification.Data.Rate     = dto.Rate;
                notification.Data.Url      = dto.Url;
                notification.Data.BTCDue   = dto.BTCDue;
                notification.Data.BTCPaid  = dto.BTCPaid;
                notification.Data.BTCPrice = dto.BTCPrice;
#pragma warning restore CS0618
            }

            if (sendMail && !String.IsNullOrEmpty(invoice.NotificationEmail))
            {
                var json  = NBitcoin.JsonConverters.Serializer.ToString(notification);
                var store = await _StoreRepository.FindStore(invoice.StoreId);

                var storeName = store.StoreName ?? "BTCPay Server";
                var emailBody = $"Store: {storeName}<br>" +
                                $"Invoice ID: {notification.Data.Id}<br>" +
                                $"Status: {notification.Data.Status}<br>" +
                                $"Amount: {notification.Data.Price} {notification.Data.Currency}<br>" +
                                $"<br><details><summary>Details</summary><pre>{json}</pre></details>";

                (await _EmailSenderFactory.GetEmailSender(invoice.StoreId)).SendEmail(
                    invoice.NotificationEmail,
                    $"{storeName} Invoice Notification - ${invoice.StoreId}",
                    emailBody);
            }

            if (invoice.NotificationURL != null)
            {
                _Queue.Enqueue(invoice.Id, (cancellationToken) => NotifyHttp(new ScheduledJob()
                {
                    TryCount = 0, Notification = notification
                }, cancellationToken));
            }
        }
예제 #5
0
        void Notify(InvoiceEntity invoice, InvoiceEvent invoiceEvent, bool extendedNotification)
        {
            var dto          = invoice.EntityToDTO(_NetworkProvider);
            var notification = new InvoicePaymentNotificationEventWrapper()
            {
                Data = new InvoicePaymentNotification()
                {
                    Id              = dto.Id,
                    Currency        = dto.Currency,
                    CurrentTime     = dto.CurrentTime,
                    ExceptionStatus = dto.ExceptionStatus,
                    ExpirationTime  = dto.ExpirationTime,
                    InvoiceTime     = dto.InvoiceTime,
                    PosData         = dto.PosData,
                    Price           = dto.Price,
                    Status          = dto.Status,
                    BuyerFields     = invoice.RefundMail == null ? null : new Newtonsoft.Json.Linq.JObject()
                    {
                        new JProperty("buyerEmail", invoice.RefundMail)
                    },
                    PaymentSubtotals = dto.PaymentSubtotals,
                    PaymentTotals    = dto.PaymentTotals,
                    AmountPaid       = dto.AmountPaid,
                    ExchangeRates    = dto.ExchangeRates,
                },
                Event = new InvoicePaymentNotificationEvent()
                {
                    Code = invoiceEvent.EventCode,
                    Name = invoiceEvent.Name
                },
                ExtendedNotification = extendedNotification,
                NotificationURL      = invoice.NotificationURL
            };

            // For lightning network payments, paid, confirmed and completed come all at once.
            // So despite the event is "paid" or "confirmed" the Status of the invoice is technically complete
            // This confuse loggers who think their endpoint get duplicated events
            // So here, we just override the status expressed by the notification
            if (invoiceEvent.Name == InvoiceEvent.Confirmed)
            {
                notification.Data.Status = InvoiceState.ToString(InvoiceStatus.Confirmed);
            }
            if (invoiceEvent.Name == InvoiceEvent.PaidInFull)
            {
                notification.Data.Status = InvoiceState.ToString(InvoiceStatus.Paid);
            }
            //////////////////

            // We keep backward compatibility with bitpay by passing BTC info to the notification
            // we don't pass other info, as it is a bad idea to use IPN data for logic processing (can be faked)
            var btcCryptoInfo = dto.CryptoInfo.FirstOrDefault(c => c.GetpaymentMethodId() == new PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike));

            if (btcCryptoInfo != null)
            {
#pragma warning disable CS0618
                notification.Data.Rate     = dto.Rate;
                notification.Data.Url      = dto.Url;
                notification.Data.BTCDue   = dto.BTCDue;
                notification.Data.BTCPaid  = dto.BTCPaid;
                notification.Data.BTCPrice = dto.BTCPrice;
#pragma warning restore CS0618
            }

            CancellationTokenSource cts = new CancellationTokenSource(10000);

            if (!String.IsNullOrEmpty(invoice.NotificationEmail))
            {
                var emailBody = NBitcoin.JsonConverters.Serializer.ToString(notification);

                _EmailSenderFactory.GetEmailSender(invoice.StoreId).SendEmail(
                    invoice.NotificationEmail,
                    $"BtcPayServer Invoice Notification - ${invoice.StoreId}",
                    emailBody);
            }
            if (string.IsNullOrEmpty(invoice.NotificationURL) || !Uri.IsWellFormedUriString(invoice.NotificationURL, UriKind.Absolute))
            {
                return;
            }
            var invoiceStr = NBitcoin.JsonConverters.Serializer.ToString(new ScheduledJob()
            {
                TryCount = 0, Notification = notification
            });
            if (!string.IsNullOrEmpty(invoice.NotificationURL))
            {
                _JobClient.Schedule(() => NotifyHttp(invoiceStr), TimeSpan.Zero);
            }
        }