Start using JSONB column instead of app side compressed data (#4574)

This commit is contained in:
Nicolas Dorier 2023-02-21 15:06:34 +09:00 committed by GitHub
parent 5c61de3ae9
commit 2bd8227e20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 669 additions and 300 deletions

View file

@ -1,7 +1,6 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Data.Data;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
@ -90,23 +89,23 @@ namespace BTCPayServer.Data
// some of the data models don't have OnModelCreating for now, commenting them
ApplicationUser.OnModelCreating(builder);
ApplicationUser.OnModelCreating(builder, Database);
AddressInvoiceData.OnModelCreating(builder);
APIKeyData.OnModelCreating(builder);
APIKeyData.OnModelCreating(builder, Database);
AppData.OnModelCreating(builder);
CustodianAccountData.OnModelCreating(builder);
CustodianAccountData.OnModelCreating(builder, Database);
//StoredFile.OnModelCreating(builder);
InvoiceEventData.OnModelCreating(builder);
InvoiceSearchData.OnModelCreating(builder);
InvoiceWebhookDeliveryData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder);
NotificationData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder, Database);
NotificationData.OnModelCreating(builder, Database);
//OffchainTransactionData.OnModelCreating(builder);
BTCPayServer.Data.PairedSINData.OnModelCreating(builder);
PairingCodeData.OnModelCreating(builder);
//PayjoinLock.OnModelCreating(builder);
PaymentRequestData.OnModelCreating(builder);
PaymentData.OnModelCreating(builder);
PaymentRequestData.OnModelCreating(builder, Database);
PaymentData.OnModelCreating(builder, Database);
PayoutData.OnModelCreating(builder);
PendingInvoiceData.OnModelCreating(builder);
//PlannedTransaction.OnModelCreating(builder);
@ -117,7 +116,7 @@ namespace BTCPayServer.Data
StoreWebhookData.OnModelCreating(builder);
StoreData.OnModelCreating(builder, Database);
U2FDevice.OnModelCreating(builder);
Fido2Credential.OnModelCreating(builder);
Fido2Credential.OnModelCreating(builder, Database);
BTCPayServer.Data.UserStore.OnModelCreating(builder);
//WalletData.OnModelCreating(builder);
WalletObjectData.OnModelCreating(builder, Database);
@ -125,14 +124,14 @@ namespace BTCPayServer.Data
#pragma warning disable CS0612 // Type or member is obsolete
WalletTransactionData.OnModelCreating(builder);
#pragma warning restore CS0612 // Type or member is obsolete
WebhookDeliveryData.OnModelCreating(builder);
LightningAddressData.OnModelCreating(builder);
PayoutProcessorData.OnModelCreating(builder);
//WebhookData.OnModelCreating(builder);
FormData.OnModelCreating(builder, Database);
WebhookDeliveryData.OnModelCreating(builder, Database);
LightningAddressData.OnModelCreating(builder, Database);
PayoutProcessorData.OnModelCreating(builder, Database);
WebhookData.OnModelCreating(builder, Database);
FormData.OnModelCreating(builder, Database);
if (Database.IsSqlite() && !_designTime)
if (Database.IsSqlite() && !_designTime)
{
// SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations
// here: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#query-limitations

View file

@ -1,9 +1,11 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class APIKeyData
public class APIKeyData : IHasBlob<APIKeyBlob>
{
[MaxLength(50)]
public string Id { get; set; }
@ -16,13 +18,15 @@ namespace BTCPayServer.Data
public APIKeyType Type { get; set; } = APIKeyType.Legacy;
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public StoreData StoreData { get; set; }
public ApplicationUser User { get; set; }
public string Label { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<APIKeyData>()
.HasOne(o => o.StoreData)
@ -36,6 +40,13 @@ namespace BTCPayServer.Data
builder.Entity<APIKeyData>()
.HasIndex(o => o.StoreId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<APIKeyData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}

View file

@ -2,11 +2,13 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data
{
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
public class ApplicationUser : IdentityUser, IHasBlob<UserBlob>
{
public bool RequiresEmailConfirmation { get; set; }
public List<StoredFile> StoredFiles { get; set; }
@ -20,15 +22,28 @@ namespace BTCPayServer.Data
public List<UserStore> UserStores { get; set; }
public List<Fido2Credential> Fido2Credentials { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public List<IdentityUserRole<string>> UserRoles { get; set; }
public static void OnModelCreating(ModelBuilder builder)
public static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<ApplicationUser>()
.HasMany<IdentityUserRole<string>>(user => user.UserRoles)
.WithOne().HasForeignKey(role => role.UserId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<ApplicationUser>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
public class UserBlob
{
public bool ShowInvoiceStatusChangeHint { get; set; }
}
}

View file

@ -1,11 +1,13 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data;
public class CustodianAccountData
public class CustodianAccountData : IHasBlob<JObject>
{
[Required]
[MaxLength(50)]
@ -24,19 +26,29 @@ public class CustodianAccountData
public string Name { get; set; }
[JsonIgnore]
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
[JsonIgnore]
public string Blob2 { get; set; }
[JsonIgnore]
public StoreData StoreData { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<CustodianAccountData>()
.HasOne(o => o.StoreData)
.WithMany(i => i.CustodianAccounts)
.HasForeignKey(i => i.StoreId).OnDelete(DeleteBehavior.Cascade);
builder.Entity<APIKeyData>()
builder.Entity<CustodianAccountData>()
.HasIndex(o => o.StoreId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<CustodianAccountData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}

View file

@ -2,10 +2,11 @@ using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class Fido2Credential
public class Fido2Credential : IHasBlobUntyped
{
public string Name { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
@ -14,6 +15,7 @@ namespace BTCPayServer.Data
public string ApplicationUserId { get; set; }
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public CredentialType Type { get; set; }
public enum CredentialType
{
@ -22,12 +24,18 @@ namespace BTCPayServer.Data
[Display(Name = "Lightning node (LNURL Auth)")]
LNURLAuth
}
public static void OnModelCreating(ModelBuilder builder)
public static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<Fido2Credential>()
.HasOne(o => o.ApplicationUser)
.WithMany(i => i.Fido2Credentials)
.HasForeignKey(i => i.ApplicationUserId).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<Fido2Credential>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
public ApplicationUser ApplicationUser { get; set; }

View file

@ -1,8 +1,8 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data.Data;
namespace BTCPayServer.Data;
public class FormData
{

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BTCPayServer.Data
{
public interface IHasBlob<T>
{
[Obsolete("Use Blob2 instead")]
byte[] Blob { get; set; }
string Blob2 { get; set; }
}
public interface IHasBlob
{
[Obsolete("Use Blob2 instead")]
byte[] Blob { get; set; }
string Blob2 { get; set; }
public Type Type { get; set; }
}
public interface IHasBlobUntyped
{
[Obsolete("Use Blob2 instead")]
byte[] Blob { get; set; }
string Blob2 { get; set; }
}
}

View file

@ -2,10 +2,11 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class InvoiceData
public class InvoiceData : IHasBlobUntyped
{
public string Id { get; set; }
@ -16,7 +17,9 @@ namespace BTCPayServer.Data
public List<PaymentData> Payments { get; set; }
public List<InvoiceEventData> Events { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public string ItemCode { get; set; }
public string OrderId { get; set; }
public string Status { get; set; }
@ -32,7 +35,7 @@ namespace BTCPayServer.Data
public RefundData CurrentRefund { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<InvoiceData>()
.HasOne(o => o.StoreData)
@ -42,6 +45,13 @@ namespace BTCPayServer.Data
builder.Entity<InvoiceData>()
.HasOne(o => o.CurrentRefund);
builder.Entity<InvoiceData>().HasIndex(o => o.Created);
if (databaseFacade.IsNpgsql())
{
builder.Entity<InvoiceData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
}

View file

@ -1,17 +1,21 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data;
public class LightningAddressData
public class LightningAddressData : IHasBlob<LightningAddressDataBlob>
{
public string Username { get; set; }
public string StoreDataId { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public StoreData Store { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<LightningAddressData>()
.HasOne(o => o.Store)
@ -20,6 +24,12 @@ public class LightningAddressData
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<LightningAddressData>().HasKey(o => o.Username);
if (databaseFacade.IsNpgsql())
{
builder.Entity<LightningAddressData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}

View file

@ -1,10 +1,12 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
namespace BTCPayServer.Data
{
public class NotificationData
public class NotificationData : IHasBlobUntyped
{
[MaxLength(36)]
public string Id { get; set; }
@ -17,14 +19,23 @@ namespace BTCPayServer.Data
[Required]
public string NotificationType { get; set; }
public bool Seen { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<NotificationData>()
.HasOne(o => o.ApplicationUser)
.WithMany(n => n.Notifications)
.HasForeignKey(k => k.ApplicationUserId).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<NotificationData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
}

View file

@ -1,24 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class PaymentData
public class PaymentData : IHasBlobUntyped
{
public string Id { get; set; }
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public string Type { get; set; }
public bool Accounted { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<PaymentData>()
.HasOne(o => o.InvoiceData)
.WithMany(i => i.Payments).OnDelete(DeleteBehavior.Cascade);
builder.Entity<PaymentData>()
.HasIndex(o => o.InvoiceDataId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PaymentData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
}

View file

@ -1,9 +1,10 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class PaymentRequestData
public class PaymentRequestData : IHasBlobUntyped
{
public string Id { get; set; }
public DateTimeOffset Created { get; set; }
@ -14,10 +15,12 @@ namespace BTCPayServer.Data
public Client.Models.PaymentRequestData.PaymentRequestStatus Status { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<PaymentRequestData>()
.HasOne(o => o.StoreData)
@ -28,6 +31,13 @@ namespace BTCPayServer.Data
.HasDefaultValue(new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero));
builder.Entity<PaymentRequestData>()
.HasIndex(o => o.Status);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PaymentRequestData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
}

View file

@ -1,9 +1,15 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data.Data;
namespace BTCPayServer.Data;
public class PayoutProcessorData
public class AutomatedPayoutBlob
{
public TimeSpan Interval { get; set; } = TimeSpan.FromHours(1);
}
public class PayoutProcessorData : IHasBlobUntyped
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
@ -12,14 +18,22 @@ public class PayoutProcessorData
public string PaymentMethod { get; set; }
public string Processor { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<PayoutProcessorData>()
.HasOne(o => o.Store)
.WithMany(data => data.PayoutProcessors).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PayoutProcessorData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
public override string ToString()

View file

@ -3,11 +3,10 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using BTCPayServer.Client.Models;
using BTCPayServer.Data.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData;
using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.Data
{

View file

@ -1,15 +1,29 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class WebhookData
public class WebhookData : IHasBlobUntyped
{
[Key]
[MaxLength(25)]
public string Id { get; set; }
[Required]
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public List<WebhookDeliveryData> Deliveries { get; set; }
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
if (databaseFacade.IsNpgsql())
{
builder.Entity<WebhookData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
}

View file

@ -1,10 +1,11 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class WebhookDeliveryData
public class WebhookDeliveryData : IHasBlobUntyped
{
[Key]
[MaxLength(25)]
@ -16,17 +17,24 @@ namespace BTCPayServer.Data
[Required]
public DateTimeOffset Timestamp { get; set; }
[Required]
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<WebhookDeliveryData>()
.HasOne(o => o.Webhook)
.WithMany(a => a.Deliveries).OnDelete(DeleteBehavior.Cascade);
builder.Entity<WebhookDeliveryData>().HasIndex(o => o.WebhookId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<WebhookDeliveryData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
}

View file

@ -0,0 +1,150 @@
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20230130040047_blob2")]
public partial class blob2 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
var type = migrationBuilder.IsNpgsql() ? "JSONB" : "TEXT";
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Webhooks",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "WebhookDeliveries",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "PaymentRequests",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Notifications",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "LightningAddresses",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Fido2Credentials",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "AspNetUsers",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "ApiKeys",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Invoices",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Payments",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "PayoutProcessors",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "CustodianAccount",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Type",
table: "Payments",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Blob2",
table: "Webhooks");
migrationBuilder.DropColumn(
name: "Blob2",
table: "WebhookDeliveries");
migrationBuilder.DropColumn(
name: "Blob2",
table: "PaymentRequests");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Notifications");
migrationBuilder.DropColumn(
name: "Blob2",
table: "LightningAddresses");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Fido2Credentials");
migrationBuilder.DropColumn(
name: "Blob2",
table: "AspNetUsers");
migrationBuilder.DropColumn(
name: "Blob2",
table: "ApiKeys");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Invoices");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Payments");
migrationBuilder.DropColumn(
name: "Blob2",
table: "PayoutProcessors");
migrationBuilder.DropColumn(
name: "Blob2",
table: "CustodianAccount");
migrationBuilder.DropColumn(
name: "Type",
table: "Payments");
}
}
}

View file

@ -45,6 +45,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("Label")
.HasColumnType("TEXT");
@ -109,6 +112,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
@ -183,6 +189,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("CustodianCode")
.IsRequired()
.HasMaxLength(50)
@ -205,7 +214,7 @@ namespace BTCPayServer.Migrations
b.ToTable("CustodianAccount");
});
modelBuilder.Entity("BTCPayServer.Data.Data.FormData", b =>
modelBuilder.Entity("BTCPayServer.Data.FormData", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
@ -230,7 +239,7 @@ namespace BTCPayServer.Migrations
b.ToTable("Forms");
});
modelBuilder.Entity("BTCPayServer.Data.Data.PayoutProcessorData", b =>
modelBuilder.Entity("BTCPayServer.Data.PayoutProcessorData", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
@ -267,6 +276,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
@ -291,6 +303,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Created")
.HasColumnType("TEXT");
@ -401,6 +416,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("StoreDataId")
.IsRequired()
.HasColumnType("TEXT");
@ -426,6 +444,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Created")
.HasColumnType("TEXT");
@ -537,9 +558,15 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("InvoiceDataId")
.HasColumnType("TEXT");
b.Property<string>("Type")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("InvoiceDataId");
@ -558,6 +585,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob")
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Created")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT")
@ -945,9 +975,11 @@ namespace BTCPayServer.Migrations
.HasColumnType("TEXT");
b.Property<byte[]>("Blob")
.IsRequired()
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Webhooks");
@ -960,9 +992,11 @@ namespace BTCPayServer.Migrations
.HasColumnType("TEXT");
b.Property<byte[]>("Blob")
.IsRequired()
.HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("TEXT");
@ -1154,7 +1188,7 @@ namespace BTCPayServer.Migrations
b.Navigation("StoreData");
});
modelBuilder.Entity("BTCPayServer.Data.Data.FormData", b =>
modelBuilder.Entity("BTCPayServer.Data.FormData", b =>
{
b.HasOne("BTCPayServer.Data.StoreData", "Store")
.WithMany("Forms")
@ -1164,7 +1198,7 @@ namespace BTCPayServer.Migrations
b.Navigation("Store");
});
modelBuilder.Entity("BTCPayServer.Data.Data.PayoutProcessorData", b =>
modelBuilder.Entity("BTCPayServer.Data.PayoutProcessorData", b =>
{
b.HasOne("BTCPayServer.Data.StoreData", "Store")
.WithMany("PayoutProcessors")

View file

@ -1696,7 +1696,9 @@ namespace BTCPayServer.Tests
var db = tester.PayTester.GetService<Data.ApplicationDbContextFactory>();
using var ctx = db.CreateContext();
var dbInvoice = await ctx.Invoices.FindAsync(oldInvoice.Id);
#pragma warning disable CS0618 // Type or member is obsolete
dbInvoice.Blob = ZipUtils.Zip(invoiceV1);
#pragma warning restore CS0618 // Type or member is obsolete
await ctx.SaveChangesAsync();
var newInvoice = await AssertInvoiceMetadata();
@ -1998,7 +2000,7 @@ namespace BTCPayServer.Tests
//get
var invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id);
Assert.Equal(newInvoice.Metadata, invoice.Metadata);
Assert.True(JObject.DeepEquals(newInvoice.Metadata, invoice.Metadata));
var paymentMethods = await viewOnly.GetInvoicePaymentMethods(user.StoreId, newInvoice.Id);
Assert.Single(paymentMethods);
var paymentMethod = paymentMethods.First();

View file

@ -11,6 +11,7 @@ using BTCPayServer.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using StoreData = BTCPayServer.Data.StoreData;
using PayoutProcessorData = BTCPayServer.Client.Models.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield
{

View file

@ -4,15 +4,14 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors;
using BTCPayServer.PayoutProcessors.Lightning;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData;
using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield
{
@ -55,7 +54,7 @@ namespace BTCPayServer.Controllers.Greenfield
return new LightningAutomatedPayoutSettings()
{
PaymentMethod = data.PaymentMethod,
IntervalSeconds = InvoiceRepository.FromBytes<AutomatedPayoutBlob>(data.Blob).Interval
IntervalSeconds = data.HasTypedBlob<AutomatedPayoutBlob>().GetBlob()!.Interval
};
}
@ -81,7 +80,7 @@ namespace BTCPayServer.Controllers.Greenfield
}))
.FirstOrDefault();
activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(FromModel(request));
activeProcessor.HasTypedBlob<AutomatedPayoutBlob>().SetBlob(FromModel(request));
activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = paymentMethod;
activeProcessor.Processor = LightningAutomatedPayoutSenderFactory.ProcessorName;

View file

@ -4,15 +4,14 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors;
using BTCPayServer.PayoutProcessors.OnChain;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData;
using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield
{
@ -87,7 +86,7 @@ namespace BTCPayServer.Controllers.Greenfield
}))
.FirstOrDefault();
activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(FromModel(request));
activeProcessor.HasTypedBlob<OnChainAutomatedPayoutBlob>().SetBlob(FromModel(request));
activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = paymentMethod;
activeProcessor.Processor = OnChainAutomatedPayoutSenderFactory.ProcessorName;

View file

@ -26,7 +26,9 @@ namespace BTCPayServer.Controllers.Greenfield
private LightningAddressData ToModel(BTCPayServer.Data.LightningAddressData data)
{
var blob = data.Blob.GetBlob<LightningAddressDataBlob>();
var blob = data.GetBlob();
if (blob is null)
return new LightningAddressData();
return new LightningAddressData()
{
Username = data.Username, Max = blob.Max, Min = blob.Min, CurrencyCode = blob.CurrencyCode
@ -79,12 +81,13 @@ namespace BTCPayServer.Controllers.Greenfield
if (await _lightningAddressService.Set(new Data.LightningAddressData()
{
StoreDataId = storeId,
Username = username,
Blob = new LightningAddressDataBlob()
{
Max = data.Max, Min = data.Min, CurrencyCode = data.CurrencyCode
}.SerializeBlob()
}))
Username = username
}.SetBlob(new LightningAddressDataBlob()
{
Max = data.Max,
Min = data.Min,
CurrencyCode = data.CurrencyCode
})))
{
return await GetStoreLightningAddress(storeId, username);
}

View file

@ -34,6 +34,7 @@ using PullPaymentData = BTCPayServer.Client.Models.PullPaymentData;
using StoreData = BTCPayServer.Client.Models.StoreData;
using StoreWebhookData = BTCPayServer.Client.Models.StoreWebhookData;
using WebhookDeliveryData = BTCPayServer.Client.Models.WebhookDeliveryData;
using PayoutProcessorData = BTCPayServer.Client.Models.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield
{

View file

@ -336,7 +336,7 @@ namespace BTCPayServer
return NotFound("Unknown username");
}
var blob = lightningAddressSettings.Blob.GetBlob<LightningAddressDataBlob>();
var blob = lightningAddressSettings.GetBlob();
return await GetLNURL("BTC", lightningAddressSettings.StoreDataId, blob.CurrencyCode, blob.Min, blob.Max,
() => (username, null, null, null, null, true));
}
@ -684,7 +684,7 @@ namespace BTCPayServer
{
Items = addresses.Select(s =>
{
var blob = s.Blob.GetBlob<LightningAddressDataBlob>();
var blob = s.GetBlob();
return new EditLightningAddressVM.EditLightningAddressItem
{
Max = blob.Max,
@ -722,14 +722,13 @@ namespace BTCPayServer
if (await _lightningAddressService.Set(new LightningAddressData()
{
StoreDataId = storeId,
Username = vm.Add.Username,
Blob = new LightningAddressDataBlob()
{
Max = vm.Add.Max,
Min = vm.Add.Min,
CurrencyCode = vm.Add.CurrencyCode
}.SerializeBlob()
}))
Username = vm.Add.Username
}.SetBlob(new LightningAddressDataBlob()
{
Max = vm.Add.Max,
Min = vm.Add.Min,
CurrencyCode = vm.Add.CurrencyCode
})))
{
TempData.SetStatusMessageModel(new StatusMessageModel
{

View file

@ -107,10 +107,8 @@ namespace BTCPayServer.Controllers
var blob = user.GetBlob();
blob.ShowInvoiceStatusChangeHint = false;
if (user.SetBlob(blob))
{
await _userManager.UpdateAsync(user);
}
user.SetBlob(blob);
await _userManager.UpdateAsync(user);
return RedirectToAction(nameof(Index));
}

View file

@ -1,37 +0,0 @@
using System.Linq;
using NBXplorer;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data
{
public static class APIKeyDataExtensions
{
public static APIKeyBlob GetBlob(this APIKeyData apiKeyData)
{
return GetBlob<APIKeyBlob>(apiKeyData.Blob);
}
public static bool SetBlob(this APIKeyData apiKeyData, APIKeyBlob blob)
{
var newBlob = SerializeBlob(blob);
if (apiKeyData?.Blob?.SequenceEqual(newBlob) is true)
return false;
apiKeyData.Blob = newBlob;
return true;
}
public static T GetBlob<T>(this byte[] data)
{
var result = data == null
? default
: JObject.Parse(ZipUtils.Unzip(data)).ToObject<T>();
return result;
}
public static byte[] SerializeBlob<T>(this T blob)
{
var newBlob = new Serializer(null).ToString(blob);
return ZipUtils.Zip(newBlob);
}
}
}

View file

@ -1,3 +1,4 @@
#nullable enable
using BTCPayServer.Services.Invoices;
using Newtonsoft.Json.Linq;
@ -7,19 +8,6 @@ public static class CustodianAccountDataExtensions
{
public static JObject GetBlob(this CustodianAccountData custodianAccountData)
{
var result = custodianAccountData.Blob == null
? new JObject()
: InvoiceRepository.FromBytes<JObject>(custodianAccountData.Blob);
return result;
}
public static bool SetBlob(this CustodianAccountData custodianAccountData, JObject blob)
{
var original = custodianAccountData.GetBlob();
if (JToken.DeepEquals(original, blob))
return false;
custodianAccountData.Blob = blob is null ? null : InvoiceRepository.ToBytes(blob);
return true;
return ((IHasBlob<JObject>)custodianAccountData).GetBlob() ?? new JObject();
}
}

View file

@ -0,0 +1,92 @@
#nullable enable
using System;
using System.Collections;
using System.Linq;
using System.Reflection.Metadata;
using NBXplorer;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data
{
public static class IHasBlobExtensions
{
static readonly JsonSerializerSettings DefaultSerializer;
static IHasBlobExtensions()
{
DefaultSerializer = new JsonSerializerSettings()
{
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
Formatting = Formatting.None
};
NBitcoin.JsonConverters.Serializer.RegisterFrontConverters(DefaultSerializer);
}
class HasBlobWrapper<B> : IHasBlob<B>
{
IHasBlobUntyped data;
public HasBlobWrapper(IHasBlobUntyped data)
{
this.data = data;
}
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get { return data.Blob; } set { data.Blob = value; } }
public string Blob2 { get { return data.Blob2; } set { data.Blob2 = value; } }
}
class HasBlobWrapper : IHasBlob
{
IHasBlobUntyped data;
private Type type;
public HasBlobWrapper(IHasBlobUntyped data, Type type)
{
this.data = data;
this.type = type;
}
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get => data.Blob; set => data.Blob = value; }
public string Blob2 { get => data.Blob2; set => data.Blob2 = value; }
public Type Type { get => type; set => type = value; }
}
public static IHasBlob<B> HasTypedBlob<B>(this IHasBlobUntyped data)
{
return new HasBlobWrapper<B>(data);
}
public static IHasBlob HasTypedBlob(this IHasBlobUntyped data, Type blobType)
{
return new HasBlobWrapper(data, blobType);
}
public static B? GetBlob<B>(this IHasBlob<B> data, JsonSerializerSettings? settings = null)
{
if (data.Blob2 is not null)
return JObject.Parse(data.Blob2).ToObject<B>(JsonSerializer.CreateDefault(settings ?? DefaultSerializer));
#pragma warning disable CS0618 // Type or member is obsolete
if (data.Blob is not null && data.Blob.Length != 0)
return JObject.Parse(ZipUtils.Unzip(data.Blob)).ToObject<B>();
#pragma warning restore CS0618 // Type or member is obsolete
return default;
}
public static object? GetBlob(this IHasBlob data, JsonSerializerSettings? settings = null)
{
if (data.Blob2 is not null)
return JObject.Parse(data.Blob2).ToObject(data.Type, JsonSerializer.CreateDefault(settings ?? DefaultSerializer));
#pragma warning disable CS0618 // Type or member is obsolete
if (data.Blob is not null && data.Blob.Length != 0)
return JObject.Parse(ZipUtils.Unzip(data.Blob)).ToObject(data.Type);
#pragma warning restore CS0618 // Type or member is obsolete
return default;
}
public static T SetBlob<T, B>(this T data, B blob, JsonSerializerSettings? settings = null) where T : IHasBlob<B>
{
if (blob is null)
data.Blob2 = null;
else
data.Blob2 = JObject.FromObject(blob, JsonSerializer.CreateDefault(settings ?? DefaultSerializer)).ToString(Formatting.None);
#pragma warning disable CS0618 // Type or member is obsolete
data.Blob = new byte[0];
#pragma warning restore CS0618 // Type or member is obsolete
return data;
}
}
}

View file

@ -1,26 +1,44 @@
using System.Reflection.Metadata;
using BTCPayServer.Services.Invoices;
using Newtonsoft.Json;
namespace BTCPayServer.Data
{
public static class InvoiceDataExtensions
{
public static void SetBlob(this InvoiceData invoiceData, InvoiceEntity blob)
{
if (blob.Metadata is null)
blob.Metadata = new InvoiceMetadata();
invoiceData.HasTypedBlob<InvoiceEntity>().SetBlob(blob);
}
public static InvoiceEntity GetBlob(this InvoiceData invoiceData, BTCPayNetworkProvider networks)
{
var entity = InvoiceRepository.FromBytes<InvoiceEntity>(invoiceData.Blob);
entity.Networks = networks;
if (entity.Metadata is null)
#pragma warning disable CS0618 // Type or member is obsolete
if (invoiceData.Blob is not null && invoiceData.Blob.Length != 0)
{
if (entity.Version < InvoiceEntity.GreenfieldInvoices_Version)
var entity = JsonConvert.DeserializeObject<InvoiceEntity>(ZipUtils.Unzip(invoiceData.Blob), InvoiceRepository.DefaultSerializerSettings);
entity.Networks = networks;
if (entity.Metadata is null)
{
entity.MigrateLegacyInvoice();
}
else
{
entity.Metadata = new InvoiceMetadata();
if (entity.Version < InvoiceEntity.GreenfieldInvoices_Version)
{
entity.MigrateLegacyInvoice();
}
else
{
entity.Metadata = new InvoiceMetadata();
}
}
return entity;
}
return entity;
else
{
var entity = invoiceData.HasTypedBlob<InvoiceEntity>().GetBlob();
entity.Networks = networks;
return entity;
}
#pragma warning restore CS0618 // Type or member is obsolete
}
public static InvoiceState GetInvoiceState(this InvoiceData invoiceData)
{

View file

@ -1,4 +1,5 @@
using System.Runtime.InteropServices;
using BTCPayServer.Payments;
using BTCPayServer.Services.Invoices;
using Newtonsoft.Json.Linq;
@ -6,25 +7,48 @@ namespace BTCPayServer.Data
{
public static class PaymentDataExtensions
{
public static void SetBlob(this PaymentData paymentData, PaymentEntity entity)
{
paymentData.Type = entity.GetPaymentMethodId().ToStringNormalized();
paymentData.Blob2 = entity.Network.ToString(entity);
}
public static PaymentEntity GetBlob(this PaymentData paymentData, BTCPayNetworkProvider networks)
{
var unziped = ZipUtils.Unzip(paymentData.Blob);
var cryptoCode = "BTC";
if (JObject.Parse(unziped).TryGetValue("cryptoCode", out var v) && v.Type == JTokenType.String)
cryptoCode = v.Value<string>();
var network = networks.GetNetwork<BTCPayNetworkBase>(cryptoCode);
PaymentEntity paymentEntity = null;
if (network == null)
#pragma warning disable CS0618 // Type or member is obsolete
if (paymentData.Blob is not null && paymentData.Blob.Length != 0)
{
return null;
var unziped = ZipUtils.Unzip(paymentData.Blob);
var cryptoCode = "BTC";
if (JObject.Parse(unziped).TryGetValue("cryptoCode", out var v) && v.Type == JTokenType.String)
cryptoCode = v.Value<string>();
var network = networks.GetNetwork<BTCPayNetworkBase>(cryptoCode);
PaymentEntity paymentEntity = null;
if (network == null)
{
return null;
}
else
{
paymentEntity = network.ToObject<PaymentEntity>(unziped);
}
paymentEntity.Network = network;
paymentEntity.Accounted = paymentData.Accounted;
return paymentEntity;
}
else
#pragma warning restore CS0618 // Type or member is obsolete
if (paymentData.Blob2 is not null)
{
paymentEntity = network.ToObject<PaymentEntity>(unziped);
if (!PaymentMethodId.TryParse(paymentData.Type, out var pmi))
return null;
var network = networks.GetNetwork<BTCPayNetworkBase>(pmi.CryptoCode);
if (network is null)
return null;
var entity = network.ToObject<PaymentEntity>(paymentData.Blob2);
entity.Network = network;
entity.Accounted = paymentData.Accounted;
return entity;
}
paymentEntity.Network = network;
paymentEntity.Accounted = paymentData.Accounted;
return paymentEntity;
return null;
}
}
}

View file

@ -9,13 +9,20 @@ namespace BTCPayServer.Data
{
public static PaymentRequestBaseData GetBlob(this PaymentRequestData paymentRequestData)
{
var result = paymentRequestData.Blob == null
? new PaymentRequestBaseData()
: ParseBlob(paymentRequestData.Blob);
return result;
if (paymentRequestData.Blob2 is not null)
{
return paymentRequestData.HasTypedBlob<PaymentRequestBaseData>().GetBlob();
}
#pragma warning disable CS0618 // Type or member is obsolete
else if (paymentRequestData.Blob is not null)
{
return ParseBlob(paymentRequestData.Blob);
}
#pragma warning restore CS0618 // Type or member is obsolete
return new PaymentRequestBaseData();
}
private static PaymentRequestBaseData ParseBlob(byte[] blob)
static PaymentRequestBaseData ParseBlob(byte[] blob)
{
var jobj = JObject.Parse(ZipUtils.Unzip(blob));
// Fixup some legacy payment requests
@ -24,14 +31,9 @@ namespace BTCPayServer.Data
return jobj.ToObject<PaymentRequestBaseData>();
}
public static bool SetBlob(this PaymentRequestData paymentRequestData, PaymentRequestBaseData blob)
public static void SetBlob(this PaymentRequestData paymentRequestData, PaymentRequestBaseData blob)
{
var original = new Serializer(null).ToString(paymentRequestData.GetBlob());
var newBlob = new Serializer(null).ToString(blob);
if (original == newBlob)
return false;
paymentRequestData.Blob = ZipUtils.Zip(newBlob);
return true;
paymentRequestData.HasTypedBlob<PaymentRequestBaseData>().SetBlob(blob);
}
}
}

View file

@ -48,19 +48,19 @@ namespace BTCPayServer.Data
{
public static WebhookBlob GetBlob(this WebhookData webhook)
{
return JsonConvert.DeserializeObject<WebhookBlob>(Encoding.UTF8.GetString(webhook.Blob));
return webhook.HasTypedBlob<WebhookBlob>().GetBlob();
}
public static void SetBlob(this WebhookData webhook, WebhookBlob blob)
{
webhook.Blob = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(blob));
webhook.HasTypedBlob<WebhookBlob>().SetBlob(blob);
}
public static WebhookDeliveryBlob GetBlob(this WebhookDeliveryData webhook)
{
return JsonConvert.DeserializeObject<WebhookDeliveryBlob>(ZipUtils.Unzip(webhook.Blob), HostedServices.WebhookSender.DefaultSerializerSettings);
return webhook.HasTypedBlob<WebhookDeliveryBlob>().GetBlob(HostedServices.WebhookSender.DefaultSerializerSettings);
}
public static void SetBlob(this WebhookDeliveryData webhook, WebhookDeliveryBlob blob)
{
webhook.Blob = ZipUtils.Zip(JsonConvert.SerializeObject(blob, Formatting.None, HostedServices.WebhookSender.DefaultSerializerSettings));
webhook.HasTypedBlob<WebhookDeliveryBlob>().SetBlob(blob, HostedServices.WebhookSender.DefaultSerializerSettings);
}
}
}

View file

@ -17,27 +17,5 @@ namespace BTCPayServer
name = String.Empty;
return new MimeKit.MailboxAddress(name, user.Email);
}
public static UserBlob GetBlob(this ApplicationUser user)
{
var result = user.Blob == null
? new UserBlob()
: JObject.Parse(ZipUtils.Unzip(user.Blob)).ToObject<UserBlob>();
return result;
}
public static bool SetBlob(this ApplicationUser user, UserBlob blob)
{
var newBytes = InvoiceRepository.ToBytes(blob);
if (user.Blob != null && newBytes.SequenceEqual(user.Blob))
{
return false;
}
user.Blob = newBytes;
return true;
}
}
public class UserBlob
{
public bool ShowInvoiceStatusChangeHint { get; set; }
}
}

View file

@ -9,23 +9,17 @@ namespace BTCPayServer.Fido2
{
public static Fido2CredentialBlob GetFido2Blob(this Fido2Credential credential)
{
var result = credential.Blob == null
? new Fido2CredentialBlob()
: JObject.Parse(ZipUtils.Unzip(credential.Blob)).ToObject<Fido2CredentialBlob>();
return result;
return credential.HasTypedBlob<Fido2CredentialBlob>().GetBlob() ?? new Fido2CredentialBlob();
}
public static bool SetBlob(this Fido2Credential credential, Fido2CredentialBlob descriptor)
public static void SetBlob(this Fido2Credential credential, Fido2CredentialBlob descriptor)
{
var original = new Serializer(null).ToString(credential.GetFido2Blob());
var newBlob = new Serializer(null).ToString(descriptor);
if (original == newBlob)
return false;
var current = credential.GetFido2Blob();
var a = JObject.FromObject(current);
var b = JObject.FromObject(descriptor);
if (JObject.DeepEquals(a, b))
return;
credential.Type = Fido2Credential.CredentialType.FIDO2;
credential.Blob = ZipUtils.Zip(newBlob);
return true;
credential.HasTypedBlob<Fido2CredentialBlob>().SetBlob(descriptor);
}
}
}

View file

@ -1,5 +1,5 @@
using BTCPayServer.Abstractions.Form;
using BTCPayServer.Data.Data;
using BTCPayServer.Abstractions.Form;
using BTCPayServer.Data;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

View file

@ -9,7 +9,6 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Form;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Models;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Http;

View file

@ -11,7 +11,6 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Forms.Models;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization;

View file

@ -318,7 +318,7 @@ namespace BTCPayServer.HostedServices
var sig = Encoders.Hex.EncodeData(hmac.ComputeHash(bytes));
content.Headers.Add("BTCPay-Sig", $"sha256={sig}");
request.Content = content;
var deliveryBlob = ctx.Delivery.Blob is null ? new WebhookDeliveryBlob() : ctx.Delivery.GetBlob();
var deliveryBlob = ctx.Delivery.GetBlob() ?? new WebhookDeliveryBlob();
deliveryBlob.Request = bytes;
try
{

View file

@ -358,14 +358,14 @@ namespace BTCPayServer.Hosting
new LightningAddressData()
{
StoreDataId = storeMap.Key,
Username = storeitem,
Blob = new LightningAddressDataBlob()
{
Max = val.Max,
Min = val.Min,
CurrencyCode = val.CurrencyCode
}.SerializeBlob()
}, ctx);
Username = storeitem
}
.SetBlob(new LightningAddressDataBlob()
{
Max = val.Max,
Min = val.Min,
CurrencyCode = val.CurrencyCode
}), ctx);
}
}
}

View file

@ -4,16 +4,14 @@ using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Stores;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PayoutData = BTCPayServer.Data.PayoutData;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData;
using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.PayoutProcessors;
@ -79,9 +77,8 @@ public abstract class BaseAutomatedPayoutProcessor<T> : BaseAsyncService where T
await Task.Delay(blob.Interval, CancellationToken);
}
public static T GetBlob(PayoutProcessorData data)
public static T GetBlob(PayoutProcessorData payoutProcesserSettings)
{
return InvoiceRepository.FromBytes<T>(data.Blob);
return payoutProcesserSettings.HasTypedBlob<T>().GetBlob();
}
}

View file

@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;

View file

@ -5,13 +5,11 @@ using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Configuration;
using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Data.Payouts.LightningLike;
using BTCPayServer.HostedServices;
using BTCPayServer.Lightning;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services;
using BTCPayServer.Services.Stores;
using LNURL;
@ -19,7 +17,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using PayoutData = BTCPayServer.Data.PayoutData;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData;
using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.PayoutProcessors.Lightning;

View file

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

View file

@ -6,10 +6,9 @@ using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client;
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.OnChain;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@ -90,7 +89,7 @@ public class UILightningAutomatedPayoutProcessorsController : Controller
}))
.FirstOrDefault();
activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(automatedTransferBlob.ToBlob());
activeProcessor.HasTypedBlob<AutomatedPayoutBlob>().SetBlob(automatedTransferBlob.ToBlob());
activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = new PaymentMethodId(cryptoCode, LightningPaymentType.Instance).ToString();
activeProcessor.Processor = _lightningAutomatedPayoutSenderFactory.Processor;

View file

@ -1,4 +1,4 @@
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Data;
namespace BTCPayServer.PayoutProcessors.OnChain;

View file

@ -5,11 +5,9 @@ using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Events;
using BTCPayServer.HostedServices;
using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services;
using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets;
@ -19,7 +17,7 @@ using NBitcoin;
using NBXplorer;
using NBXplorer.DerivationStrategy;
using PayoutData = BTCPayServer.Data.PayoutData;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData;
using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.PayoutProcessors.OnChain
{

View file

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Payments;
using Microsoft.AspNetCore.Http;

View file

@ -6,9 +6,8 @@ using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client;
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@ -103,7 +102,7 @@ public class UIOnChainAutomatedPayoutProcessorsController : Controller
}))
.FirstOrDefault();
activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(automatedTransferBlob.ToBlob());
activeProcessor.HasTypedBlob<OnChainAutomatedPayoutBlob>().SetBlob(automatedTransferBlob.ToBlob());
activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = new PaymentMethodId(cryptoCode, BitcoinPaymentType.Instance).ToString();
activeProcessor.Processor = _onChainAutomatedPayoutSenderFactory.Processor;

View file

@ -4,7 +4,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Logging;
using Microsoft.EntityFrameworkCore;

View file

@ -1,4 +1,4 @@
using BTCPayServer.Data.Data;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Lightning;
using BTCPayServer.PayoutProcessors.OnChain;

View file

@ -1,8 +0,0 @@
using System;
namespace BTCPayServer.PayoutProcessors.Settings;
public class AutomatedPayoutBlob
{
public TimeSpan Interval { get; set; } = TimeSpan.FromHours(1);
}

View file

@ -6,7 +6,6 @@ using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client;
using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Payments;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

View file

@ -68,7 +68,7 @@ namespace BTCPayServer.Security.Greenfield
claims.Add(new Claim(_identityOptions.CurrentValue.ClaimsIdentity.UserIdClaimType, key.UserId));
claims.AddRange((await _userManager.GetRolesAsync(key.User)).Select(s => new Claim(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s)));
claims.AddRange(Permission.ToPermissions(key.GetBlob().Permissions).Select(permission =>
claims.AddRange(Permission.ToPermissions(key.GetBlob()?.Permissions ?? Array.Empty<string>()).Select(permission =>
new Claim(GreenfieldConstants.ClaimTypes.Permission, permission.ToString())));
return AuthenticateResult.Success(new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(claims, GreenfieldConstants.AuthenticationType)),

View file

@ -1274,7 +1274,6 @@ namespace BTCPayServer.Services.Invoices
if (string.IsNullOrEmpty(CryptoPaymentDataType))
{
paymentType = BitcoinPaymentType.Instance;
;
}
else if (!PaymentTypes.TryParse(CryptoPaymentDataType, out paymentType))
{

View file

@ -22,7 +22,7 @@ namespace BTCPayServer.Services.Invoices
{
public class InvoiceRepository
{
static JsonSerializerSettings DefaultSerializerSettings;
internal static JsonSerializerSettings DefaultSerializerSettings;
static InvoiceRepository()
{
DefaultSerializerSettings = new JsonSerializerSettings();
@ -147,7 +147,7 @@ namespace BTCPayServer.Services.Invoices
var expiry = DateTimeOffset.Now + seconds;
invoice.ExpirationTime = expiry;
invoice.MonitoringExpiration = expiry.AddHours(1);
invoiceData.Blob = ToBytes(invoice, _btcPayNetworkProvider.DefaultNetwork);
invoiceData.SetBlob(invoice);
await ctx.SaveChangesAsync();
@ -168,8 +168,7 @@ namespace BTCPayServer.Services.Invoices
var invoice = invoiceData.GetBlob(_btcPayNetworkProvider);
invoice.MonitoringExpiration = invoice.MonitoringExpiration.AddHours(1);
invoiceData.Blob = ToBytes(invoice, null);
invoiceData.SetBlob(invoice);
await ctx.SaveChangesAsync();
}
@ -190,7 +189,6 @@ namespace BTCPayServer.Services.Invoices
StoreDataId = storeId,
Id = invoice.Id,
Created = invoice.InvoiceTime,
Blob = ToBytes(invoice, null),
OrderId = invoice.Metadata.OrderId,
#pragma warning disable CS0618 // Type or member is obsolete
Status = invoice.StatusString,
@ -199,6 +197,7 @@ namespace BTCPayServer.Services.Invoices
CustomerEmail = invoice.RefundMail,
Archived = false
};
invoiceData.SetBlob(invoice);
await context.Invoices.AddAsync(invoiceData);
@ -247,7 +246,7 @@ namespace BTCPayServer.Services.Invoices
private InvoiceEntity Clone(InvoiceEntity invoice)
{
var temp = new InvoiceData();
temp.Blob = ToBytes(invoice);
temp.SetBlob(invoice);
return temp.GetBlob(_btcPayNetworkProvider);
}
@ -307,7 +306,7 @@ namespace BTCPayServer.Services.Invoices
}
#pragma warning restore CS0618
invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = ToBytes(invoiceEntity, network);
invoice.SetBlob(invoiceEntity);
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
{
@ -341,7 +340,7 @@ namespace BTCPayServer.Services.Invoices
.Set(GetDestination(paymentMethod), paymentMethod.GetId()));
}
invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = ToBytes(invoiceEntity, network);
invoice.SetBlob(invoiceEntity);
AddToTextSearch(context, invoice, paymentMethod.GetPaymentMethodDetails().GetPaymentDestination());
await context.SaveChangesAsync();
}
@ -416,7 +415,7 @@ namespace BTCPayServer.Services.Invoices
var blob = invoiceData.GetBlob(_btcPayNetworkProvider);
blob.Price = invoice.Price;
AddToTextSearch(context, invoiceData, new[] { invoice.Price.ToString(CultureInfo.InvariantCulture) });
invoiceData.Blob = ToBytes(blob, null);
invoiceData.SetBlob(blob);
await context.SaveChangesAsync().ConfigureAwait(false);
}
@ -478,7 +477,7 @@ namespace BTCPayServer.Services.Invoices
}
blob.Metadata = newMetadata;
invoiceData.Blob = ToBytes(blob);
invoiceData.SetBlob(blob);
await context.SaveChangesAsync().ConfigureAwait(false);
return ToEntity(invoiceData);
}
@ -770,22 +769,12 @@ namespace BTCPayServer.Services.Invoices
return status;
}
public static byte[] ToBytes<T>(T obj, BTCPayNetworkBase network = null)
{
return ZipUtils.Zip(ToJsonString(obj, network));
}
public static T FromBytes<T>(byte[] blob, BTCPayNetworkBase network = null)
{
return network == null
? JsonConvert.DeserializeObject<T>(ZipUtils.Unzip(blob), DefaultSerializerSettings)
: network.ToObject<T>(ZipUtils.Unzip(blob));
}
public static string ToJsonString<T>(T data, BTCPayNetworkBase network)
{
return network == null ? JsonConvert.SerializeObject(data, DefaultSerializerSettings) : network.ToString(data);
}
}
public class InvoiceQuery

View file

@ -65,16 +65,15 @@ namespace BTCPayServer.Services.Invoices
bitcoinPaymentMethod.NextNetworkFee = bitcoinPaymentMethod.NetworkFeeRate.GetFee(100); // assume price for 100 bytes
paymentMethod.SetPaymentMethodDetails(bitcoinPaymentMethod);
invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = InvoiceRepository.ToBytes(invoiceEntity, network);
invoice.SetBlob(invoiceEntity);
}
PaymentData data = new PaymentData
{
Id = paymentData.GetPaymentId(),
Blob = InvoiceRepository.ToBytes(entity, entity.Network),
InvoiceDataId = invoiceId,
Accounted = accounted
};
data.SetBlob(entity);
await context.Payments.AddAsync(data);
InvoiceRepository.AddToTextSearch(context, invoice, paymentData.GetSearchTerms());
@ -123,7 +122,7 @@ namespace BTCPayServer.Services.Invoices
}
dbPayment.Accounted = payment.Value.entity.Accounted;
dbPayment.Blob = InvoiceRepository.ToBytes(payment.Value.entity, payment.Value.entity.Network);
dbPayment.SetBlob(payment.Value.entity);
}
await context.SaveChangesAsync().ConfigureAwait(false);
eventsToSend.ForEach(_eventAggregator.Publish);

View file

@ -154,15 +154,15 @@ namespace BTCPayServer.Services.Notifications
var handler = GetHandler(data.NotificationType);
if (handler is null)
return null;
var notification = JsonConvert.DeserializeObject(ZipUtils.Unzip(data.Blob), handler.NotificationBlobType);
var obj = new NotificationViewModel
{
Id = data.Id,
Type = data.NotificationType,
Created = data.Created,
Seen = data.Seen
};
handler.FillViewModel(notification, obj);
var notification = data.HasTypedBlob(handler.NotificationBlobType).GetBlob();
var obj = new NotificationViewModel
{
Id = data.Id,
Type = data.NotificationType,
Created = data.Created,
Seen = data.Seen
};
handler.FillViewModel(notification, obj);
return obj;
}

View file

@ -40,16 +40,15 @@ namespace BTCPayServer.Services.Notifications
{
foreach (var uid in users)
{
var obj = JsonConvert.SerializeObject(notification);
var data = new NotificationData
{
Id = Guid.NewGuid().ToString(),
Created = DateTimeOffset.UtcNow,
ApplicationUserId = uid,
NotificationType = notification.NotificationType,
Blob = ZipUtils.Zip(obj),
Seen = false
};
data.HasTypedBlob<BaseNotification>().SetBlob(notification);
await db.Notifications.AddAsync(data);
}
await db.SaveChangesAsync();

View file

@ -1,6 +1,6 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Abstractions.Models
@model List<BTCPayServer.Data.Data.FormData>
@model List<BTCPayServer.Data.FormData>
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData["NavPartialName"] = "../UIStores/_Nav";

View file

@ -1,7 +1,7 @@
@inject UserManager<ApplicationUser> _userManager
@inject UserManager<ApplicationUser> _userManager
@* This is a temporary infobox to inform users about the state changes in 1.4.0. It should be removed eventually. *@
@if ((await _userManager.GetUserAsync(User)).GetBlob().ShowInvoiceStatusChangeHint)
@if ((await _userManager.GetUserAsync(User)).GetBlob()?.ShowInvoiceStatusChangeHint is true)
{
<div class="alert alert-light alert-dismissible fade show mb-5" role="alert">
<form method="post" asp-controller="UIManage" asp-action="DisableShowInvoiceStatusChangeHint" id="invoicestatuschangeform">