mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 14:22:40 +01:00
Migrate payment requests (#6260)
This commit is contained in:
parent
82620ee327
commit
4a31cf0a09
5 changed files with 103 additions and 21 deletions
39
BTCPayServer.Data/Data/PaymentRequestData.Migration.cs
Normal file
39
BTCPayServer.Data/Data/PaymentRequestData.Migration.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Data
|
||||||
|
{
|
||||||
|
public partial class PaymentRequestData : MigrationInterceptor.IHasMigration
|
||||||
|
{
|
||||||
|
[NotMapped]
|
||||||
|
public bool Migrated { get; set; }
|
||||||
|
|
||||||
|
public bool TryMigrate()
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
if (Blob is null && Blob2 is not null)
|
||||||
|
return false;
|
||||||
|
if (Blob2 is null)
|
||||||
|
{
|
||||||
|
Blob2 = Blob is not (null or { Length: 0 }) ? MigrationExtensions.Unzip(Blob) : "{}";
|
||||||
|
Blob2 = MigrationExtensions.SanitizeJSON(Blob2);
|
||||||
|
}
|
||||||
|
Blob = null;
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
var jobj = JObject.Parse(Blob2);
|
||||||
|
// Fixup some legacy payment requests
|
||||||
|
if (jobj["expiryDate"].Type == JTokenType.Date)
|
||||||
|
{
|
||||||
|
jobj["expiryDate"] = new JValue(NBitcoin.Utils.DateTimeToUnixTime(jobj["expiryDate"].Value<DateTime>()));
|
||||||
|
Blob2 = jobj.ToString(Newtonsoft.Json.Formatting.None);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
|
||||||
namespace BTCPayServer.Data
|
namespace BTCPayServer.Data
|
||||||
{
|
{
|
||||||
public class PaymentRequestData : IHasBlobUntyped
|
public partial class PaymentRequestData : IHasBlobUntyped
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public DateTimeOffset Created { get; set; }
|
public DateTimeOffset Created { get; set; }
|
||||||
|
|
|
@ -9,26 +9,7 @@ namespace BTCPayServer.Data
|
||||||
{
|
{
|
||||||
public static PaymentRequestBaseData GetBlob(this PaymentRequestData paymentRequestData)
|
public static PaymentRequestBaseData GetBlob(this PaymentRequestData paymentRequestData)
|
||||||
{
|
{
|
||||||
if (paymentRequestData.Blob2 is not null)
|
return paymentRequestData.HasTypedBlob<PaymentRequestBaseData>().GetBlob() ?? new PaymentRequestBaseData();
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
static PaymentRequestBaseData ParseBlob(byte[] blob)
|
|
||||||
{
|
|
||||||
var jobj = JObject.Parse(ZipUtils.Unzip(blob));
|
|
||||||
// Fixup some legacy payment requests
|
|
||||||
if (jobj["expiryDate"].Type == JTokenType.Date)
|
|
||||||
jobj["expiryDate"] = new JValue(NBitcoin.Utils.DateTimeToUnixTime(jobj["expiryDate"].Value<DateTime>()));
|
|
||||||
return jobj.ToObject<PaymentRequestBaseData>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetBlob(this PaymentRequestData paymentRequestData, PaymentRequestBaseData blob)
|
public static void SetBlob(this PaymentRequestData paymentRequestData, PaymentRequestBaseData blob)
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Abstractions.Contracts;
|
||||||
|
using BTCPayServer.Data;
|
||||||
|
using BTCPayServer.Migrations;
|
||||||
|
using BTCPayServer.Services.Invoices;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace BTCPayServer.HostedServices
|
||||||
|
{
|
||||||
|
public class PaymentRequestsMigratorHostedService : BlobMigratorHostedService<PaymentRequestData>
|
||||||
|
{
|
||||||
|
public PaymentRequestsMigratorHostedService(
|
||||||
|
ILogger<PaymentRequestsMigratorHostedService> logs,
|
||||||
|
ISettingsRepository settingsRepository,
|
||||||
|
ApplicationDbContextFactory applicationDbContextFactory) : base(logs, settingsRepository, applicationDbContextFactory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public override string SettingsKey => "PaymentRequestsMigration";
|
||||||
|
|
||||||
|
protected override IQueryable<PaymentRequestData> GetQuery(ApplicationDbContext ctx, DateTimeOffset? progress)
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
var query = progress is DateTimeOffset last2 ?
|
||||||
|
ctx.PaymentRequests.Where(i => i.Created < last2 && !(i.Blob == null && i.Blob2 != null)) :
|
||||||
|
ctx.PaymentRequests.Where(i => !(i.Blob == null && i.Blob2 != null));
|
||||||
|
return query.OrderByDescending(i => i.Created);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task PostMigrationCleanup(ApplicationDbContext ctx, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Logs.LogInformation("Post-migration VACUUM (FULL, ANALYZE)");
|
||||||
|
await ctx.Database.ExecuteSqlRawAsync("VACUUM (FULL, ANALYZE) \"PaymentRequests\"", cancellationToken);
|
||||||
|
Logs.LogInformation("Post-migration VACUUM (FULL, ANALYZE) finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DateTimeOffset ProcessEntities(ApplicationDbContext ctx, List<PaymentRequestData> entities)
|
||||||
|
{
|
||||||
|
// The PaymentRequestData.Migrate() is automatically called by EF.
|
||||||
|
// But Modified isn't set as it happens before the ctx is bound to the entity.
|
||||||
|
foreach (var entity in entities)
|
||||||
|
{
|
||||||
|
ctx.PaymentRequests.Entry(entity).State = EntityState.Modified;
|
||||||
|
}
|
||||||
|
return entities[^1].Created;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task Reindex(ApplicationDbContext ctx, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -578,6 +578,9 @@ o.GetRequiredService<IEnumerable<IPaymentLinkExtension>>().ToDictionary(o => o.P
|
||||||
services.AddSingleton<InvoiceBlobMigratorHostedService>();
|
services.AddSingleton<InvoiceBlobMigratorHostedService>();
|
||||||
services.AddSingleton<IHostedService, InvoiceBlobMigratorHostedService>(o => o.GetRequiredService<InvoiceBlobMigratorHostedService>());
|
services.AddSingleton<IHostedService, InvoiceBlobMigratorHostedService>(o => o.GetRequiredService<InvoiceBlobMigratorHostedService>());
|
||||||
|
|
||||||
|
services.AddSingleton<PaymentRequestsMigratorHostedService>();
|
||||||
|
services.AddSingleton<IHostedService, PaymentRequestsMigratorHostedService>(o => o.GetRequiredService<PaymentRequestsMigratorHostedService>());
|
||||||
|
|
||||||
// Broken
|
// Broken
|
||||||
// Providers.Add("argoneum", new ArgoneumRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_ARGONEUM")));
|
// Providers.Add("argoneum", new ArgoneumRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_ARGONEUM")));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue