mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Invoices has events recorded
This commit is contained in:
@@ -15,6 +15,7 @@ using BTCPayServer.Models.AccountViewModels;
|
|||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
using BTCPayServer.Services.Mails;
|
using BTCPayServer.Services.Mails;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
|
using BTCPayServer.Logging;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
@@ -25,10 +26,10 @@ namespace BTCPayServer.Controllers
|
|||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
private readonly IEmailSender _emailSender;
|
private readonly IEmailSender _emailSender;
|
||||||
private readonly ILogger _logger;
|
|
||||||
StoreRepository storeRepository;
|
StoreRepository storeRepository;
|
||||||
RoleManager<IdentityRole> _RoleManager;
|
RoleManager<IdentityRole> _RoleManager;
|
||||||
SettingsRepository _SettingsRepository;
|
SettingsRepository _SettingsRepository;
|
||||||
|
ILogger _logger;
|
||||||
|
|
||||||
public AccountController(
|
public AccountController(
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
@@ -36,16 +37,15 @@ namespace BTCPayServer.Controllers
|
|||||||
StoreRepository storeRepository,
|
StoreRepository storeRepository,
|
||||||
SignInManager<ApplicationUser> signInManager,
|
SignInManager<ApplicationUser> signInManager,
|
||||||
IEmailSender emailSender,
|
IEmailSender emailSender,
|
||||||
SettingsRepository settingsRepository,
|
SettingsRepository settingsRepository)
|
||||||
ILogger<AccountController> logger)
|
|
||||||
{
|
{
|
||||||
this.storeRepository = storeRepository;
|
this.storeRepository = storeRepository;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_emailSender = emailSender;
|
_emailSender = emailSender;
|
||||||
_logger = logger;
|
|
||||||
_RoleManager = roleManager;
|
_RoleManager = roleManager;
|
||||||
_SettingsRepository = settingsRepository;
|
_SettingsRepository = settingsRepository;
|
||||||
|
_logger = Logs.PayServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[TempData]
|
[TempData]
|
||||||
@@ -259,12 +259,10 @@ namespace BTCPayServer.Controllers
|
|||||||
var result = await _userManager.CreateAsync(user, model.Password);
|
var result = await _userManager.CreateAsync(user, model.Password);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("User created a new account with password.");
|
|
||||||
|
|
||||||
var admin = await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin);
|
var admin = await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin);
|
||||||
|
Logs.PayServer.LogInformation($"A new user just registered {user.Email} {(admin.Count == 0 ? "(admin)" : "")}");
|
||||||
if (admin.Count == 0)
|
if (admin.Count == 0)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Admin created.");
|
|
||||||
await _RoleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
|
await _RoleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
|
||||||
await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);
|
await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
UserId = GetUserId(),
|
UserId = GetUserId(),
|
||||||
InvoiceId = invoiceId,
|
InvoiceId = invoiceId,
|
||||||
IncludeAddresses = true
|
IncludeAddresses = true,
|
||||||
|
IncludeEvents = true
|
||||||
})).FirstOrDefault();
|
})).FirstOrDefault();
|
||||||
if (invoice == null)
|
if (invoice == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@@ -57,7 +58,8 @@ namespace BTCPayServer.Controllers
|
|||||||
NotificationUrl = invoice.NotificationURL,
|
NotificationUrl = invoice.NotificationURL,
|
||||||
RedirectUrl = invoice.RedirectURL,
|
RedirectUrl = invoice.RedirectURL,
|
||||||
ProductInformation = invoice.ProductInformation,
|
ProductInformation = invoice.ProductInformation,
|
||||||
StatusException = invoice.ExceptionStatus
|
StatusException = invoice.ExceptionStatus,
|
||||||
|
Events = invoice.Events
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var data in invoice.GetCryptoData(null))
|
foreach (var data in invoice.GetCryptoData(null))
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ namespace BTCPayServer.Data
|
|||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DbSet<InvoiceEventData> InvoiceEvents
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
public DbSet<HistoricalAddressInvoiceData> HistoricalAddressInvoices
|
public DbSet<HistoricalAddressInvoiceData> HistoricalAddressInvoices
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
@@ -132,6 +137,15 @@ namespace BTCPayServer.Data
|
|||||||
o.InvoiceDataId,
|
o.InvoiceDataId,
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
o.Address
|
o.Address
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<InvoiceEventData>()
|
||||||
|
.HasKey(o => new
|
||||||
|
{
|
||||||
|
o.InvoiceDataId,
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
o.UniqueId
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ namespace BTCPayServer.Data
|
|||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<InvoiceEventData> Events
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
public List<RefundAddressesData> RefundAddresses
|
public List<RefundAddressesData> RefundAddresses
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
|
|||||||
22
BTCPayServer/Data/InvoiceEventData.cs
Normal file
22
BTCPayServer/Data/InvoiceEventData.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Data
|
||||||
|
{
|
||||||
|
public class InvoiceEventData
|
||||||
|
{
|
||||||
|
public string InvoiceDataId
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
public string UniqueId { get; internal set; }
|
||||||
|
public DateTimeOffset Timestamp
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,10 +8,19 @@ namespace BTCPayServer.Events
|
|||||||
public class InvoiceDataChangedEvent
|
public class InvoiceDataChangedEvent
|
||||||
{
|
{
|
||||||
public string InvoiceId { get; set; }
|
public string InvoiceId { get; set; }
|
||||||
|
public string Status { get; internal set; }
|
||||||
|
public string ExceptionStatus { get; internal set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Invoice {InvoiceId} data changed";
|
if (string.IsNullOrEmpty(ExceptionStatus) || ExceptionStatus == "false")
|
||||||
|
{
|
||||||
|
return $"Invoice status is {Status}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $"Invoice status is {Status} (Exception status: {ExceptionStatus})";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,16 +9,20 @@ namespace BTCPayServer.Events
|
|||||||
public class InvoicePaymentEvent
|
public class InvoicePaymentEvent
|
||||||
{
|
{
|
||||||
|
|
||||||
public InvoicePaymentEvent(string invoiceId)
|
public InvoicePaymentEvent(string invoiceId, string cryptoCode, string address)
|
||||||
{
|
{
|
||||||
InvoiceId = invoiceId;
|
InvoiceId = invoiceId;
|
||||||
|
Address = address;
|
||||||
|
CryptoCode = cryptoCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Address { get; set; }
|
||||||
|
public string CryptoCode { get; private set; }
|
||||||
public string InvoiceId { get; set; }
|
public string InvoiceId { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Invoice {InvoiceId} received a payment";
|
return $"{CryptoCode}: Invoice {InvoiceId} received a payment on {Address}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,10 +184,27 @@ namespace BTCPayServer.HostedServices
|
|||||||
{
|
{
|
||||||
await Notify(invoice);
|
await Notify(invoice);
|
||||||
}
|
}
|
||||||
|
await SaveEvent(invoice.Id, e);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
leases.Add(_EventAggregator.Subscribe<InvoiceDataChangedEvent>(async e =>
|
||||||
|
{
|
||||||
|
await SaveEvent(e.InvoiceId, e);
|
||||||
|
}));
|
||||||
|
|
||||||
|
leases.Add(_EventAggregator.Subscribe<InvoicePaymentEvent>(async e =>
|
||||||
|
{
|
||||||
|
await SaveEvent(e.InvoiceId, e);
|
||||||
|
}));
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task SaveEvent(string invoiceId, object evt)
|
||||||
|
{
|
||||||
|
return _InvoiceRepository.AddInvoiceEvent(invoiceId, evt);
|
||||||
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
leases.Dispose();
|
leases.Dispose();
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace BTCPayServer.HostedServices
|
|||||||
if (updateContext.Dirty)
|
if (updateContext.Dirty)
|
||||||
{
|
{
|
||||||
await _InvoiceRepository.UpdateInvoiceStatus(invoice.Id, invoice.Status, invoice.ExceptionStatus).ConfigureAwait(false);
|
await _InvoiceRepository.UpdateInvoiceStatus(invoice.Id, invoice.Status, invoice.ExceptionStatus).ConfigureAwait(false);
|
||||||
_EventAggregator.Publish(new InvoiceDataChangedEvent() { InvoiceId = invoice.Id });
|
updateContext.Events.Add(new InvoiceDataChangedEvent() { Status = invoice.Status, ExceptionStatus = invoice.ExceptionStatus, InvoiceId = invoice.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
var changed = stateBefore != invoice.Status;
|
var changed = stateBefore != invoice.Status;
|
||||||
@@ -169,7 +169,7 @@ namespace BTCPayServer.HostedServices
|
|||||||
invoice.Payments.Add(payment);
|
invoice.Payments.Add(payment);
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
alreadyAccounted.Add(coin.Coin.Outpoint);
|
alreadyAccounted.Add(coin.Coin.Outpoint);
|
||||||
context.Events.Add(new InvoicePaymentEvent(invoice.Id));
|
context.Events.Add(new InvoicePaymentEvent(invoice.Id, coins.Wallet.Network.CryptoCode, coin.Coin.ScriptPubKey.GetDestinationAddress(coins.Wallet.Network.NBitcoinNetwork).ToString()));
|
||||||
dirtyAddress = true;
|
dirtyAddress = true;
|
||||||
}
|
}
|
||||||
if (dirtyAddress)
|
if (dirtyAddress)
|
||||||
|
|||||||
508
BTCPayServer/Migrations/20180114123253_events.Designer.cs
generated
Normal file
508
BTCPayServer/Migrations/20180114123253_events.Designer.cs
generated
Normal file
@@ -0,0 +1,508 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using BTCPayServer.Data;
|
||||||
|
using BTCPayServer.Services.Invoices;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20180114123253_events")]
|
||||||
|
partial class events
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.0.1-rtm-125");
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("CreatedTime");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceDataId");
|
||||||
|
|
||||||
|
b.HasKey("Address");
|
||||||
|
|
||||||
|
b.HasIndex("InvoiceDataId");
|
||||||
|
|
||||||
|
b.ToTable("AddressInvoices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.HistoricalAddressInvoiceData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("InvoiceDataId");
|
||||||
|
|
||||||
|
b.Property<string>("Address");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Assigned");
|
||||||
|
|
||||||
|
b.Property<string>("CryptoCode");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UnAssigned");
|
||||||
|
|
||||||
|
b.HasKey("InvoiceDataId", "Address");
|
||||||
|
|
||||||
|
b.ToTable("HistoricalAddressInvoices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<byte[]>("Blob");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created");
|
||||||
|
|
||||||
|
b.Property<string>("CustomerEmail");
|
||||||
|
|
||||||
|
b.Property<string>("ExceptionStatus");
|
||||||
|
|
||||||
|
b.Property<string>("ItemCode");
|
||||||
|
|
||||||
|
b.Property<string>("OrderId");
|
||||||
|
|
||||||
|
b.Property<string>("Status");
|
||||||
|
|
||||||
|
b.Property<string>("StoreDataId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("StoreDataId");
|
||||||
|
|
||||||
|
b.ToTable("Invoices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.InvoiceEventData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("InvoiceDataId");
|
||||||
|
|
||||||
|
b.Property<string>("UniqueId");
|
||||||
|
|
||||||
|
b.Property<string>("Message");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Timestamp");
|
||||||
|
|
||||||
|
b.HasKey("InvoiceDataId", "UniqueId");
|
||||||
|
|
||||||
|
b.ToTable("InvoiceEvents");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.PairedSINData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Facade");
|
||||||
|
|
||||||
|
b.Property<string>("Label");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("PairingTime");
|
||||||
|
|
||||||
|
b.Property<string>("SIN");
|
||||||
|
|
||||||
|
b.Property<string>("StoreDataId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SIN");
|
||||||
|
|
||||||
|
b.HasIndex("StoreDataId");
|
||||||
|
|
||||||
|
b.ToTable("PairedSINData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.PairingCodeData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateCreated");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Expiration");
|
||||||
|
|
||||||
|
b.Property<string>("Facade");
|
||||||
|
|
||||||
|
b.Property<string>("Label");
|
||||||
|
|
||||||
|
b.Property<string>("SIN");
|
||||||
|
|
||||||
|
b.Property<string>("StoreDataId");
|
||||||
|
|
||||||
|
b.Property<string>("TokenValue");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PairingCodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.PaymentData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Accounted");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Blob");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceDataId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("InvoiceDataId");
|
||||||
|
|
||||||
|
b.ToTable("Payments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.PendingInvoiceData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PendingInvoices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.RefundAddressesData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<byte[]>("Blob");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceDataId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("InvoiceDataId");
|
||||||
|
|
||||||
|
b.ToTable("RefundAddresses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.SettingData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Value");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.StoreData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("DefaultCrypto");
|
||||||
|
|
||||||
|
b.Property<string>("DerivationStrategies");
|
||||||
|
|
||||||
|
b.Property<string>("DerivationStrategy");
|
||||||
|
|
||||||
|
b.Property<int>("SpeedPolicy");
|
||||||
|
|
||||||
|
b.Property<byte[]>("StoreBlob");
|
||||||
|
|
||||||
|
b.Property<byte[]>("StoreCertificate");
|
||||||
|
|
||||||
|
b.Property<string>("StoreName");
|
||||||
|
|
||||||
|
b.Property<string>("StoreWebsite");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Stores");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.UserStore", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ApplicationUserId");
|
||||||
|
|
||||||
|
b.Property<string>("StoreDataId");
|
||||||
|
|
||||||
|
b.Property<string>("Role");
|
||||||
|
|
||||||
|
b.HasKey("ApplicationUserId", "StoreDataId");
|
||||||
|
|
||||||
|
b.HasIndex("StoreDataId");
|
||||||
|
|
||||||
|
b.ToTable("UserStore");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Models.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed");
|
||||||
|
|
||||||
|
b.Property<bool>("RequiresEmailConfirmation");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<string>("Value");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||||
|
.WithMany("AddressInvoices")
|
||||||
|
.HasForeignKey("InvoiceDataId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.HistoricalAddressInvoiceData", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Data.InvoiceData")
|
||||||
|
.WithMany("HistoricalAddressInvoices")
|
||||||
|
.HasForeignKey("InvoiceDataId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("StoreDataId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.InvoiceEventData", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Data.InvoiceData")
|
||||||
|
.WithMany("Events")
|
||||||
|
.HasForeignKey("InvoiceDataId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.PaymentData", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||||
|
.WithMany("Payments")
|
||||||
|
.HasForeignKey("InvoiceDataId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.RefundAddressesData", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||||
|
.WithMany("RefundAddresses")
|
||||||
|
.HasForeignKey("InvoiceDataId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.UserStore", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Models.ApplicationUser", "ApplicationUser")
|
||||||
|
.WithMany("UserStores")
|
||||||
|
.HasForeignKey("ApplicationUserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||||
|
.WithMany("UserStores")
|
||||||
|
.HasForeignKey("StoreDataId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("BTCPayServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
BTCPayServer/Migrations/20180114123253_events.cs
Normal file
38
BTCPayServer/Migrations/20180114123253_events.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Migrations
|
||||||
|
{
|
||||||
|
public partial class events : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "InvoiceEvents",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
InvoiceDataId = table.Column<string>(nullable: false),
|
||||||
|
UniqueId = table.Column<string>(nullable: false),
|
||||||
|
Message = table.Column<string>(nullable: true),
|
||||||
|
Timestamp = table.Column<DateTimeOffset>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_InvoiceEvents", x => new { x.InvoiceDataId, x.UniqueId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_InvoiceEvents_Invoices_InvoiceDataId",
|
||||||
|
column: x => x.InvoiceDataId,
|
||||||
|
principalTable: "Invoices",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "InvoiceEvents");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,6 +81,21 @@ namespace BTCPayServer.Migrations
|
|||||||
b.ToTable("Invoices");
|
b.ToTable("Invoices");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.InvoiceEventData", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("InvoiceDataId");
|
||||||
|
|
||||||
|
b.Property<string>("UniqueId");
|
||||||
|
|
||||||
|
b.Property<string>("Message");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Timestamp");
|
||||||
|
|
||||||
|
b.HasKey("InvoiceDataId", "UniqueId");
|
||||||
|
|
||||||
|
b.ToTable("InvoiceEvents");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("BTCPayServer.Data.PairedSINData", b =>
|
modelBuilder.Entity("BTCPayServer.Data.PairedSINData", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("Id")
|
b.Property<string>("Id")
|
||||||
@@ -407,6 +422,14 @@ namespace BTCPayServer.Migrations
|
|||||||
.HasForeignKey("StoreDataId");
|
.HasForeignKey("StoreDataId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BTCPayServer.Data.InvoiceEventData", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BTCPayServer.Data.InvoiceData")
|
||||||
|
.WithMany("Events")
|
||||||
|
.HasForeignKey("InvoiceDataId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("BTCPayServer.Data.PaymentData", b =>
|
modelBuilder.Entity("BTCPayServer.Data.PaymentData", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||||
|
|||||||
@@ -126,5 +126,6 @@ namespace BTCPayServer.Models.InvoicingModels
|
|||||||
}
|
}
|
||||||
public HistoricalAddressInvoiceData[] Addresses { get; set; }
|
public HistoricalAddressInvoiceData[] Addresses { get; set; }
|
||||||
public DateTimeOffset MonitoringDate { get; internal set; }
|
public DateTimeOffset MonitoringDate { get; internal set; }
|
||||||
|
public List<Data.InvoiceEventData> Events { get; internal set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
public bool ExtendedNotifications { get; set; }
|
public bool ExtendedNotifications { get; set; }
|
||||||
|
public List<InvoiceEventData> Events { get; internal set; }
|
||||||
|
|
||||||
public bool IsExpired()
|
public bool IsExpired()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -173,8 +173,11 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
invoiceEntity.SetCryptoData(currencyData);
|
invoiceEntity.SetCryptoData(currencyData);
|
||||||
invoice.Blob = ToBytes(invoiceEntity, network.NBitcoinNetwork);
|
invoice.Blob = ToBytes(invoiceEntity, network.NBitcoinNetwork);
|
||||||
|
|
||||||
context.AddressInvoices.Add(new AddressInvoiceData() {
|
context.AddressInvoices.Add(new AddressInvoiceData()
|
||||||
InvoiceDataId = invoiceId, CreatedTime = DateTimeOffset.UtcNow }
|
{
|
||||||
|
InvoiceDataId = invoiceId,
|
||||||
|
CreatedTime = DateTimeOffset.UtcNow
|
||||||
|
}
|
||||||
.SetHash(bitcoinAddress.ScriptPubKey.Hash, network.CryptoCode));
|
.SetHash(bitcoinAddress.ScriptPubKey.Hash, network.CryptoCode));
|
||||||
context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData()
|
context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData()
|
||||||
{
|
{
|
||||||
@@ -188,6 +191,21 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task AddInvoiceEvent(string invoiceId, object evt)
|
||||||
|
{
|
||||||
|
using (var context = _ContextFactory.CreateContext())
|
||||||
|
{
|
||||||
|
context.InvoiceEvents.Add(new InvoiceEventData()
|
||||||
|
{
|
||||||
|
InvoiceDataId = invoiceId,
|
||||||
|
Message = evt.ToString(),
|
||||||
|
Timestamp = DateTimeOffset.UtcNow,
|
||||||
|
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
|
||||||
|
});
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, string cryptoCode)
|
private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, string cryptoCode)
|
||||||
{
|
{
|
||||||
foreach (var address in entity.GetCryptoData(null))
|
foreach (var address in entity.GetCryptoData(null))
|
||||||
@@ -314,6 +332,10 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
{
|
{
|
||||||
entity.AvailableAddressHashes = invoice.AddressInvoices.Select(a => a.GetHash() + a.GetCryptoCode()).ToHashSet();
|
entity.AvailableAddressHashes = invoice.AddressInvoices.Select(a => a.GetHash() + a.GetCryptoCode()).ToHashSet();
|
||||||
}
|
}
|
||||||
|
if(invoice.Events != null)
|
||||||
|
{
|
||||||
|
entity.Events = invoice.Events.OrderBy(c => c.Timestamp).ToList();
|
||||||
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,8 +348,10 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
.Invoices
|
.Invoices
|
||||||
.Include(o => o.Payments)
|
.Include(o => o.Payments)
|
||||||
.Include(o => o.RefundAddresses);
|
.Include(o => o.RefundAddresses);
|
||||||
if(queryObject.IncludeAddresses)
|
if (queryObject.IncludeAddresses)
|
||||||
query = query.Include(o => o.HistoricalAddressInvoices).Include(o => o.AddressInvoices);
|
query = query.Include(o => o.HistoricalAddressInvoices).Include(o => o.AddressInvoices);
|
||||||
|
if (queryObject.IncludeEvents)
|
||||||
|
query = query.Include(o => o.Events);
|
||||||
if (!string.IsNullOrEmpty(queryObject.InvoiceId))
|
if (!string.IsNullOrEmpty(queryObject.InvoiceId))
|
||||||
{
|
{
|
||||||
query = query.Where(i => i.Id == queryObject.InvoiceId);
|
query = query.Where(i => i.Id == queryObject.InvoiceId);
|
||||||
@@ -536,5 +560,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
public bool IncludeAddresses { get; set; }
|
public bool IncludeAddresses { get; set; }
|
||||||
|
|
||||||
|
public bool IncludeEvents { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,5 +225,28 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h3>Events</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead class="thead-inverse">
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach(var evt in Model.Events)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@evt.Timestamp</td>
|
||||||
|
<td>@evt.Message</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user